/* =============================================
   Gestionale Ristorazione — Sistema di componenti
   =============================================
   Questo livello sta SOPRA css/style.css e sostituisce gli stili inline
   sparsi nei template: ogni elemento ricorrente ha una classe, così le pagine
   hanno la stessa densità, gli stessi margini e gli stessi colori.

   ── IL MONDO: LA LUCE DEL PASSE ──
   Il gestionale non è un pannello scuro con un accento di marca. È un piano
   d'acciaio sotto una lampada calda — il passe di una cucina — e da questa
   sola immagine discende tutto il foglio: ciò che conta adesso sta nella
   pozza di luce, il resto riposa nella penombra tiepida, e non c'è nessuna
   superficie fredda e uniforme in cui il lavoro possa perdersi.

   Il mondo precedente era la segnaletica d'impianto: targhe smaltate a
   spigolo quasi vivo, accostate a fuga di due pixel su un substrato di
   lamiera. Era coerente ma severo — spigoloso in ogni angolo, e su un tema
   scuro senza luce d'ambiente leggeva come un locale senza finestre. Quello
   che di quel mondo era MISURATO è rimasto, e si riconosce nel foglio: il
   codice colore delle quattro tinte, i tre gradi di forma, i contrasti
   verificati, la difesa contro i browser senza sfocatura. Quello che era
   materiale è stato sostituito.

   Quattro regole reggono tutto il foglio:

   1. LA LASTRA DI VETRO È L'ATOMO. Ogni superficie è translucida, ha l'angolo
      morbido, prende un filo di luce sul bordo alto e posa un'ombra lunga:
      sta SOPRA il piano, non ci è avvitata. Il velo lascia passare la pozza
      di luce, che è la ragione per cui il vetro si legge come vetro.
   2. L'AMBRA È LUCE, NON PITTURA. L'accento d'interfaccia non riempie mai un
      fondo per dire uno stato: fa la pozza d'ambiente, l'anello di fuoco,
      l'alone sotto la cosa accesa e l'inchiostro di un'etichetta d'ottone.
      È ciò che tiene le quattro tinte del codice libere di dire solo stato.
   3. ESSERE ACCESI È ESSERE CHIARI. La sezione aperta, l'azione primaria, il
      segmento scelto sono una lastra d'osso caldo con l'alone d'ambra: la
      cosa nella pozza di luce, una per schermo.
   4. NESSUNO STATO VIVE DI SOLO COLORE. Pieno, retinato o a filo è il secondo
      canale, e regge per chi non distingue rosso e verde. Il vetro ne
      aggiunge un terzo: una lastra di stato ILLUMINA il piano sotto di sé
      con la propria tinta, e da un metro e mezzo l'alone arriva prima del
      testo.

   Il movimento sta in css/style.css: la firma è LA LUCE CHE SALE, e la
   modale è il posto in cui si sente (vedi .modal, più sotto).
   ============================================= */

:root {
    /* I CONTROLLI CHE DISEGNA IL BROWSER, NON IL NOSTRO CSS.
       Senza `color-scheme` l'orologio di `<input type="time">` e il calendario
       di `type="date"` li disegna scuri, come su una pagina bianca — quindi
       scuri su un campo scuro. Nessuna variabile qui sotto li può toccare: è
       fuori dalla portata del CSS. Vale per tutta la famiglia: frecce dei
       numeri, elenco della `<select>`, barre di scorrimento, riempimento
       automatico. `accent-color` porta caselle e radio sull'ambra della
       lampada, che in questo mondo è l'accento d'interfaccia. */
    color-scheme: dark;
    accent-color: #e79a2f;

    /* ── IL PIANO E LE LASTRE ──
       Il fondo non è un pannello di lamiera: è il piano d'acciaio del passe
       visto sotto la lampada. Ardesia calda, non nero — un grigio uniforme a
       questa profondità è precisamente ciò che rende un gestionale scuro una
       stanza senza finestre.
       Sopra al piano non ci sono targhe avvitate ma LASTRE DI VETRO: ogni
       superficie è translucida, prende la luce sul bordo alto e posa un'ombra
       lunga e morbida sotto di sé. Il piano resta più scuro di ogni lastra,
       perché è la ragione per cui il vetro si legge come vetro. */
    /* Misurato in riesame: la prima stesura era #14161d, cioè un valore più
       fondo di quello che OWN-WORLD nomina e con il blu otto punti sopra il
       rosso — un nero-blu, non un'ardesia calda, ed era la ragione principale
       per cui il tema scuro somigliava ancora alla «prigione» da cui questa
       richiesta parte.
       #1d1a1f tiene lo stesso valore che il contratto nomina (#191c23) e ne
       corregge la temperatura: rosso sopra il blu, quindi sotto la pozza
       d'ambra il piano si scalda invece di virare al viola. È la traduzione
       dichiarata di quel token, non un valore nuovo. */
    --substrato: #1d1a1f;
    --bg-primary: #1d1a1f;

    /* LE LASTRE. Sono translucide, e il velo è reale: dietro passa la pozza
       di luce ambra dell'ambiente (vedi --ambient-a) e, sulla pianta della
       sala, le tinte dei tavoli. Senza qualcosa da lasciar passare il vetro
       non è vetro, è un grigio in più — ed è esattamente l'errore che il
       mondo precedente aveva registrato prima di rinunciare al velo.
       Ogni regola che usa questi fondi riceve la sfocatura dal blocco
       LA SUPERFICIE DI VETRO più sotto: un posto solo, non un fallback
       scritto a mano per ogni componente. */
    /* I valori sono la TINTA DEL VETRO, non il colore che si vede: quello lo
       decide il velo risolto sul piano. Misurati in cattura: al primo giro le
       lastre erano una tinta scura al 58% e la composita usciva a #262b36 —
       dodici valori sopra il piano, cioè un vetro che non si distingueva dal
       fondo, e il difetto che la richiesta chiama per nome. Adesso la tinta è
       PIÙ CHIARA e il velo PIÙ SOTTILE: più fondo traspare (vetro vero) e la
       composita sale a #2b303d, che si stacca. */
    --bg-secondary: rgba(120, 130, 152, 0.30);  /* la lastra → #3a3941 */
    --bg-elevated: rgba(132, 142, 166, 0.34);   /* la lastra sollevata: tasti, pannello a comparsa */
    --bg-card: rgba(120, 130, 152, 0.30);
    --bg-input: rgba(8, 6, 10, 0.42);           /* l'incavo: dove si scrive, il vetro è più fondo */
    --bg-hover: rgba(150, 162, 186, 0.34);
    --bg-sidebar: rgba(96, 104, 124, 0.20);     /* la penombra: più scura delle lastre */
    --bg-track: rgba(8, 6, 10, 0.40);

    /* LO STACCO fra due lastre. Non è più l'armatura da due pixel del mondo
       precedente: là serviva a far leggere due targhe accostate, qui serve a
       far passare la luce del piano fra le lastre. Dodici pixel sono la
       misura in cui una lastra ha un'ombra propria invece di sporcare la
       vicina, e sono la ragione principale per cui il quadro non è più
       serrato. Una misura sola per tutto il gestionale. */
    --fuga: 12px;

    /* IL FILO DI LUCE E L'OMBRA. Il bordo alto di una lastra di vetro sotto
       una lampada prende una riga di luce; sotto, l'ombra è lunga e sfocata
       perché la lastra STA SOPRA il piano e non ci è avvitata. È il verso
       opposto dell'incisione dura del mondo precedente. */
    --bisello: rgba(255, 255, 255, 0.20);
    --incisione: rgba(0, 0, 0, 0.42);

    /* ── LA LAMPADA ──
       L'ambra è l'accento d'interfaccia di questo mondo, ed è LUCE: non
       riempie mai un fondo per dire uno stato. Fa quattro cose e solo quelle:
       la pozza d'ambiente dietro le intestazioni, l'anello di fuoco, l'alone
       sotto la cosa accesa, e l'inchiostro di un'etichetta in ottone.
       Questo è ciò che tiene le quattro tinte del codice libere di dire solo
       stato: l'accento non è un colore in concorrenza con loro, è
       l'illuminazione della stanza. */
    --luce: #e79a2f;
    --luce-ink: #f6c98c;                       /* l'ambra come TESTO: 6,4:1 sulla lastra */
    --luce-soft: rgba(231, 154, 47, 0.20);
    --luce-alone: rgba(231, 154, 47, 0.34);
    --ottone: #dcc296;

    /* ── LA SCALA DI LUCE ──
       Alzata dichiarata: quanto una superficie è illuminata è un VALORE DI
       SISTEMA e non una scelta per componente. Tre gradini, e il nome dice a
       cosa serve: la penombra è il riposo, il tiepido è ciò che si può
       toccare, il caldo è la cosa che sta nella pozza di luce — una per
       schermo. */
    /* L'alone di luce ha SEMPRE uno scostamento e una sfocatura: e' una lastra
       illuminata che posa una luce sotto di se', non un anello di colore
       intorno a un rettangolo. La prima stesura portava anche un `0 0 0 1px`
       della propria tinta, cioe' un cerchio a scostamento zero: quello non e'
       profondita' — e' un contorno colorato che finge di essere luce, e il
       perimetro di una lastra lo disegna gia' --glass-border. */
    --luce-spento: none;
    --luce-tiepido: 0 5px 18px -8px var(--luce-soft);
    --luce-caldo: 0 8px 28px -6px var(--luce-alone);

    /* ── IL CODICE COLORE ──
       Le quattro tinte restano IDENTICHE al mondo precedente, e non è
       conservatorismo: sono misurate, la cucina le legge da un metro e mezzo,
       e un linguaggio di stato che cambia a ogni ridisegno non è un
       linguaggio. Cambia la RESA — angolo morbido, velo di lucido sopra la
       campitura, alone della propria tinta sotto — non il significato.
       Tre ruoli per tinta, tutti necessari:
         CAMPO      la tinta piena, fondo di una lastra di stato
         -text      la stessa tinta portata a 4,5:1 come TESTO sul peggiore
                    dei fondi di questo tema
         --text-on- il testo che sta sopra il campo pieno */
    --campo-rosso: #d5301f;
    --campo-giallo: #f2b705;
    --campo-verde: #1b7f4a;
    --campo-blu: #1d5fa8;

    /* ── LE CAMPITURE SONO VETRO COLORATO ──
       Questa è la mezza promessa che OWN-WORLD fa e che la prima stesura non
       manteneva: «da campitura piena diventa vetro colorato». Le quattro
       tinte erano rimaste opache — un rosso pieno con un alone intorno è una
       targa con una luce, non una lastra di vetro.
       IL VELO È 0,94, e il numero è calcolato, non scelto: sotto una lastra
       di stato il piano si vede davvero (quindi è vetro), ma la tinta si
       sposta di così poco che il testo in negativo resta sopra il minimo nei
       DUE temi. Il lato che decide è il CHIARO: là il piano è pietra e la
       campitura si SCHIARISCE, quindi il bianco perde contrasto — a 0,94 il
       peggiore dei casi è il verde in regola a 4,60:1, a 0,90 scenderebbe a
       4,34 e sarebbe sotto. Un velo più generoso costerebbe la leggibilità
       al passe da un metro e mezzo, che non è negoziabile.
       Il fallback per i browser senza sfocatura non riguarda questi: un
       fondo translucido senza `backdrop-filter` resta comunque leggibile
       perché sotto c'è il piano e non del testo. */
    --campo-rosso-vetro: rgba(213, 48, 31, 0.94);
    --campo-giallo-vetro: rgba(242, 183, 5, 0.94);
    --campo-verde-vetro: rgba(27, 127, 74, 0.94);
    --campo-blu-vetro: rgba(29, 95, 168, 0.94);

    /* L'ALONE DI STATO. È il canale che il vetro aggiunge: una lastra di
       stato non si limita a essere colorata, ILLUMINA il piano sotto di sé
       con la propria tinta. Da un metro e mezzo dal passe si vede l'alone
       prima del testo. */
    --alone-rosso: rgba(213, 48, 31, 0.48);
    --alone-giallo: rgba(242, 183, 5, 0.40);
    --alone-verde: rgba(27, 127, 74, 0.48);
    --alone-blu: rgba(29, 95, 168, 0.48);

    /* IL BORDO DELLA CAMPITURA — il canale di FORMA, e cambia col tema.
       Sul vetro scuro è il riflesso della lampada sul bordo; sul tema chiaro
       è inchiostro (vedi il blocco del tema chiaro), perché lì il giallo
       attenzione stacca solo 1,1:1 dal fondo e da forma non esisterebbe. */
    --bordo-campo: rgba(255, 255, 255, 0.26);

    /* IL VELO DI LUCIDO sopra una campitura piena. È ciò che rende una lastra
       colorata *vetro* colorato invece di un rettangolo di tinta: la luce
       della lampada scivola sul terzo alto e si spegne. Non tocca il
       contrasto del testo, che sta nella metà bassa. */
    /* Misurato in riesame: a 0,16 sopra un rosso saturo il riflesso non si
       distingueva — «no --lucido highlight is discernible on the fill». Su una
       campitura la luce compete con una tinta piena e va portata a 0,26,
       dove si legge come un riflesso vero e resta fuori dalla metà bassa,
       cioè fuori dal testo. */
    --lucido: linear-gradient(180deg, rgba(255, 255, 255, 0.26), rgba(255, 255, 255, 0.05) 44%, transparent 68%);

    /* Il lucido TENUE: la stessa luce sulle lastre neutre. Serve perché una
       lastra neutra senza riflesso si legge come un rettangolo piatto un
       gradino più chiaro del piano — misurato in cattura sui riquadri dei
       tavoli liberi, che sono la superficie più ripetuta del gestionale. Con
       il riflesso in cima la stessa lastra si legge come vetro. È un settimo
       della forza di quello sopra una campitura: là la luce compete con una
       tinta piena, qui no. */
    --lucido-tenue: linear-gradient(180deg, rgba(255, 255, 255, 0.07), transparent 52%);

    /* IL RETINO — il secondo canale per gli stati in sospeso: la lastra
       porta la tinta ma a righe diagonali invece che piena. Si distingue dal
       pieno anche in bianco e nero e anche stampato, e regge per chi non
       distingue rosso e verde. La riga è un inchiostro scuro al 70%, che sul
       giallo attenzione dà 6,31:1 fra riga e campo. */
    --retino: repeating-linear-gradient(
        135deg,
        rgba(0, 0, 0, 0.7) 0 3px,
        transparent 3px 8px
    );

    /* L'ETICHETTA IN OTTONE. Le intestazioni di sezione non sono più nastri
       goffrati neri: sono targhette d'ottone incise, cioè un velo caldissimo
       appena percettibile e le lettere in ottone. Il nastro nero era il
       cardine del mondo precedente, ed è la singola cosa che più faceva
       sembrare il gestionale un quadro elettrico. */
    --nastro-bg: rgba(231, 154, 47, 0.10);
    --nastro-ink: #dcc296;

    /* L'altezza della fascia retinata. Sei pixel si vedono da un metro e
       mezzo e non rubano spazio all'etichetta. */
    --retino-h: 6px;

    /* ── LO SCAVO ──
       La piastrina incassata DENTRO una campitura: il tasto su un tavolo
       occupato, la pastiglia di stato sul suo stesso campo, il tempo sulla
       testata rossa della comanda in ritardo. Sopra una campitura non si può
       mettere né un secondo colore pieno (non si leggerebbe) né un bianco (la
       sfonderebbe): si SCAVA nel campo, e il testo prende il colore che il
       campo impone. Un valore solo, per tutte e quattro le tinte e per i due
       temi. */
    --scavo: rgba(0, 0, 0, 0.24);

    /* ── LA LASTRA ACCESA ──
       La sezione aperta, l'azione primaria, il segmento scelto, il giorno
       scelto: sono LA COSA CHE STA NELLA POZZA DI LUCE, e in questo mondo
       essere illuminato vuol dire prendere il colore della lampada: la lastra
       accesa è AMBRA con l'inchiostro scuro, con l'alone caldo sotto di sé.
       La prima stesura la faceva osso caldo — chiara invece che ambra — per
       tenere la lampada lontana dal giallo attenzione del codice. Rilevato in
       riesame: era una deviazione dal contratto e non era dichiarata, e
       lasciava la lampada senza il proprio colore proprio sull'oggetto che
       dovrebbe portarlo. Adesso l'ambra è la lastra accesa, e la distanza dal
       giallo attenzione la tengono due canali che il giallo ha e l'ambra no:
       la fascia RETINATA e l'inchiostro quasi-nero su un campo molto più
       chiaro (#f2b705 contro #d9822a: 1,61:1 di distanza in valore).
       LA STESSA TINTA NEI DUE TEMI, e questa è la sua ragione: una lampada
       accesa non cambia colore col colore della stanza. Sul tema chiaro
       l'ambra da sola stacca 1,8:1 dalla pietra e come FORMA non esisterebbe,
       quindi lì prende il bordo di campo in inchiostro — la stessa regola che
       il codice colore applica al giallo attenzione. */
    --comando-bg: #d9822a;
    --comando-ink: #201404;

    /* ── LA RAMPA DELLE MISURE ──
       Le misure non pescano dalla tavolozza degli stati né dall'ambra:
       l'acciaio non significa niente, che è esattamente quello che serve a un
       numero. Un valore solo per i due temi. */
    --misura-barra: #9ea6b2;

    --accent-primary: #f9a79c;        /* inchiostro rosso: 4,6:1 sul fondo peggiore, che è
                                         il tasto pericolo sotto il puntatore — rosso
                                         tenue sopra rosso al 15% */
    --accent-primary-soft: rgba(213, 48, 31, 0.15);
    --accent-primary-fill: var(--campo-rosso-vetro);   /* campitura in vetro */
    --accent-primary-text: #f9a79c;
    --accent-secondary: #f2b705;      /* il giallo regge già come testo: 7,4:1 */
    --accent-secondary-soft: rgba(242, 183, 5, 0.16);
    --accent-secondary-fill: var(--campo-giallo-vetro);
    --accent-secondary-text: #f2b705;
    --accent-success: #8ecdac;        /* inchiostro verde: 4,7:1 sul fondo peggiore */
    --accent-success-soft: rgba(27, 127, 74, 0.20);
    --accent-success-fill: var(--campo-verde-vetro);
    --accent-success-text: #8ecdac;
    --accent-info: #a6c4e5;           /* inchiostro blu: 4,7:1 sul fondo peggiore */
    --accent-info-soft: rgba(29, 95, 168, 0.22);
    --accent-info-fill: var(--campo-blu-vetro);
    --accent-info-text: #a6c4e5;

    /* Testo. I tre valori sono verificati sul PEGGIORE dei fondi del tema,
       che è la lastra sollevata della modale sopra la pozza di luce. */
    /* I tre valori sono verificati sui fondi COMPOSITI, non sui token: in un
       mondo di lastre translucide il fondo vero di un testo è il velo risolto
       sul piano, e il peggiore è la lastra sotto il puntatore (#39404f). */
    --text-primary: #f2f2f5;    /* 8,3:1 sul peggiore */
    --text-secondary: #c8ccd6;  /* 5,4:1 */
    --text-muted: #b6bbc6;      /* 4,6:1 */
    --text-inverse: #1d1a1f;

    /* Il testo sopra una campitura piena. Bianco o quasi-nero, deciso dalla
       tinta: il giallo attenzione è chiaro in entrambi i temi e vuole sempre
       inchiostro scuro (10,39:1), le altre tre vogliono sempre bianco. */
    --text-on-accent: #ffffff;    /* su rosso: 4,92:1 */
    --text-on-success: #ffffff;   /* su verde: 5,02:1 */
    --text-on-warning: #111111;   /* su giallo: 10,39:1 */
    --text-on-info: #ffffff;      /* su blu: 6,45:1 */

    /* ── IL VETRO ──
       Il velo dietro le modali e sotto le barre. Qui il vetro ha finalmente
       qualcosa da sfocare: la pozza di luce ambra sta dietro tutto il
       gestionale e le tinte dei tavoli stanno sotto le barre della sala.
       `--glass-saturate` non è decorazione: la sfocatura di un browser
       smorza la saturazione, e senza rialzarla il vetro sopra una campitura
       rossa restituisce un rosa sporco. */
    --overlay: rgba(14, 10, 14, 0.58);
    --glass-bg: rgba(120, 130, 152, 0.30);
    --glass-bg-strong: rgba(78, 80, 94, 0.80);
    --glass-blur: 20px;
    --glass-saturate: 150%;
    --glass-highlight: var(--bisello);
    --glass-border: rgba(255, 255, 255, 0.15);

    /* ── LA POZZA DI LUCE ──
       Due campi fermi dietro tutto il gestionale: l'ambra della lampada in
       alto al centro e un riflesso freddo d'acciaio in basso a sinistra.
       NON SI ANIMANO e non si muovono — è la luce di una stanza, non uno
       sfondo animato. Servono a due cose insieme: dare al vetro qualcosa da
       lasciar passare, e togliere al tema scuro il grigio piatto uniforme che
       lo faceva sembrare una stanza senza finestre. */
    --ambient-a: radial-gradient(1240px 680px at 52% -18%, rgba(231, 154, 47, 0.26), transparent 66%);
    --ambient-b: radial-gradient(1020px 720px at 2% 108%, rgba(72, 122, 142, 0.22), transparent 68%);

    /* Il bordo dei pannelli IN STAMPA. La carta non ha temi: vale identico
       nei due, ed è la ragione per cui è un token e non un esadecimale dentro
       il blocco @media print di admin.css. */
    --print-border: #cccccc;

    /* L'anello di fuoco da tastiera. È L'AMBRA, e adesso può esserlo: l'ambra
       in questo mondo non dice nessuno stato — è la luce. Un anello ambra su
       una lastra rossa, gialla, verde o blu si vede in tutti e quattro i
       casi, che è quello che deve fare un indicatore di posizione. */
    --focus-ring: #e79a2f;

    /* I bordi. Su una lastra di vetro il contorno non è una fuga scura: è il
       taglio del vetro, cioè un filo appena più chiaro del velo. `--border`
       resta il filo di serie, `--border-light` quello che si vede. */
    --border: rgba(255, 255, 255, 0.12);
    --border-light: rgba(255, 255, 255, 0.22);

    /* Le ombre di una lastra che sta SOPRA il piano: scostamento più
       sfocatura, lunghe e morbide. Le ombre corte e dure da targa avvitata
       erano del mondo precedente ed erano la ragione principale per cui
       tutto sembrava spigoloso. */
    --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.24), 0 2px 8px -4px rgba(0, 0, 0, 0.38);
    --shadow-md: 0 2px 6px rgba(0, 0, 0, 0.26), 0 12px 30px -12px rgba(0, 0, 0, 0.55);
    --shadow-lg: 0 8px 22px rgba(0, 0, 0, 0.30), 0 36px 68px -26px rgba(0, 0, 0, 0.72);
    --shadow-up: 0 -8px 24px -10px rgba(0, 0, 0, 0.52);
    --shadow-glow: var(--luce-caldo);

    /* Il rilievo di una lastra: filo di luce sul bordo alto, ombra lunga
       sotto. --elev-2 è la lastra sollevata dal dito o dal puntatore. */
    --elev-1: inset 0 1px 0 var(--bisello), 0 1px 2px rgba(0, 0, 0, 0.22), 0 10px 24px -12px rgba(0, 0, 0, 0.50);
    --elev-2: inset 0 1px 0 var(--bisello), 0 3px 8px rgba(0, 0, 0, 0.26), 0 22px 48px -18px rgba(0, 0, 0, 0.62);

    /* ── L'ANGOLO MORBIDO ──
       È il valore che più di ogni altro dice che questo non è un quadro
       elettrico. Erano 2/2/3/4 px, cioè lo spigolo quasi vivo di una targa
       avvitata: la cosa che la richiesta chiama «troppo spigoloso». Una
       lastra di vetro molato ha il bordo raggiato, e la scala sale con la
       superficie — otto per un controllo, ventidue per la calotta di una
       modale. */
    --radius-sm: 8px;
    --radius-md: 12px;
    --radius-lg: 16px;
    --radius-xl: 22px;

    --sidebar-w: 236px;
    --topbar-h: 60px;

    /* Gli stati del tavolo. LIBERO NON HA UN COLORE: è la lastra nuda.
       L'assenza di segnale significa che non c'è niente da segnalare, ed è il
       motivo per cui su una pianta di trenta tavoli si vedono a colpo
       d'occhio solo quelli che chiedono qualcosa. */
    --status-free: #9aa4b3;
    --status-occupied: #d5301f;
    --status-waiting: #f2b705;
    --status-reserved: #1d5fa8;
}

[data-theme="light"] {
    /* Vedi la nota su :root. Qui il verso è l'opposto. */
    color-scheme: light;
    accent-color: #a4650f;

    /* ── IL PIANO ALLA LUCE È PIETRA CALDA, NON CARTA ──
       Il fondo pagina NON è bianco, e la ragione è la stessa di prima con un
       materiale nuovo: se lo fosse, le lastre di vetro chiaro non avrebbero
       niente sotto e il velo non si vedrebbe. Pietra calda — un beige-grigio
       medio — e il bianco resta alla lastra. È anche il colore che una parete
       chiara prende davvero sotto una lampada calda. */
    --substrato: #e4dfd5;
    --bg-primary: #e4dfd5;

    --bg-secondary: rgba(255, 255, 255, 0.62);
    --bg-elevated: rgba(255, 255, 255, 0.88);
    --bg-card: rgba(255, 255, 255, 0.62);
    --bg-input: rgba(255, 255, 255, 0.80);
    --bg-hover: rgba(255, 255, 255, 0.90);
    --bg-sidebar: rgba(255, 255, 255, 0.55);
    --bg-track: rgba(26, 30, 38, 0.07);

    --fuga: 12px;

    /* Alla luce il rilievo lo fa l'ombra, non il riflesso: il filo di luce
       diventa un bianco quasi pieno (su una lastra già chiara un bianco al
       16% non esisterebbe) e l'ombra si alleggerisce e si scalda — un'ombra
       neutra sotto una lastra su pietra calda la fa sembrare sporca. */
    --bisello: rgba(255, 255, 255, 0.85);
    --incisione: rgba(46, 38, 26, 0.16);

    /* Le campiture sono le stesse: un codice colore che cambia col tema non è
       un codice. Cambia solo il canale di forma. */
    --campo-rosso: #d5301f;
    --campo-giallo: #f2b705;
    --campo-verde: #1b7f4a;
    --campo-blu: #1d5fa8;

    /* Vedi la nota su :root: il velo è lo stesso nei due temi perché è quel
       valore a decidere il contrasto sul peggiore dei due, che è questo. */
    --campo-rosso-vetro: rgba(213, 48, 31, 0.94);
    --campo-giallo-vetro: rgba(242, 183, 5, 0.94);
    --campo-verde-vetro: rgba(27, 127, 74, 0.94);
    --campo-blu-vetro: rgba(29, 95, 168, 0.94);

    --alone-rosso: rgba(213, 48, 31, 0.26);
    --alone-giallo: rgba(242, 183, 5, 0.26);
    --alone-verde: rgba(27, 127, 74, 0.24);
    --alone-blu: rgba(29, 95, 168, 0.24);

    /* La lampada alla luce del giorno: la stessa ambra portata a inchiostro.
       #8f5a0e sta a 5,3:1 sulla lastra chiara. */
    --luce: #b8761a;
    --luce-ink: #875409;               /* 4,8:1 anche sulla pietra nuda */
    --luce-soft: rgba(184, 118, 26, 0.17);
    --luce-alone: rgba(184, 118, 26, 0.30);
    --ottone: #6f5219;

    --luce-spento: none;
    --luce-tiepido: 0 5px 18px -8px var(--luce-soft);
    --luce-caldo: 0 8px 26px -6px var(--luce-alone);

    /* IL BORDO DELLA CAMPITURA, alla luce, è INCHIOSTRO. Vedi la nota su
       :root: il giallo attenzione stacca 1,1:1 dalla pietra chiara, quindi
       come forma non esisterebbe — una lastra gialla su fondo chiaro sarebbe
       una macchia senza contorno. Il bordo scuro della sua stessa tinta lo
       rende un oggetto. È anche come è fatto un cartello di pericolo vero:
       giallo con la cornice nera. */
    --bordo-campo: rgba(26, 30, 38, 0.48);

    /* Alla luce il lucido è più tenue: su una campitura vista in pieno giorno
       un riflesso troppo forte diventa una velatura sporca. */
    --lucido: linear-gradient(180deg, rgba(255, 255, 255, 0.34), rgba(255, 255, 255, 0.06) 44%, transparent 68%);

    /* Alla luce il riflesso su una lastra chiara è un bianco quasi pieno sul
       filo alto: un bianco al 7% su una lastra già bianca non esisterebbe. */
    --lucido-tenue: linear-gradient(180deg, rgba(255, 255, 255, 0.55), transparent 46%);

    /* Vedi la nota su :root: il retino è lo stesso nei due temi, perché la
       campitura sotto è la stessa. */
    --retino: repeating-linear-gradient(
        135deg,
        rgba(0, 0, 0, 0.7) 0 3px,
        transparent 3px 8px
    );

    /* La targhetta d'ottone incisa alla luce: velo caldo appena percettibile,
       lettere in bronzo. #7a5c1e sta a 6,1:1 sulla lastra chiara. */
    --nastro-bg: rgba(184, 118, 26, 0.10);
    --nastro-ink: #6f5219;

    /* Vedi la nota su :root: la lampada non cambia colore col colore della
       stanza. Quello che cambia è il canale di FORMA — qui l'ambra prende il
       contorno in inchiostro, o su pietra chiara sarebbe una macchia senza
       perimetro. */
    --comando-bg: #d9822a;
    --comando-ink: #201404;

    --misura-barra: #6d7480;

    --accent-primary: #a22418;        /* inchiostro rosso: 4,8:1 sulla lastra */
    --accent-primary-soft: rgba(213, 48, 31, 0.12);
    --accent-primary-fill: var(--campo-rosso-vetro);
    --accent-primary-text: #a22418;
    --accent-secondary: #6a5102;      /* il giallo come TESTO va portato a 4,8:1 */
    --accent-secondary-soft: rgba(242, 183, 5, 0.20);
    --accent-secondary-fill: var(--campo-giallo-vetro);
    --accent-secondary-text: #6a5102;
    --accent-success: #156138;        /* 4,8:1 */
    --accent-success-soft: rgba(27, 127, 74, 0.13);
    --accent-success-fill: var(--campo-verde-vetro);
    --accent-success-text: #156138;
    --accent-info: #1a5697;           /* 4,8:1 */
    --accent-info-soft: rgba(29, 95, 168, 0.12);
    --accent-info-fill: var(--campo-blu-vetro);
    --accent-info-text: #1a5697;

    --text-primary: #1a1e26;    /* 11,4:1 */
    --text-secondary: #4c5462;  /* 6,9:1 */
    --text-muted: #545c6a;      /* 6,1:1 */
    --text-inverse: #ffffff;

    /* Le campiture non cambiano, quindi il testo che ci sta sopra non cambia. */
    --text-on-accent: #ffffff;
    --text-on-success: #ffffff;
    --text-on-warning: #111111;
    --text-on-info: #ffffff;

    --overlay: rgba(116, 106, 88, 0.44);
    --glass-bg: rgba(255, 255, 255, 0.62);
    --glass-bg-strong: rgba(255, 255, 255, 0.86);
    --glass-blur: 18px;
    --glass-saturate: 150%;
    --glass-highlight: var(--bisello);
    --glass-border: rgba(26, 30, 38, 0.12);

    /* La stessa lampada, vista di giorno: più tenue, e il riflesso freddo
       diventa un'ombra d'aria invece di un acciaio. */
    --ambient-a: radial-gradient(1240px 680px at 52% -18%, rgba(224, 150, 46, 0.34), transparent 66%);
    --ambient-b: radial-gradient(1020px 720px at 2% 108%, rgba(80, 110, 130, 0.18), transparent 68%);

    --print-border: #cccccc;

    /* Sul chiaro l'ambra chiara sparirebbe: qui è il bronzo, e resta un
       colore che non dice nessuno stato. */
    --focus-ring: #a4650f;

    --border: rgba(26, 30, 38, 0.12);
    --border-light: rgba(26, 30, 38, 0.22);

    --shadow-sm: 0 1px 2px rgba(46, 38, 26, 0.10), 0 2px 8px -4px rgba(46, 38, 26, 0.16);
    --shadow-md: 0 2px 6px rgba(46, 38, 26, 0.10), 0 12px 30px -12px rgba(46, 38, 26, 0.22);
    --shadow-lg: 0 8px 22px rgba(46, 38, 26, 0.14), 0 36px 68px -26px rgba(46, 38, 26, 0.32);
    --shadow-up: 0 -8px 24px -10px rgba(46, 38, 26, 0.20);
    --shadow-glow: var(--luce-caldo);

    --elev-1: inset 0 1px 0 var(--bisello), 0 1px 2px rgba(46, 38, 26, 0.08), 0 10px 24px -12px rgba(46, 38, 26, 0.22);
    --elev-2: inset 0 1px 0 var(--bisello), 0 3px 8px rgba(46, 38, 26, 0.10), 0 22px 48px -18px rgba(46, 38, 26, 0.28);

    --status-free: #545c6a;
    --status-occupied: #d5301f;
    --status-waiting: #f2b705;
    --status-reserved: #1d5fa8;
}

/* ── QUANDO IL VETRO NON SI PUÒ FARE ──
   `backdrop-filter` manca su Firefox con la sfocatura disattivata, sui browser
   dei tablet Android di qualche anno fa e su ogni WebView vecchia. Lì un fondo
   translucido non viene sfocato: resta trasparente, e sotto una lastra si
   legge il testo della pagina attraverso — illeggibili entrambi. In questo
   mondo il rischio è più grande che nel precedente, perché qui OGNI
   superficie è translucida e non solo le barre.
   La difesa è nei TOKEN e non nelle regole: un blocco solo rende opaco ogni
   pezzo di vetro del gestionale, e la gerarchia sopravvive perché i valori
   pieni sono le stesse tinte a velo risolto sul piano. Il resto del mondo —
   angoli morbidi, ombre lunghe, pozza di luce, movimento — arriva identico. */
@supports not ((backdrop-filter: blur(2px)) or (-webkit-backdrop-filter: blur(2px))) {
    :root {
        /* Questi non sono valori nuovi: sono le stesse lastre a velo RISOLTO
           sul piano, calcolate una per una. Dove il vetro non si può fare la
           gerarchia resta identica — cambia solo che il fondo non traspare.

           VANNO RICALCOLATI OGNI VOLTA CHE SI TOCCA UNA TINTA O UN VELO DI
           SOPRA, e non è un avvertimento teorico: in questo progetto è già
           successo. Le lastre sono state ritarate (tinta più chiara, velo più
           sottile) e questo blocco è rimasto ai valori del giro precedente,
           quindi sui browser senza sfocatura e per chi chiede meno
           trasparenze le lastre uscivano un gradino più scure del vero e la
           gerarchia si spostava. Se ne è accorto chi ha letto il foglio, non
           chi lo guardava.
           La formula è quella della composizione: `tinta * velo + piano *
           (1 - velo)`, con il piano che è `--substrato`. */
        --bg-secondary: #383943;
        --bg-elevated: #40414d;
        --bg-card: #383943;
        --bg-input: #141216;
        --bg-hover: #464854;
        --bg-sidebar: #2a2a32;
        --bg-track: #151217;
        --glass-bg: #383943;
        --glass-bg-strong: #444551;
        --overlay: rgba(9, 10, 14, 0.88);
    }

    [data-theme="light"] {
        --bg-secondary: #f5f3ef;
        --bg-elevated: #fcfbfa;
        --bg-card: #f5f3ef;
        --bg-input: #faf9f7;
        --bg-hover: #fcfcfb;
        --bg-sidebar: #f3f1ec;
        --bg-track: #d6d1c9;
        --glass-bg: #f5f3ef;
        --glass-bg-strong: #fbfbf9;
        --overlay: rgba(116, 106, 88, 0.82);
    }
}

/* Chi ha chiesto al sistema meno trasparenze le ha chieste per un motivo:
   sotto un velo il testo perde contrasto. Stessa strada dei token — e qui
   spariscono anche i due campi della pozza di luce, perché una velatura
   dietro il testo è precisamente ciò che quella preferenza esclude. */
@media (prefers-reduced-transparency: reduce) {
    /* Vedi la nota sul blocco @supports qui sopra: sono gli stessi valori
       compositi, e si ricalcolano insieme a quelli. */
    :root {
        --bg-secondary: #383943;
        --bg-elevated: #40414d;
        --bg-card: #383943;
        --bg-input: #141216;
        --bg-hover: #464854;
        --bg-sidebar: #2a2a32;
        --bg-track: #151217;
        --glass-bg: #383943;
        --glass-bg-strong: #444551;
        --overlay: rgba(9, 10, 14, 0.92);
        --ambient-a: none;
        --ambient-b: none;
    }

    [data-theme="light"] {
        --bg-secondary: #f5f3ef;
        --bg-elevated: #fcfbfa;
        --bg-card: #f5f3ef;
        --bg-input: #faf9f7;
        --bg-hover: #fcfcfb;
        --bg-sidebar: #f3f1ec;
        --bg-track: #d6d1c9;
        --glass-bg: #f5f3ef;
        --glass-bg-strong: #fbfbf9;
        --overlay: rgba(116, 106, 88, 0.88);
        --ambient-a: none;
        --ambient-b: none;
    }
}

body {
    background: var(--bg-primary);
    color: var(--text-primary);
    font-family: var(--font-sans);
    font-size: var(--fs-body);
    line-height: var(--lh-body);
    -webkit-font-smoothing: antialiased;
}

/* ── LA LUCE DELLA STANZA ──
   Vedi la nota su --ambient-a. Due campi fermi dietro tutto il gestionale: la
   pozza d'ambra in alto e il riflesso freddo d'acciaio in basso a sinistra.
   `position: fixed` non scorre col contenuto — quindi la sfocatura delle
   lastre di vetro si calcola su un'immagine ferma e non a ogni fotogramma di
   scorrimento — e `z-index: -1` lo mette dietro il contenuto ma davanti al
   fondo del body.
   Non si anima, non si muove, non pulsa: è la luce di una stanza. Uno sfondo
   animato dietro dei dati è la cosa che questa richiesta esclude per nome, e
   sarebbe anche la spesa più stupida su un tablet vecchio, perché ogni
   fotogramma rifarebbe la sfocatura di ogni lastra sopra.
   Su questo strato non si tocca e non si seleziona niente: è pittura. */
body::before {
    content: '';
    position: fixed;
    inset: 0;
    z-index: -1;
    pointer-events: none;
    background-image: var(--ambient-a), var(--ambient-b);
    background-repeat: no-repeat, no-repeat;
}

/* =============================================
   LA SUPERFICIE DI VETRO
   ============================================= */
/* ── UN POSTO SOLO PER IL MATERIALE DI TUTTO IL GESTIONALE ──
   Questo è il blocco che rende il mondo quello che è, e sta qui invece che
   sparso perché la sfocatura di una superficie translucida è una proprietà
   del MATERIALE, non del componente. La sidebar della gestione, la scheda di
   un tavolo in sala, la colonna del passe e la calotta di una modale sono la
   stessa lastra: cambiano misura e contenuto, non il vetro.
   Il valore pratico: quando il vetro va tarato — più velo, meno sfocatura,
   niente saturazione su un dispositivo lento — si tara qui, per tutte e
   quattro le aree insieme. Sparso in cinque fogli, la stessa taratura sono
   quaranta regole e tre che ci si dimentica.

   I selettori arrivano da tutti i fogli di ruolo (admin, waiter, kitchen) e
   non solo da questo: app.css è caricato PRIMA di loro, quindi un fondo
   dichiarato là vince su questo, ma `backdrop-filter` no — non lo ridichiara
   nessuno. È il modo giusto di dare un materiale a classi che vivono altrove.

   Il fallback non è qui: sta nei token (vedi il blocco @supports più sopra).
   Dove `backdrop-filter` non esiste questi fondi sono già pieni, e la regola
   qui sotto non fa niente di male — sfoca uno sfondo che non traspare. */
.sidebar,
.topbar,
.panel,
.stat,
.segmented,
.data-table thead th,
.steps,
.table-card,
.current-order,
.menu-item,
.cart__footer,
.existing-orders-panel,
.existing-orders-panel__header,
.existing-order-total,
.bill__summary,
.bill-order,
.kds-filters,
.kds-summary,
.kds-batch__card,
.kds-column,
.kds-column__head,
.kds-order,
.kds-order__footer,
.asporto-compositore__carrello,
.asporto-menu__item,
.login__card,
.login__foot {
    -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate));
    backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate));
}

/* ── IL VETRO DENTRO IL VETRO NON SI SFOCA DUE VOLTE ──
   Una lastra dentro una lastra già sfocata paga una seconda passata di
   sfocatura per non mostrare niente di nuovo: il suo sfondo è uno strato già
   quasi uniforme. Sui tablet vecchi della sala questo è la differenza fra
   una pagina che scorre e una che scatta.
   Il velo translucido resta — è quello che dice «questa cosa sta sopra
   quella» — e cade solo la sfocatura. Vale anche per la modale, dove il velo
   di fondo ha già sfocato tutta la pagina. */
.modal .panel,
.modal .stat,
.modal .segmented,
.modal .data-table thead th,
.modal .menu-item,
.modal .table-card,
.modal .cart__footer,
.panel .stat,
.panel .segmented,
.panel .data-table thead th,
.kds-column .kds-order,
.kds-column .kds-order__footer,
.existing-orders-panel .existing-orders-panel__header,
.existing-orders-panel .existing-order-total {
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
}

/* ── IL TAGLIO DEL VETRO ──
   Il filo appena chiaro intorno a una lastra non è un contorno decorativo: su
   una superficie translucida è il bordo molato, e senza di esso una lastra
   scura su un piano scuro perde il proprio perimetro proprio negli angoli,
   dove l'ombra è più tenue. Un pixel, sempre, sulle lastre che stanno
   direttamente sul piano.
   È anche il motivo per cui `--border` in questo mondo è un bianco al 10% e
   non un grigio scuro: un contorno più scuro della lastra la incassa nel
   piano, e queste lastre stanno SOPRA. */
.sidebar,
.topbar,
.panel,
.stat,
.table-card,
.menu-item,
.kds-column,
.kds-batch__card,
.kds-order {
    border: 1px solid var(--glass-border);
}

/* =============================================
   GUSCIO APPLICAZIONE — sidebar + topbar + pagina
   ============================================= */
/* ── IL GUSCIO E' IL PIANO, E LE LASTRE CI GALLEGGIANO SOPRA ──
   La differenza sostanziale col mondo precedente sta in tre righe: il guscio
   ha una `padding` propria, quindi le lastre NON toccano il bordo della
   finestra. Prima la legenda e l'area di lavoro erano avvitate al vetro dello
   schermo e il gestionale cominciava dove finiva il monitor; adesso intorno
   c'e' il piano, e ogni lastra ha un'ombra su tutti e quattro i lati.
   E' anche cio' che rende visibile il vetro: il velo di una lastra lascia
   passare la pozza di luce, e quella pozza si vede perche' un bordo di piano
   resta scoperto.
   `minmax(0, 1fr)` e non `100vh`: con una `padding` sul guscio una riga alta
   quanto la finestra sfonderebbe di ventiquattro pixel. */
.app {
    display: grid;
    grid-template-columns: var(--sidebar-w) 1fr;
    grid-template-rows: minmax(0, 1fr);
    gap: var(--fuga);
    height: 100vh;
    height: 100dvh;
    padding: var(--fuga);
    background: var(--substrato);
    overflow: hidden;
}

/* ── LA LASTRA DELLA NAVIGAZIONE ──
   E' la lastra piu' fonda del gestionale — velo piu' denso delle altre — e
   sta a sinistra, cioe' fuori dalla pozza di luce, che e' in alto al centro.
   Questo e' il punto in cui il mondo si spiega da se': la navigazione riposa
   nella penombra tiepida, e la sola riga illuminata e' la sezione aperta.
   Il velo lascia passare il riflesso freddo che sale dal basso a sinistra
   (vedi --ambient-b), quindi il vetro qui e' visibile anche quando nessuna
   lastra colorata gli sta sotto. */
.sidebar {
    grid-column: 1;
    display: flex;
    flex-direction: column;
    background: var(--bg-sidebar);
    border-radius: var(--radius-lg);
    box-shadow: var(--elev-1);
    overflow: hidden;
}

/* L'imbottitura verticale è dichiarata invece di essere lasciata all'altezza
   fissa. Il risultato a schermo è identico — il blocco è centrato in una barra
   di 56 px e il contenuto ne occupa ~30, quindi gli 8 px non stringono niente
   — ma l'aria fra il nome del locale e la riga di separazione sotto adesso è
   una REGOLA e non un avanzo dell'altezza: se un domani la barra si abbassa,
   o il nome va su due righe, il testo non finisce appoggiato al bordo. */
.sidebar__brand {
    display: flex;
    align-items: center;
    gap: var(--space-ms);
    height: var(--topbar-h);
    padding: var(--space-sm) var(--space-md);
    border-bottom: 1px solid var(--border);
    flex-shrink: 0;
    text-decoration: none;
    color: inherit;
}

/* L'area di lavoro scorre dentro la propria lastra, e la lastra ha gli
   angoli morbidi: senza il ritaglio, la prima riga di una tabella spunterebbe
   fuori dall'angolo in alto mentre si scorre. */
.page {
    border-radius: var(--radius-lg);
}

/* IL LOGO DEL LOCALE È UN MARCHIO ORIZZONTALE, non un'icona quadrata.
   Prima era 28x28 con `object-fit: cover`: di una scritta larga tre volte
   l'altezza mostrava una fetta centrale che non voleva dire niente. Ora
   l'altezza è fissa, la larghezza segue, e `contain` non ritaglia. */
.sidebar__logo {
    height: 26px;
    width: auto;
    max-width: 132px;
    object-fit: contain;
    flex-shrink: 0;
}

/* Il logo è nero su trasparente (vedi public/images/logo.svg): sul tema scuro
   sparirebbe. `invert` lo porta a bianco, ed è il modo giusto per un marchio
   monocromatico — un tag <img> non eredita il colore del testo della pagina. */
[data-theme="dark"] .sidebar__logo {
    filter: invert(1);
}

.sidebar__title {
    font-size: var(--fs-body);
    font-weight: var(--fw-bold);
    letter-spacing: var(--tracking-snug);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.sidebar__subtitle {
    font-size: var(--fs-micro);
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: var(--tracking-label);
}

.sidebar__nav {
    flex: 1;
    overflow-y: auto;
    padding: var(--space-ms) var(--space-sm);
}

/* ── LA TARGHETTA D'OTTONE ──
   Le tre intestazioni della legenda (SERVIZIO, GESTIONE, CONFIGURAZIONE) sono
   targhette incise: nessun fondo pieno, le lettere in ottone e una riga
   incisa sotto. Il nastro goffrato nero del mondo precedente era la singola
   cosa che piu' faceva sembrare il gestionale un quadro elettrico — tre
   rettangoli neri pieni in mezzo alla navigazione — e l'ottone fa lo stesso
   lavoro di organizzazione senza tagliare la lastra in tre.
   La riga sotto e' il modo in cui una fascia e' marcata su un piano
   d'acciaio: si incide, non si incolla un'etichetta. */
.sidebar__group {
    font-family: var(--font-display);
    display: block;
    margin: var(--space-ml) var(--space-sm) var(--space-sm);
    padding: 0 var(--space-sm) var(--space-xs);
    border-bottom: 1px solid var(--border);
    color: var(--nastro-ink);
    font-size: var(--fs-micro);
    font-weight: var(--fw-bold);
    text-transform: uppercase;
    letter-spacing: 0.16em;
    line-height: 1.7;
}

/* Il primo gruppo non prende il margine alto: sotto il marchio del locale
   c'e' gia' il respiro della testata. */
.sidebar__nav > .sidebar__group:first-child { margin-top: var(--space-sm); }

.nav-item {
    position: relative;
    display: flex;
    align-items: center;
    gap: var(--space-ms);
    width: 100%;
    padding: var(--space-sm) var(--space-ms);
    margin-bottom: var(--space-2xs);
    border: 0;
    border-radius: var(--radius-md);
    background: transparent;
    color: var(--text-secondary);
    font-family: inherit;
    font-size: var(--fs-body);
    font-weight: var(--fw-medium);
    text-align: left;
    cursor: pointer;
    transition: background var(--transition-fast), color var(--transition-fast);
}

/* ── L'INDICATORE DELLA SEZIONE APERTA ──
   Il fondo rosa dell'elemento attivo c'era già, ma è un fondo: appare e
   sparisce, non porta da nessuna parte. Questa stanghetta invece CRESCE dal
   centro quando la sezione si apre, e il movimento è la conferma che il tocco
   ha cambiato pagina — cioè arriva prima dei dati, che devono ancora
   arrivare dalla rete.
   È una `scaleY` di uno pseudo-elemento: non ridisegna il menu e non sposta di
   un pixel il testo della voce. */
.nav-item::before {
    content: '';
    position: absolute;
    left: 3px;
    top: 26%;
    bottom: 26%;
    width: 2px;
    border-radius: var(--radius-full);
    /* Nessun colore qui: questa stanghetta non e' MAI dipinta col proprio
       fondo. A riposo sta a scaleY(0), sotto il puntatore la dipinge
       --text-muted, da attiva --comando-ink. Portava un --campo-rosso morto,
       ed era l'ultimo uso di una tinta del codice fuori dagli stati. */
    background: var(--text-muted);
    transform: scaleY(0);
    transition: transform var(--dur-slow) var(--ease-out);
}

.nav-item--active::before { transform: scaleY(1); }

@media (hover: hover) {
    .nav-item:hover {
        background: var(--bg-hover);
        color: var(--text-primary);
    }

    /* Un accenno di stanghetta sotto il puntatore: dice che quella voce PUÒ
       diventare quella attiva, con lo stesso segno che userà quando lo sarà. */
    .nav-item:hover::before {
        transform: scaleY(0.45);
        background: var(--text-muted);
    }

    /* La riga commutata non reagisce al passaggio: un interruttore inserito
       e' inserito. La levetta resta bianca sulla campitura. */
    .nav-item--active:hover {
        background: var(--comando-bg);
        color: var(--comando-ink);
    }

    .nav-item--active:hover::before {
        transform: scaleY(1);
        background: var(--comando-ink);
    }
}

.nav-item:active { background: var(--border); }

/* ── LA SCALA DEL COMANDO, TRE PIOLI, NESSUNO SUL CODICE COLORE ──
   Rilevato nel verdetto: la prima stesura dava la campitura piena d'ambra a
   SEI classi di oggetti — sezione aperta, azione primaria, segmento scelto,
   categoria scelta, passo corrente, giorno scelto — e in una schermata come
   Prenotazioni facevano quattro pieni d'ambra insieme, col riquadro del
   giorno più grande della voce di menu che FIRST VIEWPORT chiama «la sola
   cosa dentro la pozza ambra». Se tutto è nella luce, niente lo è.
   Adesso i pioli sono tre e la differenza è di RUOLO, non di tono:

     PIENO D'AMBRA        la sezione aperta e l'azione primaria — le due sole
                          cose per schermo che sono «la lampada».
     FILO D'AMBRA         ciò che è SCELTO fra alternative (segmento,
         su vetro chiaro    categoria, passo, giorno) e il comando in secondo
                          piano. Scegliere non è accendere: è dire quale.
     VETRO NUDO           tutto il resto.

   Nessuno dei tre tocca il rosso, il giallo, il verde o il blu, che dicono
   solo stato.

   LE CLASSI SONO RIPETUTE DUE VOLTE, e serve. Il fondo a riposo di questi
   quattro oggetti e' dichiarato dalla loro classe base — `.segmented__item`,
   `.calendar__cell` qui sotto, `.step` in waiter.css, `.tab-bar__item` in
   style.css — e tre di quelle regole stanno PIU' IN BASSO di questa o in un
   foglio caricato dopo. A pari specificita' vince l'ultima, quindi una
   regola scritta una volta sola qui verrebbe cancellata dal fondo a riposo
   proprio sull'oggetto scelto. Con la classe doppia la specificita' e'
   (0,2,0) e la scala del comando vince da qualunque punto del progetto,
   senza `!important` e senza duplicare i valori in quattro fogli. */
.selezione-accesa.selezione-accesa,
.segmented__item--active.segmented__item--active,
.tab-bar__item--active.tab-bar__item--active,
.step--active.step--active,
.calendar__cell--selected.calendar__cell--selected {
    background-color: var(--bg-hover);
    background-image: var(--lucido-tenue);
    border-color: var(--luce);
    color: var(--luce-ink);
    font-weight: var(--fw-bold);
    box-shadow: var(--elev-1), var(--luce-tiepido);
}

/* ── LA SOLA COSA NELLA POZZA DI LUCE ──
   La riga della sezione aperta non è evidenziata: è ILLUMINATA. In questo
   mondo essere accesi non vuol dire essere colorati — vuol dire essere
   chiari — quindi la voce aperta è una lastra d'osso caldo con l'inchiostro
   d'ardesia, e intorno le sta l'alone d'ambra della lampada.
   Questo è ciò che tiene le quattro tinte del codice libere di dire solo
   stato: la navigazione non consuma nessuna di esse. Ed è la ragione per cui
   nessuna cascata d'ingresso serve al cambio di sezione: la lastra che si
   accende lo dichiara da sé.
   L'angolo resta morbido come ogni altra lastra: il rettangolo a spigolo vivo
   a tutta larghezza era il segno più pesante del mondo precedente. */
/* Il bordo di campo non è decorazione ed è il motivo per cui la lampada può
   avere la stessa tinta nei due temi: sul tema chiaro l'ambra stacca 1,8:1
   dalla lastra della navigazione e da FORMA non esisterebbe. È la stessa
   regola che il codice colore applica al giallo attenzione — riflesso di luce
   sullo scuro, inchiostro sul chiaro. */
.nav-item--active {
    background-color: var(--comando-bg);
    background-image: var(--lucido);
    color: var(--comando-ink);
    font-weight: var(--fw-bold);
    border: 1px solid var(--bordo-campo);
    border-radius: var(--radius-md);
    box-shadow: var(--elev-1), var(--luce-caldo);
}

/* La levetta sul bordo sinistro resta, ed è ciò che arriva PRIMA dei dati:
   cresce in scaleY al tocco, quindi conferma la pressione mentre la rete
   deve ancora rispondere. Adesso è una pastiglia, non una stanghetta viva. */
.nav-item--active::before {
    background: var(--comando-ink);
    width: 3px;
    top: 26%;
    bottom: 26%;
    border-radius: var(--radius-full);
}

.nav-item--active .nav-item__icon { opacity: 1; transform: none; }

.nav-item__icon {
    width: 18px;
    text-align: center;
    font-size: var(--fs-md);
    flex-shrink: 0;
    opacity: 0.9;
    transition: transform var(--dur-slow) var(--ease-out);
}

/* L'icona non si sposta piu': sulla campitura piena lo spostamento di un
   pixel non aggiunge niente, e la levetta piu' il negativo dicono gia' tutto.
   Vedi .nav-item--active qui sopra. */

.nav-item__label {
    flex: 1;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Contatore accanto alla voce di menu (es. avvisi magazzino) */
/* Esiste solo nella barra in fondo del telefono */
.nav-item--more { display: none; }

/* Il contatore dentro un pulsante: «Lista della spesa 4». Stessa pastiglia del
   badge di navigazione, ma allineata al testo del pulsante. */
.btn__count {
    min-width: 18px;
    height: 18px;
    padding: 0 var(--space-xs);
    margin-left: var(--space-sm);
    border-radius: var(--radius-full);
    background: var(--accent-primary-fill);
    color: var(--text-on-accent);
    font-variant-numeric: tabular-nums;
    font-size: var(--fs-micro);
    font-weight: var(--fw-bold);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
}

.nav-item__badge {
    min-width: 18px;
    height: 18px;
    padding: 0 var(--space-xs);
    border-radius: var(--radius-full);
    background: var(--accent-primary-fill);
    color: var(--text-on-accent);
    font-variant-numeric: tabular-nums;
    font-size: var(--fs-micro);
    font-weight: var(--fw-bold);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
}

.sidebar__footer {
    flex-shrink: 0;
    border-top: 1px solid var(--border);
    padding: var(--space-ms);
}

.sidebar__user {
    display: flex;
    align-items: center;
    gap: var(--space-sm);
    padding: var(--space-sm);
    margin-bottom: var(--space-sm);
}

/* Serve al taglio con i puntini del nome utente: senza, il blocco di testo
   non scende sotto la sua larghezza minima e allarga la sidebar. */
.sidebar__user > div { min-width: 0; }

.sidebar__avatar {
    width: 28px;
    height: 28px;
    border-radius: 50%;
    background: var(--accent-primary-soft);
    color: var(--accent-primary-text);
    display: flex;
    align-items: center;
    justify-content: center;
    font-weight: var(--fw-bold);
    font-size: var(--fs-sm);
    flex-shrink: 0;
}

.sidebar__user-name {
    font-size: var(--fs-sm);
    font-weight: var(--fw-semi);
    line-height: var(--lh-flat);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.sidebar__user-role {
    font-size: var(--fs-micro);
    color: var(--text-muted);
    text-transform: capitalize;
}

.sidebar__actions {
    display: flex;
    gap: var(--space-sm);
}

/* ── Area principale ── */
.main {
    grid-column: 2;
    display: flex;
    flex-direction: column;
    /* La targa d'identificazione in cima e l'area di lavoro sotto sono due
       piastre, non una colonna divisa da un bordo. */
    gap: var(--fuga);
    overflow: hidden;
    min-width: 0;
}

/* ── LA LASTRA SOTTO LA LAMPADA ──
   E' la lastra che sta nella pozza di luce, e l'unica che la dichiara: il
   campo d'ambra sul terzo alto e' un secondo strato dentro la lastra, non un
   fondo tinto — passa sopra il velo e si spegne prima di arrivare al testo.
   E' anche il motivo per cui il nome della sezione si legge come inciso e non
   come scritto sopra: la luce arriva da dietro di lui.
   Il campo NON si anima e non pulsa: e' una lampada accesa, non un effetto. */
.topbar {
    position: relative;
    height: var(--topbar-h);
    flex-shrink: 0;
    display: flex;
    align-items: center;
    gap: var(--space-md);
    padding: 0 var(--space-ml);
    background: var(--bg-secondary);
    border-radius: var(--radius-lg);
    box-shadow: var(--elev-1);
    overflow: hidden;
}

/* LA POZZA, e in tutto lo schermo è questa. Sta sopra il nome della sezione —
   non in mezzo al vuoto fra il titolo e l'orologio, che era dove cadeva nella
   prima stesura — e da lì scende sulla riga delle misure sotto. È il motivo
   per cui il nome della sezione si legge come inciso invece che scritto
   sopra: la luce gli arriva da dietro. */
.topbar::before {
    content: '';
    position: absolute;
    inset: 0;
    pointer-events: none;
    background: radial-gradient(660px 220px at 9% -52%, var(--luce-alone), transparent 74%);
}

/* Il contenuto della barra sta SOPRA la pozza: senza questo, un campo
   posizionato dentro la barra finirebbe dietro il proprio alone. */
.topbar > * { position: relative; z-index: 1; }

/* Il nome della sezione sta nella luce, quindi non ha bisogno di un fondo:
   la pozza d'ambra e' il suo sfondo. Il maiuscolo spaziato resta — la parola
   e' corta e la spaziatura la fa leggere come un'incisione — e l'inchiostro
   e' quello primario, non l'ottone: e' il titolo della schermata, la cosa da
   leggere prima, e un'etichetta in ottone e' un livello piu' in basso nella
   gerarchia. */
.topbar__title {
    font-family: var(--font-display);
    font-size: var(--fs-lg);
    font-weight: var(--fw-display);
    text-transform: uppercase;
    letter-spacing: 0.09em;
    line-height: 1.2;
    color: var(--text-primary);
}

.topbar__subtitle {
    font-size: var(--fs-xs);
    color: var(--text-muted);
}

.topbar__spacer { flex: 1; }

.topbar__meta {
    display: flex;
    align-items: center;
    gap: var(--space-ms);
    font-size: var(--fs-sm);
    color: var(--text-muted);
    font-variant-numeric: tabular-nums;
}

.page {
    flex: 1;
    overflow-y: auto;
    padding: var(--space-ml);
}

.page__section { display: none; }
.page__section--active { display: block; }

/* LA CASCATA D'INGRESSO E' STATA TOLTA, di proposito. Era del mondo
   precedente: a ogni cambio di sezione i blocchi salivano uno dietro l'altro.
   Un quadro d'impianto non si monta davanti a chi lo guarda — c'e' gia', e
   quando lo si apre le spie sono nello stato in cui sono. Che la sezione sia
   cambiata lo dice l'interruttore inserito nella legenda (.nav-item--active),
   non un'animazione di mezzo secondo su quindici pannelli. Questo e' anche
   cio' che rende istantaneo il passaggio fra sezioni.
   Il keyframe rise-in resta in style.css: lo usano ancora l’avviso e la
   pagina senza rete, dove qualcosa è davvero appena comparso. */

/* Barra strumenti sopra i dati: filtri a sinistra, azioni a destra */
.toolbar {
    display: flex;
    align-items: center;
    gap: var(--space-sm);
    flex-wrap: wrap;
    margin-bottom: var(--space-md);
}

.toolbar__spacer { flex: 1; }

.toolbar__label {
    font-size: var(--fs-xs);
    color: var(--text-muted);
    font-weight: var(--fw-semi);
    white-space: nowrap;
}

.toolbar__group {
    display: flex;
    align-items: center;
    gap: var(--space-sm);
}

.toolbar__divider {
    width: 1px;
    height: 22px;
    background: var(--border);
}

/* =============================================
   SEGMENTI (filtri mutuamente esclusivi)
   ============================================= */
.segmented {
    display: inline-flex;
    background: var(--bg-track);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    padding: var(--space-2xs);
    gap: var(--space-2xs);
}

.segmented__item {
    padding: var(--space-xs) var(--space-ms);
    border: 0;
    border-radius: var(--radius-sm);
    background: transparent;
    color: var(--text-secondary);
    font-family: inherit;
    font-size: var(--fs-sm);
    font-weight: var(--fw-medium);
    cursor: pointer;
    white-space: nowrap;
    transition: background var(--transition-fast),
                color var(--transition-fast),
                box-shadow var(--transition-fast),
                transform var(--dur-instant) var(--ease-quick);
}

@media (hover: hover) {
    .segmented__item:hover { color: var(--text-primary); background: var(--bg-hover); }
}

.segmented__item:active { transform: scale(0.96); }

.segmented__item:disabled {
    opacity: 0.45;
    cursor: not-allowed;
    transform: none;
}

/* Il segmento scelto è ALZATO fuori dalla scanalatura, ed è la stessa lastra
   accesa della sezione aperta: osso caldo, inchiostro d'ardesia, alone tiepido
   intorno. Un solo linguaggio per «questo è scelto», in tutto il gestionale. */
/* Il segmento scelto prende il filo d'ambra: vedi la scala del comando sopra.
   Il bordo va dichiarato perché la guida del segmentato non ne dà uno. */
.segmented__item--active.segmented__item--active { border: 1px solid var(--luce); }

/* =============================================
   PANNELLI E CARD
   ============================================= */
/* ── LA LASTRA ──
   Il pannello e' una lastra di vetro appoggiata sul piano: angolo morbido,
   filo di luce sul bordo alto, ombra lunga sotto, taglio del vetro intorno
   (il bordo arriva dal blocco LA SUPERFICIE DI VETRO). Il margine inferiore
   e' lo stacco fra due lastre: dodici pixel, cioe' quanto serve perche'
   ognuna abbia la propria ombra invece di sporcare la vicina.
   Il ritaglio serve: dentro ci sono testate a tutta larghezza e tabelle che
   scorrono, e con l'angolo morbido spunterebbero fuori. */
.panel {
    background-color: var(--bg-card);
    background-image: var(--lucido-tenue);
    border-radius: var(--radius-lg);
    box-shadow: var(--elev-1);
    overflow: hidden;
    margin-bottom: var(--fuga);
}

/* Sotto l'ultimo pannello di una sezione torna il respiro: il blocco finisce. */
.panel:last-child { margin-bottom: var(--space-ml); }

/* `flex-wrap` perché alcune testate portano dei controlli (le due date e il
   filtro dello storico comande): senza andare a capo il pulsante "Cerca"
   finiva fuori dal pannello e non si poteva premere. */
/* La testata della lastra e' il suo terzo illuminato: un campo d'ambra molto
   tenue che scende da sopra e un filo inciso sotto. Non e' un nastro nero
   incollato in cima — quello era il mondo precedente, e in una pagina da sei
   pannelli erano sei fasce nere a tutta larghezza. Qui la testata e' la parte
   della lastra su cui cade la luce, e il titolo si legge dentro quella luce. */
/* La testata NON porta la pozza di luce, e questa è una correzione registrata:
   la prima stesura ci metteva un campo d'ambra, e con sei pannelli per pagina
   (due sole nella sezione prenotazioni) diventavano sei pozze — cioè una
   velatura calda su tutta la pagina invece di una lampada. Un alone che sta
   dappertutto non illumina niente: è carta da parati, ed è precisamente il
   modo in cui il vetro e la luce diventano decorazione.
   LA POZZA STA SU UN OGGETTO SOLO PER SCHERMO — la barra in cima (.topbar,
   .navbar in style.css) e la testata di una modale, che è uno schermo a sé.
   Il RIFLESSO invece resta su ogni lastra: quello è il materiale del vetro,
   non la lampada (vedi --lucido-tenue). */
.panel__head {
    display: flex;
    align-items: center;
    gap: var(--space-ms);
    padding: var(--space-ms) var(--space-md);
    border-bottom: 1px solid var(--border);
    flex-wrap: wrap;
}

.panel__title {
    font-family: var(--font-display);
    color: var(--text-primary);
    text-transform: none;
    letter-spacing: var(--tracking-snug);
    font-size: var(--fs-md);
    font-weight: var(--fw-display);
}

/* Il titolo di un pannello era 0,85 rem contro gli 0,84 delle celle sotto:
   mezzo pixel di differenza, cioè nessuna. Ora sta un gradino sopra il corpo,
   ed è il primo appiglio quando si scorre una pagina di sei pannelli. */
.panel__title {
    font-size: var(--fs-md);
    font-weight: var(--fw-bold);
    letter-spacing: var(--tracking-snug);
    line-height: var(--lh-flat);
}

.panel__count {
    font-size: var(--fs-xs);
    color: var(--nastro-ink);
    font-weight: var(--fw-semi);
    font-variant-numeric: tabular-nums;
    background: var(--nastro-bg);
    border: 1px solid var(--border);
    padding: var(--space-2xs) var(--space-sm);
    border-radius: var(--radius-full);
}

.panel__spacer { flex: 1; }
.panel__body { padding: var(--space-md); }

/* Lo scorrimento orizzontale sta DENTRO il pannello: le tabelle dei report
   vivono in pannelli affiancati (`.grid--2`) e sotto i 620 px la colonna si
   stringe più della tabella. Senza questo la tabella sfondava il pannello. */
.panel__body--flush { padding: 0; overflow-x: auto; }

/* Le griglie si accostano a fuga: le piastre di statistica e i riquadri dei
   tavoli formano un quadro continuo, non una fila di schede separate. */
.grid {
    display: grid;
    gap: var(--fuga);
}

/* Il `min(…, 100%)` è la difesa contro lo sfondamento: `minmax(340px, 1fr)`
   crea una colonna che NON scende sotto i 340 px, così a 360 px di schermo
   (contenuto utile 332 px) la griglia era più larga del suo contenitore e la
   parte a destra finiva tagliata da `.app { overflow: hidden }`, irraggiungibile.
   Con `min()` la colonna vale 340 px finché c'è spazio, poi si adatta. */
.grid--2 { grid-template-columns: repeat(auto-fit, minmax(min(340px, 100%), 1fr)); }
.grid--3 { grid-template-columns: repeat(auto-fit, minmax(min(260px, 100%), 1fr)); }
.grid--stats { grid-template-columns: repeat(auto-fit, minmax(min(170px, 100%), 1fr)); }

/* Unità o secondo termine accanto a un numero grande ("3 / 12" nei tavoli) */
.stat__unit { font-size: var(--fs-md); font-weight: var(--fw-semi); }

/* Griglia inserita in testa a un pannello senza padding */
.grid--inset { padding: var(--space-md) var(--space-md) 0; }

/* =============================================
   RIQUADRI STATISTICA
   ============================================= */
/* Il riquadro statistica è la prima cosa che si guarda aprendo una sezione, e
   non si tocca: tutto il suo lavoro è farsi leggere da lontano. Il rilievo lo
   stacca dalla pagina; il filo d'accento sul bordo alto — un pixel, e solo sui
   riquadri che portano un colore di stato — dice a quale famiglia appartiene
   il numero senza colorare il riquadro intero. */
/* ── LA LASTRA DI MISURA ──
   E' la prima cosa che si guarda aprendo una sezione e non si tocca: tutto
   il suo lavoro e' farsi leggere da lontano. Lastra di vetro, cifra alta
   quanto la lastra, barra d'acciaio in fondo.
   La luce le arriva dall'alto come a ogni altra lastra, e questo e' il
   dettaglio che le lega alla barra sotto la lampada: la fila delle misure e
   la barra della sezione sono illuminate dalla stessa lampada, quindi si
   leggono come un blocco solo invece che come quattro schede. */
.stat {
    position: relative;
    background-color: var(--bg-card);
    background-image: var(--lucido-tenue);
    border-radius: var(--radius-lg);
    box-shadow: var(--elev-1);
    padding: var(--space-md);
    overflow: hidden;
}

/* Vedi la nota su .panel__head: la lastra di misura porta il RIFLESSO del
   vetro (--lucido-tenue, sulla regola sopra) e non la pozza della lampada.
   Cinque misure in fila erano cinque pozze. */
.stat > * { position: relative; }


/* L'etichetta della misura e' incisa nell'ottone: nessun fondo, lettere
   spaziate, un gradino sotto la cifra nella gerarchia. Il nastro nero pieno
   sopra ogni numero era la ragione per cui una fila di cinque misure sembrava
   una fila di cinque targhe da magazzino. */
.stat__label {
    font-family: var(--font-display);
    display: block;
    color: var(--nastro-ink);
    font-size: var(--fs-micro);
    font-weight: var(--fw-bold);
    text-transform: uppercase;
    letter-spacing: 0.14em;
    line-height: 1.4;
    margin-bottom: var(--space-sm);
}

/* LA CIFRA E' ALTA QUANTO LA TARGA, che e' quello che FIRST VIEWPORT
   promette. Era a 36px dentro una piastra da 86 con un vuoto morto sotto:
   misurata in revisione e corretta. A 3rem con interlinea 0,92 la cifra
   riempie la piastra e si legge in piedi dalla porta dell'ufficio, che e' il
   compito dichiarato. */
.stat__value {
    font-family: var(--font-display);
    font-size: 3rem;
    font-weight: var(--fw-display);
    letter-spacing: -0.035em;
    font-variant-numeric: tabular-nums;
    line-height: 0.92;
}

.stat__hint {
    font-size: var(--fs-xs);
    color: var(--text-secondary);
    line-height: var(--lh-flat);
    margin-top: var(--space-xs);
}

/* ── DUE COSE DIVERSE, DUE RESE DIVERSE ──
   Qui c'era un errore mio, corretto: avevo dato a .stat--warning la campitura
   piena, ma in questo gestionale quei quattro modificatori NON segnalano un
   allarme — marcano la CATEGORIA di una misura. Li usa quattordici volte il
   pannello, e fra quelle ci sono «Entrato in cassa», «Uscite totali» e
   «Sconti concessi». Una piastra gialla piena con dentro uno zero grida al
   lupo, e un incasso in campitura rossa dice che qualcosa non va quando
   invece e' andato bene.

   La regola giusta e' quella della segnaletica vera:
     UNO STATO prende la campitura intera — il tavolo occupato, il piatto sul
       fuoco, la comanda in ritardo, la sezione aperta. Sono cose che stanno
       succedendo adesso e chiedono qualcosa.
     UNA MISURA prende la BARRA DI CODICE — la fascia di colore in cima alla
       piastra, che e' come sono marcate le targhe in un quadro per dire a
       quale circuito appartengono. Dice di che famiglia e' il numero, non che
       c'e' un problema.
   Correzione successiva, dalla revisione di finitura: le barre e le cifre NON
   pescano piu' dalla tavolozza degli stati. La distinzione misura/stato
   reggeva, l'assegnazione dell'inchiostro no — «CONTI APERTI» portava la
   barra rossa da fermo su del denaro entrato, e il passe mostrava «0 IN
   CORSO» in giallo d'attenzione. Adesso la barra e' ACCIAIO e la cifra e'
   l'inchiostro neutro: l'acciaio non significa niente, che e' precisamente
   quello che serve a un numero, e quale famiglia sia lo dice l'etichetta.
   Quattro token, nessuna chiamata cambiata, nessuna logica che debba sapere
   il valore: l'allarme falso sparisce per costruzione. */
.stat--accent,
.stat--success,
.stat--warning,
.stat--info { padding-bottom: calc(var(--space-md) + 6px); }

.stat--accent::after,
.stat--success::after,
.stat--warning::after,
.stat--info::after {
    content: '';
    position: absolute;
    bottom: 0;
    left: 0;
    right: 0;
    height: 6px;
    background-color: currentColor;
    opacity: 0.9;
}

/* Il compito della barra: la famiglia «tieni d'occhio» la porta RETINATA. */
.stat--warning::after {
    background-image: var(--retino);
    background-size: auto;
}

.stat--accent::after,
.stat--success::after,
.stat--warning::after,
.stat--info::after { color: var(--misura-barra); }

.stat--accent .stat__value,
.stat--success .stat__value,
.stat--warning .stat__value,
.stat--info .stat__value { color: var(--text-primary); }

/* =============================================
   TABELLE A LISTA
   ============================================= */
.table-wrap {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    max-width: 100%;
}

.data-table {
    width: 100%;
    border-collapse: collapse;
    font-size: var(--fs-body);
}

/* L'INTESTAZIONE CHE RESTA IN CIMA È L'UNICO VETRO SOPRA DEI DATI CHE SCORRONO.
   Il resto del gestionale sfoca solo il fondo, che è fermo (vedi la nota sui
   token --glass-*). Qui no: le righe passano sotto l'intestazione e la
   sfocatura si ricalcola mentre scorrono. Per questo la misura è la metà di
   quella delle barre e il velo è quello COPERTO (--glass-bg-strong): meno
   pixel da sfocare, e i titoli di colonna restano leggibili invece di
   impastarsi con i numeri che gli passano dietro.
   Prima era un fondo pieno, e nel punto in cui una riga scompariva sotto
   l'intestazione la riga veniva tagliata di netto. */
/* L'intestazione resta in cima e le righe le passano SOTTO, quindi ha bisogno
   di un fondo coperto: il velo denso, non quello leggero. La sfocatura la
   riceve dal blocco LA SUPERFICIE DI VETRO, tranne quando l'intestazione sta
   dentro un'altra lastra — allora cade, perche' sfocherebbe uno strato gia'
   uniforme una volta per fotogramma mentre le righe scorrono.
   L'ottone e non il grigio: e' un'etichetta, ed e' il livello di gerarchia
   in cui in questo mondo si scrive in ottone. */
.data-table thead th {
    font-family: var(--font-display);
    position: sticky;
    top: 0;
    z-index: 1;
    background: var(--glass-bg-strong);
    color: var(--nastro-ink);
    padding: var(--space-ms) var(--space-md);
    text-align: left;
    font-size: var(--fs-micro);
    font-weight: var(--fw-bold);
    text-transform: uppercase;
    letter-spacing: 0.12em;
    border-bottom: 1px solid var(--border-light);
    white-space: nowrap;
    line-height: var(--lh-flat);
}

.data-table tbody td {
    padding: var(--space-sm) var(--space-md);
    border-bottom: 1px solid var(--border);
    vertical-align: middle;

    /* Il fondo della riga sotto il puntatore appariva di colpo. In una tabella
       di trenta righe, muovendo il mouse in verticale, quei salti secchi sono
       la cosa che si nota di più della pagina: la transizione li rende un
       passaggio di luce. Sta sulla CELLA e non sulla riga perché è la cella a
       portare il fondo. */
    transition: background var(--dur-fast) var(--ease-quick),
                color var(--dur-fast) var(--ease-quick);
}

.data-table tbody tr:last-child td { border-bottom: 0; }
@media (hover: hover) {
    .data-table tbody tr:hover { background: var(--bg-hover); }

    /* Una riga che si APRE deve dirlo prima del clic. Il puntatore a mano lo
       dice solo mentre ci si è già sopra; qui la prima colonna — che porta
       sempre il nome della cosa — passa al colore del locale, e si vede con
       la coda dell'occhio mentre si scorre l'elenco. */
    /* Una riga che si APRE deve dirlo prima del clic, e lo dice con la LUCE:
       il nome della cosa passa all'ambra, che in questo mondo significa
       «qui sta l'attenzione» e non «c'è un problema». Verificato sul fondo
       composito della riga sotto il puntatore: 6,1:1. */
    .data-table tbody tr.is-clickable:hover td:first-child { color: var(--luce-ink); }
}

.data-table tbody tr.is-clickable { cursor: pointer; }
.data-table tbody tr.is-muted { opacity: 0.5; }

/* NUMERI IN COLONNA. `tabular-nums` c'era su alcune celle e non su altre, e
   sull'intestazione mancava l'allineamento a destra: il titolo della colonna
   stava a sinistra e i numeri sotto a destra, quindi non si capiva quale
   colonna stesse titolando. */
.data-table .num,
.data-table th.num {
    text-align: right;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.data-table .center { text-align: center; }
.data-table .shrink { width: 1%; white-space: nowrap; }

.cell-strong { font-weight: var(--fw-semi); }

.cell-sub {
    display: block;
    font-size: var(--fs-xs);
    color: var(--text-muted);
    margin-top: var(--space-2xs);
}

.cell-mono {
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum";
}

.cell-actions {
    display: flex;
    gap: var(--space-xs);
    justify-content: flex-end;
}

/* =============================================
   BADGE E PASTIGLIE DI STATO
   ============================================= */
/* ── LA PASTIGLIA DI STATO E' UNA PIASTRINA ──
   Non piu' una pastiglia tonda con il testo del colore dello stato su un
   fondo tinto al 14%: una piastrina rettangolare con la CAMPITURA piena e il
   testo in negativo. Il bordo e' il canale di forma e cambia col tema (vedi
   la nota su --bordo-campo), il maiuscoletto e' l'incisione. */
/* La pastiglia di stato e' una lastrina di vetro colorato: pieno tondo,
   campitura piu' il velo di lucido, e il filo di campo intorno che e' il
   canale di forma. Lo spigolo quasi vivo del mondo precedente era la cosa che
   piu' faceva somigliare una pastiglia a un'etichetta industriale. */
.badge {
    font-family: var(--font-display);
    display: inline-flex;
    align-items: center;
    gap: var(--space-xs);
    padding: 3px var(--space-ms);
    border-radius: var(--radius-full);
    font-size: var(--fs-micro);
    font-weight: var(--fw-bold);
    text-transform: uppercase;
    letter-spacing: 0.08em;
    white-space: nowrap;
    border: 1px solid var(--bordo-campo);
    background-image: var(--lucido);
    box-shadow: inset 0 1px 0 var(--bisello);
}

.badge::before {
    content: '';
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: currentColor;
    flex-shrink: 0;
}

/* ── IL PALLINO CHE BATTE QUANDO IL LAVORO È IN CORSO ──
   Tutte le pastiglie di stato avevano lo stesso pallino fermo: "in attesa",
   "in preparazione" e "pronto" si distinguevano solo dal colore e dalla
   parola. Ma tre di questi stati sono FOTOGRAFIE (pagato, servito, annullato)
   e due sono LAVORO CHE STA SUCCEDENDO ADESSO — una comanda inviata che la
   cucina ha preso in mano, un piatto sul fuoco. Il battito distingue le due
   famiglie prima che si legga la scritta, ed è l'informazione che serve a chi
   passa davanti allo schermo senza fermarsi.

   Batte l'OPACITÀ del solo pallino: niente si sposta, niente cambia misura,
   nessun testo diventa illeggibile a metà ciclo. */
.badge--preparing::before,
.badge--sent::before {
    animation: pulse-dot 1.8s var(--ease-in-out) infinite;
}

/* ── IL TERZO GRADO: A FILO ──
   Difetto misurato in revisione: «LIBERO» era un fondo tinto con testo
   colorato — testo a 4,12:1 e fondo a 1,24:1 dalla sua piastra, cioe' una
   pastiglia senza forma — ripetuta tredici volte nel primo viewport. Ed era
   proprio la cosa che THESIS rifiuta per nome.
   Adesso e' il terzo grado del canale: contorno da 2px su tutto il
   perimetro nell'inchiostro dello stato, fondo trasparente, testo a peso
   d'inchiostro. Cosi' pieno / retinato / a filo sono tre gradi di un sistema
   invece di due piu' un'eccezione, e il grado si riconosce senza vedere il
   colore. */
.badge--free,
.badge--pending {
    background: transparent;
    color: var(--accent-success-text);
    border: 2px solid var(--accent-success-text);
    box-shadow: none;
}

/* «In attesa» non e' «in regola»: stesso grado a filo, inchiostro neutro. */
.badge--pending {
    color: var(--text-secondary);
    border-color: var(--text-secondary);
}

/* FERMO. */
.badge--occupied,
.badge--cancelled {
    background: var(--accent-primary-fill);
    color: var(--text-on-accent);
}

/* ATTENZIONE, la famiglia «sta succedendo adesso» (comanda inviata, piatto
   sul fuoco, tavolo che ha chiesto il conto): campitura piena piu' la FASCIA
   retinata sul bordo basso, che e' il secondo canale.
   La fascia e NON il riempimento: col retino su tutta la piastra il
   tratteggio passava sotto il testo e lo rendeva illeggibile — succedeva su
   «Chiama sala» in cucina. Un canale che rende illeggibile l'etichetta che
   accompagna non e' un canale, e' un danno. */
.badge--waiting_bill,
.badge--preparing,
.badge--sent {
    background-color: var(--accent-secondary-fill);
    background-image: var(--retino);
    background-size: 100% var(--retino-h);
    background-position: bottom left;
    background-repeat: repeat-x;
    color: var(--text-on-warning);
    padding-bottom: calc(2px + var(--retino-h));
}

/* IN REGOLA. */
.badge--ready,
.badge--paid,
.badge--confirmed,
.badge--received {
    background: var(--accent-success-fill);
    color: var(--text-on-success);
}

/* DA FARE. */
.badge--reserved,
.badge--served,
.badge--seated {
    background: var(--accent-info-fill);
    color: var(--text-on-info);
}

/* CHIUSO — anche questo a filo, ma con l'inchiostro tenue: e' finito, non
   chiede niente, e si legge ancora. Il contorno e' da 1px e non da 2 perche'
   la differenza fra «non c'e' niente da fare» e «e' stato fatto» sta nel
   peso del filo. */
.badge--no_show,
.badge--completed,
.badge--draft {
    background: transparent;
    color: var(--text-muted);
    border: 1px solid var(--text-muted);
    box-shadow: none;
}

/* Badge senza pallino, per etichette non di stato */
.tag {
    display: inline-flex;
    align-items: center;
    gap: var(--space-xs);
    padding: var(--space-2xs) var(--space-sm);
    border-radius: var(--radius-sm);
    background: var(--bg-input);
    border: 1px solid var(--border);
    font-size: var(--fs-xs);
    font-weight: var(--fw-semi);
    color: var(--text-secondary);
    white-space: nowrap;
}

/* "Tutto il menu": è il caso da guardare, non un'informazione neutra —
   un'aggiunta senza categorie compare anche su una bottiglia d'acqua. */
.tag--warn { color: var(--accent-secondary); border-color: var(--accent-secondary); }

/* ── LA POSTAZIONE NON E' UNO STATO ──
   Pizzeria, cucina e bar sono la CATEGORIA di un prodotto — dove si prepara —
   non qualcosa che sta succedendo. Portavano il giallo attenzione, il blu
   d'obbligo e il verde in regola, cioe' tre tinte del codice su un'etichetta
   che non segnala niente: e' la stessa cosa che facevano le piastre di misura
   prima di passare all'acciaio.
   Adesso sono targhette d'ottone: la parola dice quale postazione, che e' il
   suo mestiere, e le tre tinte tornano disponibili per gli stati veri. */
.tag--pizza,
.tag--kitchen,
.tag--bar {
    background: var(--nastro-bg);
    color: var(--nastro-ink);
    border-color: var(--border);
    box-shadow: none;
    font-family: var(--font-display);
    text-transform: uppercase;
    letter-spacing: 0.1em;
}

/* =============================================
   PULSANTI
   ============================================= */
/* ── IL TASTO DEL QUADRO ──
   Piastrina con il bisello sopra e l'incisione sotto, spigolo quasi vivo,
   etichetta in maiuscoletto spaziato: e' come sono marcati i pulsanti su un
   quadro vero, e a colpo d'occhio distingue un comando da un'etichetta. */
.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-sm);
    padding: var(--space-sm) var(--space-md);
    border: 1px solid var(--glass-border);
    border-radius: var(--radius-md);
    box-shadow: var(--elev-1);
    /* NIENTE MAIUSCOLO sui tasti, e la ragione e' misurata: in segnaletica il
       maiuscolo sta sulle parole CORTE — STOP, USCITA, il numero di un
       circuito — perche' senza le ascendenti e le discendenti una parola si
       riconosce dalla forma solo se e' breve. Qui dentro ci sono etichette
       come «Conferma e manda in cucina», 26 caratteri: in maiuscolo diventa
       una fila di rettangoli da leggere lettera per lettera, e questo e' un
       gestionale dove si preme di fretta.
       Il tasto resta un comando grazie al peso e alla spaziatura, che sono
       gli altri due segnali di una legenda di quadro. Il maiuscolo resta
       dov'e' sempre corto: nastri, titoli di piastra, pastiglie di stato,
       filtri di categoria. */
    letter-spacing: 0.03em;
    background: var(--bg-elevated);
    color: var(--text-primary);
    font-family: inherit;
    font-size: var(--fs-sm);
    font-weight: var(--fw-semi);
    line-height: var(--lh-flat);
    cursor: pointer;
    white-space: nowrap;

    /* Tre cose si muovono su un tasto, e ognuna ha la sua velocita': il fondo
       e il bordo cambiano in 180 ms (un cambio di stato, non un'attesa),
       l'ombra segue la stessa curva perche' e' la LUCE che cambia con
       l'altezza, e la posizione va sul gradino piu' corto — 110 ms — perche'
       il rientro deve arrivare al dito e non all'occhio. */
    transition: background var(--transition-fast),
                border-color var(--transition-fast),
                box-shadow var(--transition-fast),
                transform var(--dur-instant) var(--ease-morbido);
}

/* ── PERCHÉ TUTTI GLI `:hover` DEL FOGLIO STANNO IN `@media (hover: hover)` ──
   Su uno schermo touch il browser applica `:hover` all'ultimo elemento
   toccato e ce lo LASCIA finché non se ne tocca un altro. In sala il tavolo
   appena aperto restava schiarito anche dopo aver chiuso la modale, e a colpo
   d'occhio sembrava quello selezionato. `hover: hover` accende queste regole
   solo dove c'è un puntatore vero. Il segnale del tocco è `:active`, che dura
   quanto il dito. */
/* Sotto il puntatore il tasto SI ALZA di un pixel e la sua ombra si allunga:
   e' una lastra che si stacca dal piano, non un rettangolo che si schiarisce.
   Un pixel e non tre — in una barra di quattro tasti affiancati uno che si
   alza troppo copre il bordo del vicino. */
@media (hover: hover) {
    .btn:hover {
        background: var(--bg-hover);
        border-color: var(--border-light);
        transform: translateY(-1px);
        box-shadow: var(--elev-2);
    }
}

/* IL PULSANTE RIENTRA, NON SCENDE. Un `translateY(1px)` sposta l'etichetta di
   un pixel e il bordo resta dov'era: sembra un difetto di allineamento. Una
   riduzione dell'1,5% rimpicciolisce il pulsante INTERO verso il suo centro,
   che è come si comporta un tasto vero sotto il dito. In sala, dove si tocca
   con lo schermo sporco e le mani occupate, è la conferma che il tocco è
   arrivato prima che la richiesta parta. */
/* IL TASTO SI SCHIACCIA CONTRO IL PIANO. Una riduzione dell'1,5% rimpicciolisce
   il tasto INTERO verso il proprio centro e l'ombra si accorcia con lui, che
   e' come si comporta una lastra spinta giu' — un `translateY` invece sposta
   l'etichetta di un pixel e lascia il bordo dov'era, e sembra un difetto di
   allineamento. In sala, dove si tocca con lo schermo sporco e le mani
   occupate, e' la conferma che il tocco e' arrivato prima che la richiesta
   parta. */
.btn:active {
    transform: scale(0.975);
    box-shadow: var(--shadow-sm), inset 0 1px 2px var(--incisione);
}

.btn:disabled {
    opacity: 0.45;
    cursor: not-allowed;
    transform: none;
    box-shadow: none;
}

/* Il pulsante spento non deve reagire al passaggio: il fondo che si schiariva
   era l'unico segnale che restava, e diceva il contrario di quello che
   succede al clic. */
.btn:disabled:hover {
    background: var(--bg-elevated);
    border-color: var(--glass-border);
    transform: none;
    box-shadow: none;
}

/* ── I PULSANTI PIENI SONO SOLLEVATI ──
   Erano rettangoli di colore appoggiati sulla pagina, alla stessa quota di un
   pulsante grigio: il colore era l'unica differenza. Un'ombra CORTA e tinta
   del colore del pulsante stesso (non nera: un'ombra nera sotto un rosso lo
   sporca di grigio) li porta un piano sopra, e il filo di luce sul bordo alto
   li fa leggere come tasti.
   È l'azione principale della schermata: deve essere la cosa che si vede
   prima di aver letto le etichette. */
/* L'azione primaria e' l'INTERRUTTORE PRINCIPALE, e commuta grafite-e-bianco
   (vedi la nota su --comando-bg). Non e' rossa: il rosso segnale dice «fermo»,
   e «Incassa» o «Conferma e manda in cucina» sono l'opposto di un fermo. */
/* L'azione primaria e' LA COSA ACCESA della schermata: la stessa lastra d'osso
   caldo della sezione aperta, con l'alone d'ambra intorno. Non e' rossa — il
   rosso segnale dice «fermo», e «Incassa» o «Conferma e manda in cucina» sono
   l'opposto di un fermo — e non e' ambra piena, perche' l'ambra in questo
   mondo e' luce e non pittura. */
/* L'alone e' TIEPIDO e non caldo, e la ragione e' di gerarchia: il caldo e' la
   COSA nella pozza di luce, una per schermo, ed e' la sezione aperta. Di
   azioni primarie invece ce ne sono due o tre per schermata — una per pannello
   piu' quella nel piede di una modale — e dando a tutte l'alone pieno la
   scala di luce perdeva significato: se tutto e' illuminato, niente lo e'.
   Sotto il puntatore l'azione sale al caldo: la si sta per premere. */
.btn--primary {
    background: var(--comando-bg);
    border-color: var(--bordo-campo);
    color: var(--comando-ink);
    box-shadow: var(--elev-1), var(--luce-tiepido);
}

.btn--primary:hover {
    filter: brightness(1.04);
    background: var(--comando-bg);
    border-color: var(--bordo-campo);
    box-shadow: var(--elev-2), var(--luce-caldo);
}

/* Sul pieno d'accento l'anello del fuoco tocca il fondo rosso e si sporca:
   uno stacco di 1 px del colore della pagina lo separa. */
/* Sul pieno d'accento l'anello del fuoco tocca la campitura e si sporca: uno
   stacco di 1 px del colore del substrato lo separa, e il rilievo va
   riscritto insieme perche' e' la stessa proprieta'. */
/* Il tasto d'attenzione non e' piu' un pieno (vedi la nota su .btn--warning),
   quindi esce da questa regola: l'anello di fuoco su un tasto a filo non
   tocca nessuna campitura e non ha bisogno dello stacco. */
.btn--primary:focus-visible,
.btn--success:focus-visible {
    box-shadow: 0 0 0 1px var(--substrato), var(--elev-1);
}

/* Vedi la nota su .btn--primary: stesso rilievo. */
/* La CAMPITURA e non l'inchiostro: --accent-success e' la variante schiarita
   per il testo, e su un tasto pieno era un verde slavato. */
/* La CAMPITURA piu' il velo di lucido: e' la resa che rende ogni campo di
   questo mondo *vetro* colorato invece di un rettangolo di tinta. La luce
   scivola sul terzo alto e si spegne prima dell'etichetta, quindi il
   contrasto del testo non lo tocca. */
.btn--success {
    background-color: var(--accent-success-fill);
    background-image: var(--lucido);
    border-color: var(--bordo-campo);
    color: var(--text-on-success);
    box-shadow: var(--elev-1), 0 6px 20px -8px var(--alone-verde);
}

.btn--success:hover { filter: brightness(1.1); background-color: var(--accent-success-fill); }

/* Il tasto d'attenzione: CAMPITURA (non l'inchiostro — sul tema chiaro
   --accent-secondary e' un ocra scuro, tarato per leggersi come testo, e come
   fondo di un tasto sarebbe stato marrone) piu' la fascia retinata in basso.
   Il retino su tutto il fondo passava sotto l'etichetta e la rendeva
   illeggibile: succedeva su «Chiama sala» in cucina. */
/* ── IL COMANDO IN SECONDO PIANO, E PERCHE' NON E' PIU' GIALLO ──
   Questo tasto portava la campitura del GIALLO ATTENZIONE piu' la fascia
   retinata, ed era sbagliato due volte.
   La prima: il retino e' il secondo canale degli STATI — «sta succedendo
   adesso» — e questo non e' uno stato, e' un comando. Lo usano «Conto»,
   «Apri conto» e «Chiama sala»: cose da premere, non cose che accadono. Su un
   tasto alto ventisei pixel la fascia occupava un quarto della superficie e
   il tasto si leggeva come nastro da cantiere invece che come un comando —
   rilevato in riesame sulle catture della cucina.
   La seconda: consumava una delle quattro tinte del codice per
   un'interfaccia, che e' esattamente cio' che THESIS rifiuta.
   Adesso e' il gradino intermedio di una scala di comando a tre pioli, e
   nessuno dei tre tocca il codice colore:
     PIENO D'AMBRA   l'azione primaria — la lampada (.btn--primary)
     AMBRA A FILO    l'azione in secondo piano — questo tasto
     VETRO NUDO      l'azione neutra (.btn)
   Il retino resta dov'e' sempre stato utile: sugli stati — pastiglia
   d'attenzione, tavolo in attesa di conto, colonna «in preparazione» del
   passe, barra della misura da tenere d'occhio, prenotazione in ritardo. */
.btn--warning {
    background-color: var(--bg-elevated);
    background-image: var(--lucido-tenue);
    border-color: var(--luce);
    color: var(--luce-ink);
    font-weight: var(--fw-bold);
    box-shadow: var(--elev-1);
}

.btn--warning:hover {
    background-color: var(--bg-hover);
    border-color: var(--luce);
    box-shadow: var(--elev-2), var(--luce-tiepido);
}

.btn--ghost {
    background: transparent;
    border-color: transparent;
    color: var(--text-secondary);
}

.btn--ghost:hover { background: var(--bg-hover); color: var(--text-primary); border-color: transparent; box-shadow: var(--elev-1); }

.btn--danger { color: var(--accent-primary-text); }
.btn--danger:hover { background: var(--accent-primary-soft); border-color: var(--accent-primary); }

.btn--sm { padding: var(--space-xs) var(--space-ms); font-size: var(--fs-xs); border-radius: var(--radius-sm); }
.btn--lg { padding: var(--space-ms) var(--space-lg); font-size: var(--fs-md); border-radius: var(--radius-lg); }

/* I DUE MODIFICATORI DI MISURA CANCELLAVANO LA CORSIA DEL RETINO.
   `.btn--warning` si riserva sei pixel di imbottitura in fondo perché la
   fascia retinata ci passa dentro; `.btn--sm` e `.btn--lg` dichiarano
   `padding` per intero e stanno DOPO nel foglio, quindi quella riserva
   spariva e il retino finiva sotto l'etichetta. Si vedeva su «Chiama sala»
   in cucina, che è un `.btn--sm` giallo: la parola era attraversata dalle
   righe. Le due regole qui rimettono la corsia sulla misura giusta. */
/* Le due regole che rimettevano la corsia del retino sulle misure piccola e
   grande non servono piu': il tasto d'attenzione non porta il retino (vedi la
   nota su .btn--warning). Sono state tolte invece di essere lasciate a
   correggere un problema che non esiste. */
.btn--full { width: 100%; }
.btn--icon { padding: var(--space-sm); }

/* =============================================
   ICONE — Lucide, al posto delle emoji
   =============================================
   Le emoji le disegnava ogni sistema a modo suo: la stessa stampante era grigia
   su Windows e azzurra su Android, molte non seguivano il colore del testo —
   quindi restavano colorate sul tema chiaro e su un pulsante rosso — e in
   caratteri diversi cambiavano larghezza, sbilanciando le barre.

   Qui invece: disegno unico, colore da `currentColor`, misura in `em` che segue
   il testo intorno. */
.icon {
    width: 1.15em;
    height: 1.15em;
    /* Le icone stanno quasi sempre accanto a del testo: allineate alla linea di
       base scivolerebbero in basso. `-0.14em` le centra sull'occhio medio. */
    vertical-align: -0.14em;
    flex-shrink: 0;
    /* Su un tratto di 2 unità in un riquadro di 24, ridotto a 1em, le linee
       sottili sparivano sugli schermi a bassa densità della sala. */
    stroke-width: 2;
    pointer-events: none;
}

/* Dentro un pulsante il `gap` del flex separa già icona ed etichetta. */
.btn .icon { width: 1.05em; height: 1.05em; vertical-align: 0; }

/* Un pulsante di sola icona: l'icona è il contenuto, e va un filo più grande. */
.btn--icon .icon { width: 1.25em; height: 1.25em; }

.icon--lg { width: 1.6em; height: 1.6em; }
.icon--xl { width: 2.4em; height: 2.4em; }

/* Colori di stato, per le icone che dicono com'è andata. */
.icon--ok    { color: var(--accent-success); }
.icon--warn  { color: var(--accent-secondary); }
.icon--error { color: var(--accent-primary-text); }
.icon--info  { color: var(--accent-info); }
.icon--muted { color: var(--text-muted); }

/* Scelta dell'icona di una categoria del menu: si vede quello che si sceglie,
   invece di scrivere il nome di un'icona a memoria. */
.icon-picker {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-xs);
    padding: var(--space-sm);
    background: var(--bg-input);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    max-height: 8.5rem;
    overflow-y: auto;
}

.icon-picker__item {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    padding: 0;
    color: var(--text-secondary);
    background: transparent;
    border: 1px solid transparent;
    border-radius: var(--radius-sm);
    cursor: pointer;
}

@media (hover: hover) {
    .icon-picker__item:hover { background: var(--bg-hover); color: var(--text-primary); }
}

.icon-picker__item:active { transform: scale(0.92); }

.icon-picker__item--active {
    color: var(--accent-primary-text);
    background: var(--accent-primary-soft);
    border-color: var(--accent-primary);
}

.icon-picker__item .icon { width: 18px; height: 18px; vertical-align: 0; }

/* =============================================
   VARIANTI E AGGIUNTE
   =============================================
   Stavano in waiter.css. Sono componenti, non roba di sala: da quando il
   pannello compone gli asporti presi al telefono servono a due aree, e una
   copia per area sarebbe una seconda definizione da tenere allineata a mano. */
.variants-list {
    display: flex;
    flex-direction: column;
    gap: var(--space-xs);
    max-height: 240px;
    overflow-y: auto;
}

.variant-option {
    display: grid;
    grid-template-columns: 22px 1fr auto auto;
    gap: var(--space-sm);
    align-items: center;
    padding: var(--space-sm) var(--space-ms);
    background: var(--bg-input);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    cursor: pointer;
    font-size: var(--fs-body);
    transition: border-color var(--transition-fast),
                background var(--transition-fast),
                transform var(--dur-instant) var(--ease-quick);
}

.variant-option:active { transform: scale(0.99); }

.variant-option--selected {
    border-color: var(--accent-primary);
    background: var(--accent-primary-soft);
}

/* Mancava del tutto: la riga di un'aggiunta non dava nessun segno prima del
   clic, e l'elenco è alto — si sbaglia riga. */
@media (hover: hover) {
    .variant-option:hover { border-color: var(--border-light); background: var(--bg-hover); }
    .variant-option--selected:hover { border-color: var(--accent-primary); background: var(--accent-primary-soft); }
}

.variant-option__check {
    width: 20px;
    height: 20px;
    border: 1px solid var(--border-light);
    border-radius: var(--radius-sm);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: var(--fs-xs);
    font-weight: var(--fw-bold);
    color: var(--accent-primary-text);
}

/* LA CASELLA SPUNTATA SI RIEMPIE CON UN RIMBALZO CORTO. È l'unica cosa che
   conferma di aver aggiunto una variante a un piatto — non c'è nessun altro
   ritorno, la riga resta dov'è — e in sala si tocca in fretta, una dopo
   l'altra: senza il segno si ricontrolla, e ricontrollare costa più tempo del
   tocco. Novanta millesimi, quanto la pressione di un tasto. */
.variant-option--selected .variant-option__check {
    border-color: var(--accent-primary-fill);
    background: var(--accent-primary-fill);
    color: var(--text-on-accent);
    animation: check-pop var(--dur-fast) var(--ease-out);
}

@keyframes check-pop {
    from { transform: scale(0.7); }
    60% { transform: scale(1.08); }
    to { transform: none; }
}

.variant-option__name { font-weight: var(--fw-semi); }

.variant-option__type {
    font-size: var(--fs-xs);
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: var(--tracking-label);
}

.variant-option__price {
    font-size: var(--fs-sm);
    font-weight: var(--fw-bold);
    font-variant-numeric: tabular-nums;
    color: var(--text-muted);
}

.variant-option__price--add { color: var(--accent-secondary); }
.variant-option__price--remove { color: var(--accent-success); }

/* =============================================
   TOGLIERE UN INGREDIENTE DAL PIATTO
   =============================================
   «Una tonno e cipolla senza cipolla». Sono gli ingredienti della ricetta.

   Stessa forma delle aggiunte qui sopra — riga, casella, etichetta: il gesto è
   identico, e due grafiche diverse a mezzo centimetro di distanza facevano
   sembrare due cose diverse quello che diverso non è. */
.removals-list {
    display: flex;
    flex-direction: column;
    gap: var(--space-xs);
    max-height: 240px;
    overflow-y: auto;
}

.removal-option {
    display: grid;
    grid-template-columns: 22px 1fr auto;
    gap: var(--space-sm);
    align-items: center;
    padding: var(--space-sm) var(--space-ms);
    background: var(--bg-input);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    cursor: pointer;
    font-size: var(--fs-body);
    color: var(--text-primary);
    transition: border-color var(--transition-fast), background var(--transition-fast);
}

@media (hover: hover) {
    .removal-option:hover { border-color: var(--border-light); background: var(--bg-hover); }
}

.removal-option__check {
    width: 20px;
    height: 20px;
    border: 1px solid var(--border-light);
    border-radius: var(--radius-sm);
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--text-on-accent);
}
.removal-option__check .icon { width: 0.9em; height: 0.9em; vertical-align: 0; }

.removal-option__name { font-weight: var(--fw-semi); }

.removal-option__type {
    font-size: var(--fs-xs);
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: var(--tracking-label);
}

/* Tolto: casella con la X, nome barrato, rosso. Nella casella va una X e non
   una spunta — qui «scelto» vuol dire SENZA, e una spunta direbbe il contrario
   di quello che succede al piatto. Il barrato è la cosa che si legge da
   lontano: il colore da solo non basta a chi non lo distingue. */
.removal-option--tolto {
    border-color: var(--accent-primary);
    background: var(--accent-primary-soft);
}

/* Vedi la nota su .variant-option--selected .variant-option__check: qui la
   conferma conta ancora di più, perché togliere un ingrediente da un piatto è
   la cosa che in cucina non si può indovinare guardando il piatto. */
.removal-option--tolto .removal-option__check {
    border-color: var(--accent-primary);
    background: var(--accent-primary-fill);
    animation: check-pop var(--dur-fast) var(--ease-out);
}

.removal-option--tolto .removal-option__name {
    color: var(--accent-primary-text);
    text-decoration: line-through;
    text-decoration-thickness: 1.5px;
}

/* I «senza» nel carrello e nella comanda in composizione: in cucina sono la
   riga che manda indietro un piatto se non la si legge. */
.cart-item__mod--senza,
.current-order__mods--senza {
    color: var(--accent-primary-text);
    font-weight: var(--fw-semi);
}

/* =============================================
   RIGHE DEL CARRELLO — sala e pannello
   =============================================
   STAVANO SOLO IN waiter.css, e il pannello non lo carica.
   Risultato: nella modale dell'asporto queste righe non avevano NESSUNO stile —
   div impilati uno sull'altro, i pulsanti grigi di serie del browser, il totale
   come testo qualunque. Lo stesso componente, disegnato in un posto solo.

   La riga è a DUE PIANI per default: il nome del prodotto sopra, su una riga
   sua, e sotto quantità, prezzo e il pulsante per togliere. È la forma che
   regge a qualunque larghezza — la colonna del carrello nel pannello è larga
   260px — e il nome è il dato che si legge mentre il cliente detta, quindi non
   va tagliato a due parole. Su un carrello largo la riga si distende su un
   piano solo: lo decide la larghezza del CARRELLO, non quella della finestra,
   ed è per questo che è una @container e non una @media. */
.cart-item {
    display: grid;
    grid-template-columns: 1fr auto;
    grid-template-areas:
        "nome    rimuovi"
        "quantita prezzo";
    gap: var(--space-sm) var(--space-ms);
    align-items: center;
    padding: var(--space-ms);
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
}

/* Le righe non si toccano: erano incollate perché il contenitore del pannello
   non dava spazio fra una e l'altra. */
.cart-item + .cart-item { margin-top: var(--space-sm); }

/* min-width: 0 sulla colonna del nome: senza, la colonna 1fr si allarga fino
   al contenuto e spinge prezzo e "✕" fuori dalla riga. */
.cart-item__main { grid-area: nome; min-width: 0; }

.cart-item__name {
    font-weight: var(--fw-bold);
    font-size: var(--fs-md);
    line-height: var(--lh-snug);
    /* Un nome lungo va a capo invece di allargare la riga: «Alette di pollo
       con patatine» non sta in 260px su una riga sola. */
    overflow-wrap: anywhere;
}

.cart-item__mods {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-xs);
    margin-top: var(--space-xs);
}

.cart-item__mod {
    font-size: var(--fs-xs);
    padding: var(--space-2xs) var(--space-sm);
    border-radius: var(--radius-sm);
    background: var(--bg-input);
    border: 1px solid var(--border);
    color: var(--text-secondary);
}

.cart-item__notes {
    font-size: var(--fs-xs);
    color: var(--text-muted);
    margin-top: var(--space-xs);
    font-style: italic;
}

/* ── La quantità: UN comando, non tre pulsanti sparsi ──
   Erano tre elementi staccati, due tondi grigi e un numero in mezzo: sembravano
   tre cose indipendenti. Uniti in una pastiglia sola con un bordo intorno si
   leggono per quello che sono — «meno, quanti, più». */
.cart-item__qty {
    grid-area: quantita;
    display: inline-flex;
    align-items: center;
    justify-self: start;
    border: 1px solid var(--border);
    border-radius: var(--radius-full);
    background: var(--bg-track);
    overflow: hidden;
}

.cart-item__qty-btn {
    width: 30px;
    height: 28px;
    border: 0;
    background: transparent;
    color: var(--text-secondary);
    font-size: var(--fs-lg);
    font-weight: var(--fw-bold);
    line-height: 1;
    cursor: pointer;
    transition: background var(--transition-fast), color var(--transition-fast);
}

.cart-item__qty-btn:hover {
    background: var(--bg-hover);
    color: var(--text-primary);
}

.cart-item__qty-btn:active { background: var(--border); }

/* Il "meno" a quantità 1 non ha niente da fare: senza segno lo si preme e
   non succede nulla. */
.cart-item__qty-btn:disabled {
    opacity: 0.35;
    cursor: not-allowed;
    background: transparent;
}

.cart-item__qty-value {
    min-width: 26px;
    text-align: center;
    font-weight: var(--fw-bold);
    font-size: var(--fs-body);
    /* Cifre a larghezza fissa: passando da 9 a 10 la pastiglia non si allarga
       e i pulsanti non si spostano sotto il dito. */
    font-variant-numeric: tabular-nums;
    /* Separata dai due pulsanti, così si vede che è un valore e non un tasto. */
    border-inline: 1px solid var(--border);
    align-self: stretch;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}

.cart-item__price {
    grid-area: prezzo;
    font-weight: var(--fw-bold);
    font-variant-numeric: tabular-nums;
    text-align: right;
    white-space: nowrap;
}

/* ── Il pulsante per togliere ──
   Era un quadrato grigio pieno, grosso come i pulsanti della quantità e su una
   riga sua: pesava quanto il prodotto che doveva togliere. Ora è in alto a
   destra, senza fondo, e si colora di rosso solo quando ci passi sopra —
   presente ma non invitante, che è il tono giusto per un'azione che cancella. */
.cart-item__remove {
    grid-area: rimuovi;
    align-self: start;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 26px;
    height: 26px;
    border: 0;
    background: transparent;
    color: var(--text-muted);
    font-size: var(--fs-md);
    cursor: pointer;
    border-radius: var(--radius-sm);
    transition: background var(--transition-fast), color var(--transition-fast);
}

.cart-item__remove:hover {
    color: var(--accent-primary-text);
    background: var(--accent-primary-soft);
}

/* Il totale, che nel pannello era testo nudo. */
.cart__total {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: var(--space-ms);
    font-size: var(--fs-md);
    font-weight: var(--fw-semi);
}

.cart__total-price {
    font-size: var(--fs-2xl);
    font-weight: var(--fw-display);
    font-variant-numeric: tabular-nums;
    letter-spacing: var(--tracking-tight);
    line-height: var(--lh-tight);
    white-space: nowrap;
}

/* Su un carrello largo — la sala su tablet orizzontale — tutto su un piano.
   Serve che il contenitore dichiari `container-type: inline-size`: se non lo
   fa, questa regola non si applica e resta la forma a due piani, che funziona
   comunque. È il ripiego giusto. */
@container carrello (min-width: 400px) {
    .cart-item {
        grid-template-columns: 1fr auto auto auto;
        grid-template-areas: "nome quantita prezzo rimuovi";
        gap: var(--space-ms);
        padding: var(--space-ms);
    }

    .cart-item__remove { align-self: center; }
    .cart-item__price { min-width: 66px; }
}

/* =============================================
   CAMPI
   ============================================= */
/* `resize: vertical` come regola e non come `style` sui singoli campi: un
   textarea allargabile in orizzontale sfonda il modale. */
textarea.input { resize: vertical; }

/* ── IL CAMPO E' UN INCAVO, NON UNA PIASTRA ──
   Dove si scrive, il pannello e' fresato: fondo piu' scuro del substrato e
   l'ombra INTERNA in alto, cioe' il verso opposto del bisello di una piastra.
   E' quello che distingue a colpo d'occhio le cose su cui si scrive da quelle
   che si leggono, senza aggiungere un bordo colorato. */
.input,
select.input,
textarea.input {
    width: 100%;
    padding: var(--space-ms) var(--space-md);
    background: var(--bg-input);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    box-shadow: inset 0 1px 3px var(--incisione);
    color: var(--text-primary);
    font-family: inherit;
    font-size: var(--fs-body);
    transition: border-color var(--transition-fast),
                box-shadow var(--transition-fast),
                background var(--transition-fast);
}

@media (hover: hover) {
    .input:hover:not(:disabled) { border-color: var(--border-light); }
}

/* IL CAMPO ATTIVO SI ACCENDE. Prima cambiava solo il bordo: un pixel di rosso
   su un modulo di dodici campi, e per trovare dove si stava scrivendo bisognava
   cercarlo. L'alone è il colore del locale al 14% e allarga il segnale a tre
   pixel intorno al campo, che si vede con la coda dell'occhio.
   Non è un'ombra e non finge di essere profondità: non ha scostamento perché
   deve circondare il campo in modo uguale da tutti i lati, come un anello. */
/* Il campo attivo: l'incavo resta e intorno si accende l'anello. NON e'
   rosso: nel codice colore il rosso dice «fermo», e un anello rosso intorno
   al campo in cui si sta scrivendo direbbe che c'e' un problema. E' il colore
   dell'indicatore di posizione, che non dice nessuno stato — bianco sullo
   scuro, quasi-nero sul chiaro. */
/* Il campo al fuoco non cambia forma: si ACCENDE. Il filo prende l'ambra
   della lampada e intorno gli sale l'alone caldo, che e' lo stesso segnale
   della lastra accesa — un solo linguaggio per «qui sta l'attenzione».
   L'ambra e non una tinta del codice: un anello rosso intorno al campo in cui
   si sta scrivendo direbbe che c'e' un problema. */
.input:focus {
    outline: none;
    border-color: var(--focus-ring);
    box-shadow: inset 0 1px 3px var(--incisione),
                0 0 0 2px var(--focus-ring),
                0 0 0 6px var(--luce-soft);
}

/* L'`outline: none` qui sopra è per il clic col mouse, dove il bordo rosso
   basta. Da tastiera no: senza anello, passando i campi con il Tab non si sa
   in quale si sta scrivendo — e la cassa si compila così. Questa regola viene
   dopo e ha la stessa specificità, quindi rimette l'anello nel solo caso in
   cui serve. */
.input:focus-visible {
    outline: var(--focus-width) solid var(--focus-ring);
    outline-offset: 1px;
}

/* Campo non compilabile: era identico a uno vuoto da riempire, e chi lo
   trovava vuoto ci provava. */
.input:disabled {
    background: var(--bg-secondary);
    color: var(--text-muted);
    cursor: not-allowed;
    border-color: var(--border);
    box-shadow: none;
}

.input::placeholder { color: var(--text-muted); }
.input--auto { width: auto; }
.input--sm { padding: var(--space-xs) var(--space-sm); font-size: var(--fs-sm); }

/* Campo per un numero corto (persone, quantità): stretto ma con il tetto al
   100%, così su schermo piccolo non sfonda mai il contenitore. */
.input--narrow { width: 110px; max-width: 100%; }

.field { margin-bottom: var(--space-ms); }

.field__label {
    display: block;
    font-size: var(--fs-sm);
    font-weight: var(--fw-semi);
    color: var(--text-secondary);
    line-height: var(--lh-flat);
    margin-bottom: var(--space-xs);
}

.field__hint {
    display: block;
    font-size: var(--fs-xs);
    color: var(--text-muted);
    margin-top: var(--space-xs);
    line-height: var(--lh-body);
}

.field-row {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(150px, 100%), 1fr));
    gap: var(--space-ms);
}

/* Pila verticale di campi dentro i modali: sostituisce i
   `style="display:flex;flex-direction:column;gap:12px"` ripetuti nei template. */
.stack {
    display: flex;
    flex-direction: column;
    gap: var(--space-ms);
}

/* Riquadro con elenco a scelta multipla (i tavoli di una prenotazione): i
   tavoli possono essere tanti e non devono allungare il modale oltre lo
   schermo. Le caselle dentro si dispongono da sé con `.check-row`. */
.pick-box {
    max-height: 180px;
    overflow-y: auto;
    padding: var(--space-xs);
}

/* =============================================
   INCASSO — la modale del pagamento
   =============================================
   ERANO DUE COPIE DIVERSE. La modale la costruisce `public/js/conto.js`, che è
   un modulo condiviso: la usano il pannello (Cassa e conti) e la sala. Le sue
   classi però erano definite sia in admin.css sia in waiter.css, con valori
   diversi — corpo 0,86 contro 0,88 rem, totale 1,3 contro 1,35, colonne da 104
   contro 112 px, pulsanti alti 33 contro 42 px. Lo stesso pannello di cassa
   aveva due facce a seconda di chi lo apriva.

   E `.pay-history` (l'elenco degli incassi già fatti) esisteva SOLO in
   admin.css: in sala quel blocco era testo nudo senza fondo né rientro.

   Una definizione sola, qui, tarata sul dito: la cassa la si batte in fretta e
   spesso sul tablet, dove sbagliare il metodo di pagamento significa storno. */
.pay-summary { font-size: var(--fs-body); }

.pay-summary__row {
    display: flex;
    justify-content: space-between;
    gap: var(--space-ms);
    padding: var(--space-xs) 0;
    color: var(--text-secondary);
}

/* Il "da pagare" è la cifra su cui si conta il resto: il gradino più alto
   della modale. */
.pay-summary__row--total {
    border-top: 1px solid var(--border);
    margin-top: var(--space-sm);
    padding-top: var(--space-sm);
    font-size: var(--fs-xl);
    font-weight: var(--fw-display);
    color: var(--text-primary);
    letter-spacing: var(--tracking-tight);
}

.pay-summary__row--total strong { font-variant-numeric: tabular-nums; }

.pay-history {
    margin-top: var(--space-ms);
    padding: var(--space-sm) var(--space-ms);
    background: var(--bg-input);
    border-radius: var(--radius-md);
    font-size: var(--fs-xs);
    color: var(--text-muted);
    line-height: var(--lh-body);
    font-variant-numeric: tabular-nums;
}

/* Il `min(…, 100%)` era una correzione applicata solo nel pannello: senza,
   una colonna da 112 px sfonda un modale stretto. */
.pay-methods {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(112px, 100%), 1fr));
    gap: var(--space-sm);
    margin-top: var(--space-sm);
}

.pay-method {
    min-height: 48px;
    padding: var(--space-ms) var(--space-sm);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    background: var(--bg-input);
    color: var(--text-primary);
    font-family: inherit;
    font-size: var(--fs-body);
    font-weight: var(--fw-semi);
    cursor: pointer;
    transition: border-color var(--transition-fast),
                background var(--transition-fast),
                color var(--transition-fast),
                transform var(--dur-instant) var(--ease-quick);
}

@media (hover: hover) {
    .pay-method:hover { border-color: var(--border-light); background: var(--bg-hover); }
}

.pay-method:active { transform: scale(0.97); }

.pay-method--active {
    border-color: var(--accent-primary);
    background: var(--accent-primary-soft);
    color: var(--accent-primary-text);
}

.pay-quick {
    display: flex;
    gap: var(--space-sm);
    flex-wrap: wrap;
    margin-top: var(--space-sm);
}

/* L'importo battuto: `.input.pay-amount` e non `.pay-amount` da sola perché
   il campo porta anche la classe `.input`, definita sopra in questo stesso
   file — a pari specificità vincerebbe quella, e la cifra resterebbe a 14 px. */
.input.pay-amount,
.pay-amount {
    margin-top: var(--space-sm);
    font-size: var(--fs-xl);
    font-weight: var(--fw-bold);
    text-align: right;
    font-variant-numeric: tabular-nums;
}

.pay-change {
    margin-top: var(--space-ms);
    padding: var(--space-ms);
    border-radius: var(--radius-md);
    background: var(--accent-success-soft);
    border: 1px solid var(--accent-success);
    text-align: center;
    font-size: var(--fs-md);
}

/* Il resto da dare: è l'unica cifra che si legge guardando il cassetto. */
.pay-change strong {
    font-size: var(--fs-2xl);
    font-weight: var(--fw-display);
    font-variant-numeric: tabular-nums;
    letter-spacing: var(--tracking-tight);
}

/* Sul telefono e sul tablet la cassa si batte col pollice, e un tocco
   sbagliato sul metodo di pagamento è uno storno. */
@media (hover: none) {
    .pay-method { min-height: 52px; }
    .pay-quick .btn { min-width: 48px; }
}

/* =============================================
   AVVISI
   ============================================= */
.notice {
    display: flex;
    align-items: flex-start;
    gap: var(--space-ms);
    padding: var(--space-ms) var(--space-md);
    border-radius: var(--radius-md);
    border: 1px solid var(--border);
    background: var(--bg-card);
    font-size: var(--fs-body);
    line-height: var(--lh-body);
    margin-bottom: var(--space-md);
    box-shadow: var(--elev-1);

    /* Un avviso COMPARE: non era nella pagina un attimo prima. Quasi tutti
       questi avvisi si accendono dopo un tentativo andato male — password
       sbagliata, orario già occupato — e chi ha appena premuto Invio sta
       guardando il pulsante, non il punto in cui l'avviso apparirà. Sei pixel
       di salita glielo portano nel campo visivo.
       Non c'è nulla da nascondere: il messaggio arriva nella pagina già
       leggibile, e l'animazione è solo il modo in cui ci arriva. */
    animation: rise-in var(--dur-slow) var(--ease-out);
}

.notice__icon { flex-shrink: 0; font-size: var(--fs-lg); line-height: var(--lh-flat); }

/* Elenco dentro un avviso: gli orari già presi su più tavoli. */
.notice__list { margin: var(--space-xs) 0 var(--space-sm); padding-left: var(--space-ml); }
.notice__list li { margin-bottom: var(--space-xs); }

.notice--ok { background: var(--accent-success-soft); border-color: var(--accent-success); }
.notice--warn { background: var(--accent-secondary-soft); border-color: var(--accent-secondary); }
.notice--error { background: var(--accent-primary-soft); border-color: var(--accent-primary); }
.notice--info { background: var(--accent-info-soft); border-color: var(--accent-info); }

/* =============================================
   STATO VUOTO
   ============================================= */
.empty {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: var(--space-sm);
    padding: var(--space-xl) var(--space-ml);
    text-align: center;
    color: var(--text-muted);
}

.empty__icon { font-size: var(--fs-2xl); opacity: 0.5; }
.empty__text { font-size: var(--fs-body); }

.empty--compact { padding: var(--space-lg) var(--space-md); }

/* =============================================
   SALA — pianta dei tavoli
   ============================================= */
/* Una sola misura di fuga in tutto il gestionale: il quadro dei tavoli
   accostava a 12 px mentre la riga delle misure a 2, e due misure di fuga
   sono due mondi. Misurato in revisione. */
.floor {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(158px, 100%), 1fr));
    gap: var(--fuga);
}

.floor-zone { margin-bottom: var(--space-lg); }

.floor-zone__head {
    display: flex;
    align-items: center;
    gap: var(--space-sm);
    margin-bottom: var(--space-ms);
}

/* Il nome della zona è inciso nell'ottone, come ogni altra etichetta di
   questo mondo: nessun fondo, lettere spaziate, e il filetto a lato che
   continua fino al bordo della pagina. */
.floor-zone__name {
    font-family: var(--font-display);
    color: var(--nastro-ink);
    font-size: var(--fs-micro);
    font-weight: var(--fw-bold);
    text-transform: uppercase;
    letter-spacing: 0.16em;
}

.floor-zone__rule {
    flex: 1;
    height: 1px;
    background: var(--border);
}

.table-tile {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: var(--space-sm);
    padding: var(--space-md);
    background-color: var(--bg-card);
    background-image: var(--lucido-tenue);
    border: 1px solid var(--glass-border);
    border-radius: var(--radius-lg);
    box-shadow: var(--elev-1);
    cursor: pointer;
    /* La tinta dello stato cambia in 180 ms — un cambio di stato, non
       un'attesa — l'ombra la segue perché è la luce che cambia con l'altezza,
       e la posizione va sul gradino più corto perché il tocco deve arrivare
       al dito. Vedi la grammatica del movimento in style.css. */
    transition: background var(--transition-fast),
                border-color var(--transition-fast),
                box-shadow var(--transition-fast),
                transform var(--dur-instant) var(--ease-morbido);
    text-align: left;
    font-family: inherit;
    color: inherit;
    min-height: 112px;
    overflow: hidden;
}

/* Il riquadro del tavolo si solleva sotto il puntatore: in una pianta di
   trenta tavoli il solo schiarimento del fondo si perde, e con l'ombra che si
   allunga si vede quale tavolo si sta per aprire anche guardando la pianta di
   sfuggita. Un pixel di alzata, non tre: i riquadri sono affiancati e uno che
   si alza troppo copre il bordo del vicino. */
@media (hover: hover) {
    .table-tile:hover {
        background-color: var(--bg-hover);
        border-color: var(--border-light);
        box-shadow: var(--elev-2);
        transform: translateY(-2px);
    }

    /* Su una lastra colorata il fondo NON si schiarisce: cancellerebbe lo
       stato per il tempo del passaggio, e lo stato è l'unica informazione di
       quella lastra. Si alza e il suo alone si allarga — la luce cambia,
       il significato no. */
    .table-tile--occupied:hover,
    .table-tile--waiting_bill:hover,
    .table-tile--reserved:hover {
        background-color: inherit;
        filter: brightness(1.06);
        transform: translateY(-2px);
    }

    .table-tile--occupied:hover { box-shadow: var(--elev-2), 0 14px 34px -8px var(--alone-rosso); }
    .table-tile--waiting_bill:hover { box-shadow: var(--elev-2), 0 14px 34px -8px var(--alone-giallo); }
    .table-tile--reserved:hover { box-shadow: var(--elev-2), 0 14px 34px -8px var(--alone-blu); }
}

/* Il tavolo si apre col dito: un cenno di pressione dice che il tocco è
   arrivato, prima che la modale finisca di aprirsi. */
.table-tile:active { background-color: var(--bg-hover); transform: scale(0.975); box-shadow: var(--shadow-sm); }

/* ── IL QUADRO DEI TAVOLI ──
   Ogni tavolo e' una piastra e il COLORE E' LO STATO. Un tavolo libero resta
   la piastra nuda: in segnaletica l'assenza di targa vuol dire che non c'e'
   niente da segnalare, ed e' il motivo per cui i tavoli che chiedono qualcosa
   si vedono a colpo d'occhio su una pianta di trenta.
   LA STRISCIA A LATO NON C'E' PIU'. Era un border-left da 3px, cioe' la
   scheda a striscia di stato del mondo precedente sopravvissuta dentro
   quello nuovo, e faceva un quarto canale fuori dottrina accanto a pieno /
   retinato / a filo. Il canale di forma degli stati e' la campitura col suo
   bordo; quello di «niente da fare» e' il filo perimetrale. */
/* LA LASTRA DI VETRO COLORATO. La campitura resta piena — la cucina e la sala
   la leggono da lontano e non si tocca — ma sopra le passa il velo di lucido,
   e sotto le sta l'ALONE della propria tinta: il tavolo occupato illumina di
   rosso il piano intorno a sé. È il canale che il vetro aggiunge ai tre gradi
   di forma, e su una pianta di trenta tavoli è quello che arriva prima del
   testo. */
.table-tile--occupied {
    background-color: var(--accent-primary-fill);
    background-image: var(--lucido);
    color: var(--text-on-accent);
    border-color: var(--bordo-campo);
    box-shadow: var(--elev-1), 0 10px 30px -6px var(--alone-rosso);
}

.table-tile--waiting_bill {
    background-color: var(--accent-secondary-fill);
    background-image: var(--retino), var(--lucido);
    background-size: 100% var(--retino-h), 100% 100%;
    background-position: bottom left, top left;
    background-repeat: repeat-x, no-repeat;
    color: var(--text-on-warning);
    border-color: var(--bordo-campo);
    box-shadow: var(--elev-1), 0 10px 30px -6px var(--alone-giallo);
}

.table-tile--reserved {
    background-color: var(--accent-info-fill);
    background-image: var(--lucido);
    color: var(--text-on-info);
    border-color: var(--bordo-campo);
    box-shadow: var(--elev-1), 0 10px 30px -6px var(--alone-blu);
}

/* Sopra una campitura nessun testo puo' restare grigio: le righe secondarie
   della piastra ereditano il colore su campo e si tengono indietro con
   l'opacita'. */
.table-tile--occupied .table-tile__seats,
.table-tile--waiting_bill .table-tile__seats,
.table-tile--reserved .table-tile__seats,
.table-tile--occupied .table-tile__line,
.table-tile--waiting_bill .table-tile__line,
.table-tile--reserved .table-tile__line {
    color: inherit;
    opacity: 0.85;
}

/* Il pulsante dentro una piastra colorata commuta al valore opposto DELLA
   PIASTRA: fondo scavato e inchiostro ereditato dal campo. La regola sta in
   coda al file, con la classe ripetuta, perche' deve battere il filo blu
   dell'azione neutra — vedi la nota su .table-tile__foot .btn. */
.table-tile--occupied .btn,
.table-tile--waiting_bill .btn,
.table-tile--reserved .btn {
    background: var(--scavo);
    border-color: var(--bordo-campo);
    color: inherit;
}

.table-tile__top {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--space-sm);
}

/* IL NUMERO DEL TAVOLO È IL DATO DELLA PIASTRELLA. Era 1,35 rem accanto a
   "4 posti" a 0,73: un gradino di gerarchia che a un metro di distanza, in una
   sala poco illuminata, non si legge. Ora è il corpo più grande
   dell'interfaccia di sala insieme all'incasso, e i posti restano un dettaglio. */
.table-tile__number {
    font-family: var(--font-display);
    font-size: var(--fs-2xl);
    font-weight: var(--fw-display);
    letter-spacing: var(--tracking-tight);
    line-height: 1;
}

.table-tile__seats {
    font-size: var(--fs-xs);
    color: var(--text-muted);
    white-space: nowrap;
}

.table-tile__name {
    font-size: var(--fs-xs);
    color: var(--text-secondary);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Lo stato del tavolo, scritto. Il bordo colorato da solo non basta: dice
   qualcosa solo a chi ha la legenda davanti. */
/* ── LA PASTIGLIA DI STATO DEL TAVOLO, AL TERZO GRADO ──
   Era una pastiglia tonda con fondo tinto e testo colorato — la cosa che
   THESIS rifiuta per nome — e su «LIBERO» il testo stava a 4,12:1, sotto il
   floor che il contratto stesso impone, ripetuta tredici volte nel primo
   viewport. Togliendo il solo fondo il testo sale a 5,12:1 contro la piastra:
   la stessa modifica chiude il contrasto e la dottrina insieme.
   Il filo è "currentColor", quindi segue l'inchiostro dello stato senza una
   riga per tinta. */
.table-tile__state {
    font-family: var(--font-display);
    display: inline-block;
    align-self: flex-start;
    padding: 1px var(--space-sm);
    border-radius: var(--radius-sm);
    border: 2px solid currentColor;
    font-size: var(--fs-micro);
    font-weight: var(--fw-bold);
    letter-spacing: 0.03em;
    text-transform: uppercase;
    color: var(--text-secondary);
    background: transparent;
}

/* Tavolo accostato a un altro per la stessa prenotazione, con il conto altrove:
   qui non si prende comanda e non si incassa. Si spegne — resta leggibile, ma
   non invita a toccarlo — e il bordo tratteggiato lo lega al gruppo. */
.table-tile--linked {
    opacity: 0.62;
    border-top: 2px dashed var(--accent-info);
}

.table-tile--linked:hover { opacity: 1; }

/* Solo l'inchiostro: il fondo lo toglie la regola sopra, il filo lo prende da
   currentColor. Gli stati diversi da «libero» stanno sempre sopra la propria
   campitura, e là la pastiglia viene scavata dalla regola in coda al file. */
.table-tile__state--occupied { color: var(--accent-primary-text); }
.table-tile__state--waiting_bill { color: var(--accent-secondary-text); }
.table-tile__state--reserved { color: var(--accent-info-text); }
.table-tile__state--free { color: var(--accent-success-text); }

.table-tile__lines {
    display: flex;
    flex-direction: column;
    gap: var(--space-2xs);
    font-size: var(--fs-xs);
    color: var(--text-secondary);
    margin-top: auto;
}

.table-tile__line {
    display: flex;
    align-items: center;
    gap: var(--space-xs);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.table-tile__line--alert { color: var(--accent-primary-text); font-weight: var(--fw-semi); }
.table-tile__line--warn { color: var(--accent-secondary); font-weight: var(--fw-semi); }
.table-tile__line--ok { color: var(--accent-success); font-weight: var(--fw-semi); }
.table-tile__line--info { color: var(--accent-info); }

.table-tile__total {
    font-size: var(--fs-md);
    font-weight: var(--fw-bold);
    font-variant-numeric: tabular-nums;
}

.table-tile__foot {
    display: flex;
    gap: var(--space-xs);
    margin-top: var(--space-xs);
}

.table-tile__foot .btn { flex: 1; min-width: 0; }

/* ── L'AZIONE SULLA PIASTRA SI COMMETTE ──
   Difetto trovato in revisione: su una pianta di tredici tavoli liberi
   l'azione era tredici rettangoli grigi identici — l'elemento piu' ripetuto
   della sala e il meno commesso di tutta la build. In un mondo di piastre
   commutate l'azione non puo' essere l'unica cosa neutra.
   Adesso e' una piastra A FILO nell'inchiostro del «da fare»: il grado dice
   che e' un invito, non uno stato, e il blu d'obbligo dice cosa fare. */
/* Il filo blu vale SOLO sulle piastre neutre, e la condizione sta nel
   selettore invece che in una regola che corregge dopo. La catena di
   :not() sulle classi del pulsante portava questa regola a specificita'
   0,5,0, quindi batteva qualunque correzione in coda al file: sul tavolo
   prenotato l'inchiostro blu finiva sul fondo blu dello stato a 2,16:1, e
   l'azione abilitata leggeva come disabilitata. Escludendo le piastre di
   stato qui, il conflitto non esiste piu' invece di essere vinto. */
.table-tile:not(.table-tile--occupied):not(.table-tile--waiting_bill):not(.table-tile--reserved) .table-tile__foot .btn,
.table-card:not(.table-card--occupied):not(.table-card--waiting_bill):not(.table-card--reserved) .table-card__actions .btn {
    background: transparent;
    border: 2px solid var(--accent-info-text);
    color: var(--accent-info-text);
    box-shadow: none;
    font-weight: var(--fw-bold);
}

/* Legenda degli stati */
.legend {
    display: flex;
    gap: var(--space-md);
    flex-wrap: wrap;
    font-size: var(--fs-xs);
    color: var(--text-secondary);
}

.legend__item { display: flex; align-items: center; gap: var(--space-sm); }

.legend__dot {
    width: 8px;
    height: 8px;
    border-radius: var(--radius-sm);
    flex-shrink: 0;
    background: var(--status-free);
}

/* Il colore della legenda è una scelta di resa, non un dato: sta qui e non
   in uno `style` scritto dal template. */
.legend__dot--free { background: var(--status-free); }
.legend__dot--occupied { background: var(--status-occupied); }
.legend__dot--waiting { background: var(--status-waiting); }
.legend__dot--reserved { background: var(--status-reserved); }

/* =============================================
   CALENDARIO PRENOTAZIONI
   ============================================= */
.calendar {
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    box-shadow: var(--elev-1);
    overflow: hidden;
}

/* ── SETTE COLONNE CHE STANNO DENTRO, SEMPRE ──
   `minmax(0, 1fr)` e non `1fr`, e la differenza è tutto il calendario.
   `1fr` vale `minmax(auto, 1fr)`: la colonna NON scende sotto la larghezza del
   proprio contenuto. Con una prenotazione «Guaglianone» dentro una cella, quella
   colonna si allargava a 116px e le sette diventavano
   `102 23 83 23 23 23 116` — 448px in una scatola da 341, con `.calendar`
   in `overflow: hidden` che tagliava via le ultime due colonne senza modo di
   raggiungerle. L'intestazione, che contiene solo «LUN MAR MER», restava
   regolare a 39px: i nomi dei giorni non erano nemmeno allineati alle celle.
   Rilevato su schermo da 375px, dove il difetto è evidente; ma bastava un
   cognome lungo per vederlo anche su un tablet. */
.calendar__head {
    display: grid;
    grid-template-columns: repeat(7, minmax(0, 1fr));
    gap: var(--space-sm);
    padding: var(--space-sm) var(--space-sm) 0;
}

.calendar__dayname {
    font-family: var(--font-display);
    padding: var(--space-xs) 0;
    font-size: var(--fs-micro);
    font-weight: var(--fw-bold);
    text-transform: uppercase;
    letter-spacing: 0.14em;
    color: var(--nastro-ink);
    text-align: center;
}

.calendar__grid {
    display: grid;
    /* Vedi la nota su .calendar__head: `minmax(0, 1fr)` è ciò che impedisce a un
       cognome lungo di allargare la colonna e sfondare la griglia. */
    grid-template-columns: repeat(7, minmax(0, 1fr));
    gap: var(--space-sm);
    padding: var(--space-sm);
}

/* ── LE CELLE SONO LASTRINE, NON UN RETICOLO ──
   Rilevato in riesame: il calendario era rimasto la sola griglia a spigolo
   vivo del gestionale — celle divise da filetti a novanta gradi, in una
   sezione che alla richiesta «troppo spigoloso» non rispondeva affatto.
   Adesso ogni cella è una lastrina con il proprio angolo e il proprio
   riflesso, e le divide lo stacco del mondo invece di una riga: gli stessi
   dodici pixel di tutte le altre griglie. Il filetto sparisce perché non
   serve più — a separare due lastre basta il piano che si vede fra loro. */
.calendar__cell {
    min-height: 92px;
    /* La cella deve poter stringersi quanto la sua colonna: senza questo il
       contenuto ne stabilisce la larghezza minima e la griglia sfonda di nuovo. */
    min-width: 0;
    padding: var(--space-sm);
    border: 1px solid var(--glass-border);
    border-radius: var(--radius-md);
    background-color: var(--bg-card);
    background-image: var(--lucido-tenue);
    cursor: pointer;
    display: flex;
    flex-direction: column;
    gap: var(--space-xs);
    transition: background var(--transition-fast);
    text-align: left;
    font-family: inherit;
    color: inherit;
    border-top: 0;
    border-left: 0;
}



@media (hover: hover) {
    .calendar__cell:hover { background: var(--bg-hover); }
}

.calendar__cell--outside { background-color: transparent; background-image: none; opacity: 0.45; }
.calendar__cell--today { border-color: var(--accent-info); box-shadow: inset 0 0 0 1px var(--accent-info); }

/* La cella scelta si ALZA dentro la griglia: `z-index` la porta sopra le
   celle vicine, così l'anello di due pixel resta intero su tutti e quattro i
   lati invece di essere coperto dai bordi dei vicini, e l'ombra la stacca dal
   piano del calendario. Prima era solo un fondo rosa in una griglia di celle
   grigie, e su un mese pieno di prenotazioni ci si perdeva il segno. */
/* Il giorno scelto si ALZA dentro la griglia — `z-index` lo porta sopra i
   vicini e l'ombra lo stacca — e porta il filo d'ambra, non la campitura:
   vedi la scala del comando sopra. Da riquadro d'ambra pieno era l'oggetto
   più grande della schermata, e pesava più della sezione aperta. */
.calendar__cell--selected.calendar__cell--selected {
    position: relative;
    z-index: 1;
    border-width: 2px;
    box-shadow: var(--elev-2), var(--luce-tiepido);
}

/* Sopra la cella commutata il numero del giorno e il «+N altre» ereditano
   l'inchiostro del campo. La classe e' ripetuta perche' deve battere la
   regola del giorno di oggi, che porta l'azzurro e viene
   dopo: il giorno di oggi e il giorno scelto sono spesso la stessa cella.
   Le PASTIGLIE no: quelle tengono l'inchiostro del proprio stato, che e'
   l'informazione per cui esistono. */
.calendar__cell--selected.calendar__cell--selected .calendar__daynum,
.calendar__cell--selected.calendar__cell--selected .calendar__more { color: var(--luce-ink); }

.calendar__daynum {
    font-size: var(--fs-sm);
    font-weight: var(--fw-bold);
    font-variant-numeric: tabular-nums;
    color: var(--text-secondary);
}

.calendar__cell--today .calendar__daynum { color: var(--accent-info); }

/* Ogni prenotazione nel calendario è un pulsante: apre il suo dettaglio.
   Serve l'azzeramento dello stile nativo del <button> — font, bordo, larghezza
   e allineamento — altrimenti in ogni cella compaiono bottoncini di sistema. */
.calendar__chip {
    display: flex;
    align-items: center;
    gap: var(--space-xs);
    width: 100%;
    font-family: inherit;
    font-size: var(--fs-micro);
    color: inherit;
    text-align: left;
    padding: var(--space-2xs) var(--space-xs);
    /* Filo perimetrale e non striscia a lato: vedi la nota sul quarto canale
       in .table-tile--occupied. La fascia di servizio la dice l'inchiostro
       del filo, che e' anche il colore del testo. */
    border: 1px solid var(--accent-info-text);
    border-radius: var(--radius-sm);
    background: transparent;
    color: var(--accent-info-text);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    /* `overflow: hidden` da solo non basta a impedire che la pastiglia allarghi
       la cella: la larghezza MINIMA di un elemento flex è quella del suo
       contenuto, e i due valgono insieme. Serve anche sui figli, altrimenti è il
       nome dentro lo <span> a fare da fondo. */
    min-width: 0;
    cursor: pointer;
    transition: background var(--transition-fast),
                transform var(--dur-instant) var(--ease-quick);
}

.calendar__chip > * {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* La pastiglia di una prenotazione è alta 14 px dentro una cella di 92: sotto
   il puntatore si sposta di due pixel verso destra, che su un oggetto così
   piccolo si legge meglio di qualunque cambio di colore. */
@media (hover: hover) {
    .calendar__chip:hover { background: var(--bg-hover); transform: translateX(2px); }
}

.calendar__chip--pranzo { border-color: var(--accent-secondary-text); color: var(--accent-secondary-text); }
.calendar__chip--cena { border-color: var(--accent-info-text); color: var(--accent-info-text); }

/* COME È ANDATA. La prenotazione resta a calendario anche dopo il servizio:
   a distanza di giorni serve sapere se quel tavolo è venuto o no. */

/* Arrivati e a tavola adesso. */
.calendar__chip--seated {
    border-color: var(--accent-success-text);
    color: var(--accent-success-text);
    font-weight: var(--fw-bold);
}

/* Servizio finito: resta leggibile ma non chiede più niente. */
.calendar__chip--completed { opacity: 0.68; }

/* Non presentati: è l'informazione che si va a cercare. */
.calendar__chip--no-show {
    border-color: var(--accent-primary-text);
    color: var(--accent-primary-text);
    text-decoration: line-through;
    text-decoration-thickness: 1px;
}

/* Annullata: è stata cancellata prima, non è un mancato. Terzo grado del
   canale — filo tenue e barrato — invece di un'opacità al 50% che la rendeva
   quasi illeggibile su una cella piena. */
/* Il barrato è già il secondo canale, quindi l'inchiostro non ha bisogno di
   essere anche tenue per dire «non conta più»: due segnali per la stessa cosa
   costavano il contrasto. Rilevato in riesame — su una cella piena il tenue
   barrato stava sotto il minimo. Adesso porta l'inchiostro secondario, che è
   verificato a 4,5:1 sul peggiore fondo del tema, e resta distinto dalle
   altre pastiglie perché nessuna delle altre è barrata. */
.calendar__chip--cancelled {
    border-color: var(--text-secondary);
    color: var(--text-secondary);
    text-decoration: line-through;
    text-decoration-thickness: 1px;
}

/* Clienti attesi e non arrivati: deve saltare all'occhio nel calendario. */
/* Clienti attesi e non arrivati: deve saltare all'occhio, quindi e' l'unico
   stato del calendario che prende la CAMPITURA piena — con la fascia
   retinata, perche' e' la famiglia «tieni d'occhio». */
.calendar__chip--late {
    background-color: var(--accent-secondary-fill);
    background-image: var(--retino);
    background-size: 100% 4px;
    background-position: bottom left;
    background-repeat: repeat-x;
    border-color: var(--bordo-campo);
    color: var(--text-on-warning);
    font-weight: var(--fw-bold);
}

/* Riga di un elenco su cui qualcuno deve agire adesso. */
.row--late > td { background: var(--accent-secondary-soft); }

.calendar__more {
    font-size: var(--fs-micro);
    color: var(--text-muted);
    font-weight: var(--fw-semi);
}

.calendar__load {
    margin-top: auto;
    height: 3px;
    border-radius: var(--radius-full);
    background: var(--border);
    overflow: hidden;
}

.calendar__load-fill {
    height: 100%;
    background: var(--accent-info-fill);
}

/* =============================================
   LISTA CONTI E RIGHE ORDINE
   ============================================= */
.order-line {
    display: grid;
    /* Quarta e quinta colonna: la correzione della quantità (− +) e il pulsante
       di annullamento. Senza colonne loro andavano a capo sotto la riga, e la
       ✕ finiva staccata dal prodotto a cui si riferisce. Restano a 0 quando i
       pulsanti non ci sono. */
    grid-template-columns: 34px 1fr auto auto auto;
    gap: var(--space-sm);
    align-items: baseline;
    padding: var(--space-xs) 0;
    font-size: var(--fs-body);
}

/* Correzione della quantità di una riga già inviata. Non riusa `.qty-stepper`,
   che è il selettore da pollice per i coperti: qui i due tasti stanno dentro una
   riga di elenco, accanto a un prezzo, e a 32 px di diametro la spingerebbero
   fuori misura. */
.order-line__qty-edit {
    display: inline-flex;
    gap: var(--space-2xs);
    align-self: center;
}
.order-line__qty-edit .btn {
    min-width: 26px;
    padding: var(--space-2xs) var(--space-sm);
    line-height: var(--lh-flat);
}

.order-line__qty { color: var(--text-muted); font-weight: var(--fw-bold); text-align: right; }
.order-line__price { font-variant-numeric: tabular-nums; white-space: nowrap; }

.order-line__mods {
    display: block;
    font-size: var(--fs-xs);
    color: var(--text-muted);
    font-style: normal;
}

.totals { margin-top: var(--space-ms); }

.totals__row {
    display: flex;
    justify-content: space-between;
    gap: var(--space-ms);
    padding: var(--space-xs) 0;
    font-size: var(--fs-body);
    color: var(--text-secondary);
}

.totals__row strong { color: var(--text-primary); font-variant-numeric: tabular-nums; }

/* Righe degli incassi: il pulsante di storno sta accanto all'importo, non sotto. */
.totals__row .btn { flex: 0 0 auto; align-self: center; }

.totals__row--total {
    border-top: 1px solid var(--border);
    margin-top: var(--space-sm);
    padding-top: var(--space-sm);
    font-size: var(--fs-lg);
    color: var(--text-primary);
    font-weight: var(--fw-bold);
}

.totals__row--discount { color: var(--accent-primary-text); }
.totals__row--paid { color: var(--accent-success); }

/* =============================================
   MODALI
   ============================================= */
/* ── IL VELO ──
   A 14 px il contenuto dietro diventa forma e colore — si vede ancora DOVE si
   era, ma non si legge più — ed è esattamente il compito di un velo.
   La sfocatura è FERMA: si accende all'apertura e non si anima. Animare il
   raggio di una sfocatura a tutto schermo è la cosa più costosa che un
   browser possa fare, e sui tablet vecchi della sala l'apertura di ogni
   modale sarebbe uno scatto. Ad animarsi è l'OPACITÀ del velo, che la GPU
   compone senza ridisegnare: la sfocatura c'è già a piena forza al primo
   fotogramma e quello che si vede addensarsi è il buio davanti a essa.
   Questa è la sola economia importante dell'intero movimento del mondo, e la
   ragione per cui la modale può permettersi trecento millisecondi di salita
   su un tablet di sette anni. */
.modal-overlay {
    position: fixed;
    inset: 0;
    z-index: 200;
    background: var(--overlay);
    display: flex;
    align-items: center;
    justify-content: center;
    padding: var(--space-ml);
    /* LA CALOTTA. Nel mondo della segnaletica la trasparenza ha un carrier
       onesto: lo sportello in policarbonato di un armadio da quadro, che si
       chiude sopra le targhe. E adesso si VEDE, perche' sotto ci sono piastre
       rosse, gialle e blu invece del grigio piatto del mondo precedente —
       era quello, e non la calibrazione del velo, il motivo per cui il vetro
       non si notava.
       La sfocatura si accende e non si anima: animare il raggio di una
       sfocatura a tutto schermo e' la cosa piu' costosa che un browser possa
       fare, e sui tablet vecchi della sala sarebbe uno scatto a ogni modale. */
    -webkit-backdrop-filter: blur(14px) saturate(130%);
    backdrop-filter: blur(14px) saturate(130%);
    animation: velo-sale var(--dur-modale) var(--ease-luce);
}

/* ── LA MODALE SALE NELLA LUCE ──
   È l'oggetto che galleggia più in alto di tutti, quindi è quello che deve
   mostrare più chiaramente di stare sopra qualcos'altro: velo denso, angolo
   più morbido di ogni altra lastra (22 px, il massimo della scala), filo di
   luce sul bordo alto e l'ombra più lunga del gestionale.

   L'INGRESSO È IL MOMENTO DI MOVIMENTO DEL MONDO, ed è dichiarato nel
   contratto di direzione: la finestra non compare al centro, SALE di dodici
   pixel e arriva dallo 0,965 al pieno mentre la sua ombra si allarga con lei.
   Trecento millisecondi sulla curva lunga: abbastanza per capire DA DOVE è
   arrivata la finestra — ed è questo che la lega al pulsante che l'ha aperta —
   troppo poco per leggersi come attesa.
   Perché sia una salita e non un rimbalzo: `--ease-luce` non torna mai
   indietro. Un'elastica su una finestra di cassa fa sembrare il gestionale un
   giocattolo proprio nel momento in cui si stanno battendo dei soldi. */
.modal {
    width: 100%;
    max-width: 520px;
    max-height: 90vh;
    display: flex;
    flex-direction: column;
    /* Il velo translucido SÌ, la sfocatura NO — e la ragione è misurata, non
       stilistica. Il velo del fondo (.modal-overlay, sopra) sfoca già tutta la
       pagina, e diventa così la "radice di sfondo" della modale: una seconda
       `backdrop-filter` qui dentro non sfocherebbe la pagina, sfocherebbe uno
       strato scuro già quasi uniforme. Risultato invisibile, costo reale — una
       seconda passata di sfocatura a ogni fotogramma, sul tablet più vecchio
       del locale, per l'apertura di ogni modale del gestionale.
       Il 12% di trasparenza resta: attraverso di essa si intravedono le forme
       sfocate della pagina sotto, che è ciò che dice "questa finestra sta
       SOPRA quella schermata, non al posto suo". */
    background-color: var(--glass-bg-strong);
    background-image: var(--lucido-tenue);
    border: 1px solid var(--glass-border);
    border-radius: var(--radius-xl);
    box-shadow: var(--shadow-lg), inset 0 1px 0 var(--glass-highlight);
    overflow: hidden;
    animation: modale-sale var(--dur-modale) var(--ease-luce);
}

/* La testata della modale prende la luce come ogni altra testata di questo
   mondo: il campo d'ambra scende da sopra e si spegne prima del titolo. È il
   dettaglio che dice che la finestra è arrivata SOTTO la stessa lampada e non
   da un altro programma. */
/* Una modale è uno schermo a sé, quindi ha diritto alla propria pozza — ed è
   l'unica eccezione alla regola dell'una per schermo (vedi .panel__head).
   La luce le arriva da sinistra come alla barra in cima, cioè dalla stessa
   lampada: è il dettaglio che dice che la finestra è arrivata sotto quella e
   non da un altro programma. */
.modal__header {
    display: flex;
    align-items: center;
    gap: var(--space-ms);
    padding: var(--space-md) var(--space-ml);
    background-image: radial-gradient(420px 150px at 12% -60%, var(--luce-alone), transparent 74%);
    border-bottom: 1px solid var(--border);
    flex-shrink: 0;
}

.modal__title {
    flex: 1;
    font-size: var(--fs-lg);
    font-weight: var(--fw-bold);
    letter-spacing: var(--tracking-snug);
    line-height: var(--lh-snug);
}

.modal__close {
    border: 0;
    background: transparent;
    color: var(--text-muted);
    font-size: var(--fs-lg);
    cursor: pointer;
    padding: var(--space-sm);
    border-radius: var(--radius-full);
    line-height: 1;
    transition: background var(--transition-fast), color var(--transition-fast);
}

@media (hover: hover) {
    .modal__close:hover { background: var(--bg-hover); color: var(--text-primary); }
}

.modal__close:active { background: var(--border); }

.modal__body {
    padding: var(--space-ml);
    overflow-y: auto;
    flex: 1;
}

/* Il piede della modale è la parte in ombra della lastra: un velo scuro
   invece di un fondo, quindi le azioni ci stanno sopra come lastrine su un
   piano e la primaria è l'unica cosa accesa della finestra. */
.modal__footer {
    display: flex;
    justify-content: flex-end;
    gap: var(--space-sm);
    padding: var(--space-md) var(--space-ml);
    border-top: 1px solid var(--border);
    background: rgba(0, 0, 0, 0.12);
    flex-shrink: 0;
    flex-wrap: wrap;
}

.modal--wide { max-width: 780px; }
.modal--narrow { max-width: 400px; }

/* Barra con la sola ricerca: non deve avere l'aria di una toolbar piena. */
.toolbar--tight { margin-bottom: var(--space-sm); }

/* Campo di ricerca in una toolbar: prende lo spazio che c'è, senza allargare
   la riga oltre lo schermo. */
.input--search {
    flex: 1;
    min-width: 160px;
    max-width: 340px;
}

/* Testo di una domanda del gestionale (al posto di confirm/prompt del browser). */
.dialog__text { font-size: var(--fs-body); line-height: var(--lh-body); color: var(--text-primary); }

/* Campo obbligatorio lasciato vuoto. */
/* IL CAMPO SBAGLIATO NON DEVE SOMIGLIARE AL CAMPO ATTIVO. Da quando il fuoco
   accende un alone rosso (vedi .input:focus) il solo bordo rosso dell'errore
   diceva la stessa cosa del campo in cui si sta scrivendo. L'errore porta
   l'alone SEMPRE, anche senza il fuoco, e il fondo si tinge appena: così un
   modulo con due campi sbagliati li mostra entrambi a colpo d'occhio, non uno
   alla volta mentre li si attraversa col Tab. */
.input--error {
    border-color: var(--accent-primary);
    background: var(--accent-primary-soft);
    box-shadow: 0 0 0 3px var(--accent-primary-soft);
}

/* Riga cliccabile in un elenco dentro una modale: una prenotazione del tavolo,
   una comanda aperta. È un <button> per essere raggiungibile da tastiera, quindi
   va azzerato lo stile nativo. */
.row-btn {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-ms);
    width: 100%;
    padding: var(--space-sm) var(--space-ms);
    font-family: inherit;
    font-size: var(--fs-body);
    color: var(--text-primary);
    text-align: left;
    background: var(--bg-input);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    cursor: pointer;
    transition: border-color var(--transition-fast),
                background var(--transition-fast),
                transform var(--dur-instant) var(--ease-quick);
}

/* Queste righe sono scelte dentro una modale (che tavolo, che metodo di
   pagamento): il puntatore le sposta di due pixel verso il testo, come una
   voce di elenco che si fa avanti. Orizzontale e non verticale perché stanno
   incolonnate: alzarle le farebbe accavallare con la riga sopra. */
@media (hover: hover) {
    .row-btn:hover {
        background: var(--bg-hover);
        border-color: var(--border-light);
        transform: translateX(2px);
    }
}

/* L'anello del fuoco arriva dalla regola generale in style.css: qui c'era una
   copia con l'azzurro d'informazione scritto a mano, che ora è un token. */
.row-btn:active { background: var(--border); }
.row-btn__side { flex-shrink: 0; font-size: var(--fs-sm); color: var(--text-muted); }
.row-btn--warn { border-color: var(--accent-secondary); background: var(--accent-secondary-soft); }
.row-btn--warn .row-btn__side { color: var(--accent-secondary); font-weight: var(--fw-semi); }

/* Barretta proporzionale dentro una riga di elenco: gli orari di punta della
   cucina. Un grafico vero vorrebbe una libreria, e la regola del progetto è
   nessuna risorsa esterna. */
.bar {
    display: block;
    height: 8px;
    min-width: 2px;
    background: var(--accent-info-fill);
    border-radius: var(--radius-full);
}

/* Riga scelta in un elenco di scelta (Utils.scegli): deve saltare all'occhio,
   perché il pulsante di conferma agisce su quella e su nessun'altra. */
.row-btn--active {
    border-color: var(--accent-info);
    background: var(--accent-info-soft, var(--bg-hover));
    font-weight: var(--fw-semi);
}
.row-btn[disabled] { opacity: 0.45; cursor: not-allowed; }

/* Via secondaria dentro una modale: si vede se la cerchi, non attira il dito. */
.link-muted {
    display: inline-block;
    padding: 0;
    font-family: inherit;
    font-size: var(--fs-xs);
    color: var(--text-muted);
    background: none;
    border: 0;
    text-decoration: underline;
    text-underline-offset: 2px;
    cursor: pointer;
}

@media (hover: hover) {
    .link-muted:hover { color: var(--text-secondary); }
}

/* Righe impilate con poco respiro: elenchi corti dentro una modale. */
.stack-sm { display: flex; flex-direction: column; gap: var(--space-sm); }

/* Elenco chiave–valore (il dettaglio di una prenotazione). */
.kv { display: grid; grid-template-columns: auto 1fr; gap: var(--space-sm) var(--space-md); align-items: baseline; }
.kv__k { font-size: var(--fs-xs); color: var(--text-muted); white-space: nowrap; }
.kv__v { font-size: var(--fs-body); color: var(--text-primary); }

.divider {
    height: 1px;
    background: var(--border);
    margin: var(--space-md) 0;
    border: 0;
}

/* =============================================
   INDICATORE CONNESSIONE
   ============================================= */
.ws-status {
    display: inline-flex;
    align-items: center;
    gap: var(--space-sm);
    font-size: var(--fs-xs);
    font-weight: var(--fw-semi);
    color: var(--text-muted);
}

.ws-status__dot {
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: var(--text-muted);
    flex-shrink: 0;
}

.ws-status--connected .ws-status__dot { background: var(--campo-verde); }
.ws-status--connected { color: var(--accent-success); }
.ws-status--disconnected .ws-status__dot { background: var(--campo-rosso); animation: pulse-dot 1.4s infinite; }
.ws-status--disconnected { color: var(--accent-primary-text); }

@keyframes pulse-dot {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.3; }
}

/* =============================================
   NOTIFICHE
   ============================================= */
.toast-container {
    position: fixed;
    right: 16px;
    bottom: 16px;
    z-index: 400;
    display: flex;
    flex-direction: column;
    gap: var(--space-sm);
    max-width: 380px;
}

.toast {
    display: flex;
    align-items: flex-start;
    gap: var(--space-sm);
    padding: var(--space-ms);

    /* La notifica galleggia sopra il contenuto, quindi è di vetro come le
       barre (vedi la nota sui token --glass-*). Il velo COPERTO e non quello
       leggero: dentro c'è un messaggio da leggere in fretta mentre sotto
       scorre una tabella, e a questo serve anche `blur(20px)`, più alto della
       misura di serie — qui non deve trasparire nulla di leggibile. */
    background: var(--glass-bg-strong);
    -webkit-backdrop-filter: blur(20px) saturate(var(--glass-saturate));
    backdrop-filter: blur(20px) saturate(var(--glass-saturate));
    border: 2px solid var(--text-muted);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-lg), inset 0 1px 0 var(--glass-highlight);
    font-size: var(--fs-body);
    line-height: var(--lh-body);
    animation: toast-in var(--dur-slow) var(--ease-out);
}

/* La notifica entra da destra STRINGENDOSI: 24 px di percorso invece di 16, e
   una scala che parte dal 96%. Con la curva degli arrivi frena entrando, e il
   movimento arriva all'occhio anche mentre si sta guardando altro — che è il
   punto, perché una notifica che nessuno vede non serve a niente. */
@keyframes toast-in {
    from { transform: translateX(32px) scale(0.95); opacity: 0; }
    to { transform: translateX(0) scale(1); opacity: 1; }
}

/* L'USCITA È PIÙ VELOCE DELL'INGRESSO, sempre: entrando la notifica chiede
   attenzione, uscendo la restituisce, e una cosa che se ne va con calma
   trattiene lo sguardo su un messaggio già letto. Prima l'uscita durava di
   più dell'entrata (0,25 contro 0,20). */
.toast--exit { animation: toast-out var(--dur-exit) var(--ease-quick) forwards; }

@keyframes toast-out {
    to { transform: translateX(24px) scale(0.98); opacity: 0; }
}

/* Il tipo di notifica sta sul FILO PERIMETRALE, non su una striscia a lato:
   vedi la nota sul quarto canale in .table-tile--occupied. */
.toast--success { border-color: var(--accent-success-text); }
.toast--error { border-color: var(--accent-primary-text); }
.toast--warning { border-color: var(--accent-secondary-text); }
.toast--info { border-color: var(--accent-info-text); }

.toast__icon { flex-shrink: 0; }

.toast__close {
    margin-left: auto;
    border: 0;
    background: transparent;
    color: var(--text-muted);
    cursor: pointer;
    font-size: var(--fs-body);
    padding: 0 var(--space-2xs);
    line-height: 1;
}

@media (hover: hover) {
    .toast__close:hover { color: var(--text-primary); }
}

/* Su schermo touch la ✕ del toast era 15×14 px: impossibile centrarla col dito,
   e i toast si accavallano sopra i controlli in fondo mentre si lavora. */
@media (max-width: 620px) {
    .toast__close {
        min-width: 36px;
        min-height: 36px;
        font-size: var(--fs-lg);
        padding: 0;
    }
}

/* =============================================
   UTILITÀ
   ============================================= */
.text-muted { color: var(--text-muted); }
.text-secondary { color: var(--text-secondary); }
.text-accent { color: var(--accent-primary-text); }
.text-success { color: var(--accent-success); }
.text-warning { color: var(--accent-secondary); }
.text-info { color: var(--accent-info); }
.text-right { text-align: right; }
.text-center { text-align: center; }
.text-sm { font-size: var(--fs-sm); }
.text-xs { font-size: var(--fs-xs); }
.mono { font-variant-numeric: tabular-nums; }
.strong { font-weight: var(--fw-bold); }
.nowrap { white-space: nowrap; }
.mt-0 { margin-top: 0; }
.mt-1 { margin-top: var(--space-sm); }
.mt-2 { margin-top: var(--space-md); }
/* Spinge a destra ciò che segue: nei footer dei modali separa l'azione
   distruttiva (Elimina, Disattiva) da Annulla / Salva. */
.mr-auto { margin-right: auto; }
.mb-0 { margin-bottom: 0; }
.mb-1 { margin-bottom: var(--space-sm); }
.mb-2 { margin-bottom: var(--space-md); }
.flex { display: flex; }
.flex-col { flex-direction: column; }
.flex-wrap { flex-wrap: wrap; }
.items-center { align-items: center; }
.justify-between { justify-content: space-between; }
.gap-1 { gap: var(--space-sm); }
.gap-2 { gap: var(--space-md); }
.flex-1 { flex: 1; }
.hidden { display: none !important; }

.spinner {
    width: 15px;
    height: 15px;
    border: 2px solid var(--border-light);
    border-top-color: var(--accent-primary);
    border-radius: 50%;
    animation: spin 0.7s linear infinite;
    display: inline-block;
}

@keyframes spin { to { transform: rotate(360deg); } }

/* =============================================
   RESPONSIVE — sidebar a icone, poi a cassetto
   ============================================= */
@media (max-width: 1100px) {
    :root { --sidebar-w: 62px; }
    .sidebar__title,
    .sidebar__subtitle,
    .nav-item__label,
    .sidebar__user-name,
    .sidebar__user-role,
    .sidebar__group { display: none; }
    .nav-item { justify-content: center; padding: var(--space-ms) 0; }
    /* Sulla sidebar a sole icone si azzera l'imbottitura ORIZZONTALE, così il
       logo si centra nei 62 px; quella verticale resta (vedi la nota su
       .sidebar__brand), o il logo tornerebbe a toccare la riga sotto. */
    .sidebar__brand { justify-content: center; padding: var(--space-sm) 0; }
    .sidebar__user { justify-content: center; padding: var(--space-xs) 0; }
    .sidebar__actions { flex-direction: column; }
}

/* ── Telefono: la navigazione va in fondo ──
   Prima la sidebar diventava una striscia in ALTO e, con le etichette già
   nascoste dalla regola dei 1100 px, erano nove icone indistinguibili nel
   punto più lontano dal pollice. Qui la stessa sidebar diventa una barra
   inferiore: nessun pannello a scomparsa da aprire, nessun markup nuovo,
   solo riga 2 della griglia invece della riga 1.

   Il guscio torna alto quanto lo schermo (come sul desktop) così la barra non
   scorre via col contenuto: `dvh` perché su iOS la barra del browser mangia
   una parte di `vh` e la navigazione finirebbe sotto il bordo. */
@media (max-width: 720px) {
    /* Sul telefono la barra di navigazione sta in fondo e deve toccare il
       bordo dello schermo: una barra col piano intorno lascerebbe una striscia
       morta sotto il pollice, che e' l'unico posto in cui non si deve
       sprecare spazio. Il piano intorno alle lastre e' un lusso del desktop. */
    .app {
        grid-template-columns: 1fr;
        grid-template-rows: minmax(0, 1fr) auto;
        height: 100vh;
        height: 100dvh;
        padding: 0;
        gap: 0;
    }

    .sidebar,
    .topbar,
    .page { border-radius: 0; }

    .main { grid-column: 1; grid-row: 1; }

    .sidebar {
        grid-column: 1;
        grid-row: 2;
        flex-direction: row;
        align-items: stretch;
        border-right: 0;
        border-top: 1px solid var(--border);
        height: auto;
    }

    .sidebar__brand { display: none; }

    .sidebar__nav {
        display: flex;
        /* Le voci si dividono la larghezza: niente scorrimento laterale sulla
           navigazione principale. Le sezioni che non stanno in cinque posti
           passano dal foglio "Più" (vedi .nav-item--more). */
        overflow: visible;
        padding: var(--space-xs);
        gap: var(--space-2xs);
        flex: 1;
    }

    .sidebar__nav .nav-item { flex: 1 1 0; }

    /* Le sezioni di configurazione escono dalla barra ed entrano nel foglio */
    .nav-item--secondary { display: none; }
    .nav-item--more { display: flex; }

    .sidebar__nav::-webkit-scrollbar { display: none; }

    /* L'etichetta torna sotto l'icona: in fondo allo schermo il posto in
       verticale costa poco, e un'icona sola non dice che sezione apre. */
    .nav-item {
        position: relative;
        flex-direction: column;
        justify-content: center;
        gap: var(--space-2xs);
        width: auto;
        min-width: 62px;
        min-height: 48px;
        padding: var(--space-xs) var(--space-sm);
        margin-bottom: 0;
        text-align: center;
    }

    /* Era 0,62 rem, cioè 9,9 px: sotto la soglia di leggibilità di un testo
       funzionale, e queste NON sono didascalie — sono le etichette delle nove
       sezioni del gestionale, l'unica cosa che dice cosa apre ogni icona.
       Su uno schermo da 375 px le voci hanno ~75 px a testa: a 11 px le
       etichette lunghe ("Prenotazioni") restano dentro i 76 px del tetto, e
       quelle che non entrassero le taglia già la regola dei puntini. */
    .nav-item__label {
        display: block;
        flex: 0 0 auto;
        max-width: 76px;
        font-size: var(--fs-micro);
        font-weight: var(--fw-semi);
        line-height: var(--lh-flat);
    }

    /* La stanghetta della sezione aperta gira di 90°: in una barra in fondo
       allo schermo il segno "sei qui" va sul bordo verso il contenuto, cioè in
       alto, e cresce in larghezza invece che in altezza. Vedi la nota su
       .nav-item::before. */
    .nav-item::before {
        left: 24%;
        right: 24%;
        top: 0;
        bottom: auto;
        width: auto;
        height: 2px;
        border-radius: 0 0 var(--radius-sm) var(--radius-sm);
        transform: scaleX(0);
    }

    .nav-item--active::before { transform: scaleX(1); }
    .nav-item--active .nav-item__icon { transform: translateY(-1px); }

    /* In colonna il contatore finiva sotto l'etichetta e allungava la barra */
    .nav-item__badge { position: absolute; top: 2px; right: 4px; }

    /* Le informazioni si nascondono, i pulsanti no: l'avatar è informazione,
       tema / chiamata cameriere / uscita sono azioni e restano toccabili. */
    .sidebar__user { display: none; }

    /* Tema, chiamata cameriere e uscita si spostano nel foglio "Più": nella
       barra rubavano 141px ai 375 disponibili e le voci di menu finivano a
       scorrere di lato. Restano a un tocco di distanza, non a zero. */
    .sidebar__footer { display: none; }

    .page { padding: var(--space-md); }
    .topbar { padding: 0 var(--space-md); }
}

/* ── Correzioni dopo la prova a schermo ── */

/* Con 11 categorie il selettore sfondava la pagina */
/* ── IL SELETTORE A SEGMENTI VA A CAPO, NON SCORRE ──
   Era `overflow-x: auto`: dentro una barra flex il gruppo si stringeva sotto la
   propria misura e la seconda voce restava tagliata a metà parola — «Giorn»,
   con il bordo del gruppo esattamente sul bordo dello schermo e nessun segno
   che ci fosse altro da scorrere. Verificato a 375px: «Calendario | Giorno»
   sfondava di 16px in Sala, 10 in Menu, 60 in Cassa e conti.
   Ora il gruppo prende la riga intera e le voci si dividono lo spazio; se non
   ci stanno — Cassa e conti ne ha sei — vanno a capo su due righe, che si legge
   e si tocca, mentre una striscia che scorre di nascosto no. */
.segmented {
    flex: 1 1 100%;
    max-width: 100%;
    display: flex;
    flex-wrap: wrap;
}

.segmented__item {
    flex: 1 1 auto;
    /* Il testo della voce non si taglia: se serve, il gruppo va a capo. */
    min-width: max-content;
    text-align: center;
}

/* Un tavolo libero non ha righe da mostrare: non deve restare mezzo vuoto */
.table-tile { min-height: 0; }
.table-tile__lines:empty { display: none; }

/* Le celle del calendario non devono allargarsi con nomi lunghi */
.calendar__chip { max-width: 100%; }

/* I nomi delle zone arrivano dai dati in minuscolo ("sala", "dehors"):
   la maiuscola è una scelta di resa, non un dato da riscrivere nel database. */
.floor-zone__name,
.zone-block__name { text-transform: capitalize; }
.waiter__zone-filter .tab-bar__item { text-transform: capitalize; }

/* =============================================
   AVVIO SENZA SFARFALLIO
   ============================================= */

/* L'icona del tema la disegna il CSS: scriverla da JavaScript a
   DOMContentLoaded la faceva cambiare a pagina già visibile.

   È una MASCHERA e non un `content:`, perché in un content un SVG non ci si
   può mettere: la forma dell'icona ritaglia un fondo `currentColor`, così
   segue il colore del testo. L'emoji non lo faceva, e restava gialla anche
   sul tema chiaro. */
.theme-toggle { display: inline-block; width: 1.15em; height: 1.15em; }
.theme-toggle::before {
    content: '';
    display: block;
    width: 100%;
    height: 100%;
    background-color: currentColor;
    -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx=%2212%22 cy=%2212%22 r=%224%22 /%3E %3Cpath d=%22M12 2v2%22 /%3E %3Cpath d=%22M12 20v2%22 /%3E %3Cpath d=%22m4.93 4.93 1.41 1.41%22 /%3E %3Cpath d=%22m17.66 17.66 1.41 1.41%22 /%3E %3Cpath d=%22M2 12h2%22 /%3E %3Cpath d=%22M20 12h2%22 /%3E %3Cpath d=%22m6.34 17.66-1.41 1.41%22 /%3E %3Cpath d=%22m19.07 4.93-1.41 1.41%22 /%3E%3C/svg%3E") center / contain no-repeat;
    mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx=%2212%22 cy=%2212%22 r=%224%22 /%3E %3Cpath d=%22M12 2v2%22 /%3E %3Cpath d=%22M12 20v2%22 /%3E %3Cpath d=%22m4.93 4.93 1.41 1.41%22 /%3E %3Cpath d=%22m17.66 17.66 1.41 1.41%22 /%3E %3Cpath d=%22M2 12h2%22 /%3E %3Cpath d=%22M20 12h2%22 /%3E %3Cpath d=%22m6.34 17.66-1.41 1.41%22 /%3E %3Cpath d=%22m19.07 4.93-1.41 1.41%22 /%3E%3C/svg%3E") center / contain no-repeat;
}
[data-theme="light"] .theme-toggle::before {
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d=%22M20.985 12.486a9 9 0 1 1-9.473-9.472c.405-.022.617.46.402.803a6 6 0 0 0 8.268 8.268c.344-.215.825-.004.803.401%22 /%3E%3C/svg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d=%22M20.985 12.486a9 9 0 1 1-9.473-9.472c.405-.022.617.46.402.803a6 6 0 0 0 8.268 8.268c.344-.215.825-.004.803.401%22 /%3E%3C/svg%3E");
}

/* La comparsa della barra di scorrimento spostava tutto il contenuto
   di qualche pixel quando i dati arrivavano. */
.page { scrollbar-gutter: stable; }

/* Le aree che si popolano via richiesta hanno un'altezza minima: senza,
   il contenuto sotto saltava su e giù mentre i dati arrivavano. */
.grid--stats:empty { min-height: 74px; }

/* Segnaposto durante il caricamento: meglio di un riquadro vuoto che
   d'improvviso si riempie. */
/* ── IL SEGNAPOSTO DEL CARICAMENTO ──
   Era una scritta grigia ferma in mezzo a un riquadro vuoto, e ferma è il
   problema: una tabella che non arriva perché la rete del locale è caduta
   dipinge esattamente la stessa cosa di una tabella che sta arrivando. La
   striscia di luce che attraversa il riquadro ogni secondo e mezzo dice che
   il gestionale sta ancora lavorando.

   È una `background-position` che scorre, non un elemento che si muove: non
   c'è nulla da ridisegnare sotto, la compone la GPU, e gira sui tablet vecchi
   della sala come su un computer nuovo. */
.skeleton {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-sm);
    padding: var(--space-xl) var(--space-ml);
    color: var(--text-muted);
    font-size: var(--fs-body);
    background-image: linear-gradient(100deg,
        transparent 24%,
        var(--bg-hover) 42%,
        var(--bg-hover) 52%,
        transparent 70%);
    background-size: 220% 100%;
    background-repeat: no-repeat;
    animation: shimmer 1.5s linear infinite;
    border-radius: var(--radius-lg);
}

/* La pagina resta invisibile fino al primo disegno dei dati: evita di
   mostrare il guscio vuoto per poi riempirlo di colpo. Se JavaScript
   non parte, dopo 1,2s si mostra comunque (regola sotto). */
.app { opacity: 1; }

.app[data-loading="true"] .page { visibility: hidden; }

@keyframes app-ready { from { opacity: 0; } to { opacity: 1; } }
.app[data-loading="false"] .page { animation: app-ready 0.14s ease; }

/* Icona del pulsante suoni: disegnata dal CSS, come quella del tema.
   Lo stato lo scrive js/theme.js prima del primo disegno. */
#sound-toggle { display: inline-flex; align-items: center; justify-content: center; }
#sound-toggle::before {
    content: '';
    display: block;
    width: 1.15em;
    height: 1.15em;
    background-color: currentColor;
    -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d=%22M10.268 21a2 2 0 0 0 3.464 0%22 /%3E %3Cpath d=%22M3.262 15.326A1 1 0 0 0 4 17h16a1 1 0 0 0 .74-1.673C19.41 13.956 18 12.499 18 8A6 6 0 0 0 6 8c0 4.499-1.411 5.956-2.738 7.326%22 /%3E%3C/svg%3E") center / contain no-repeat;
    mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d=%22M10.268 21a2 2 0 0 0 3.464 0%22 /%3E %3Cpath d=%22M3.262 15.326A1 1 0 0 0 4 17h16a1 1 0 0 0 .74-1.673C19.41 13.956 18 12.499 18 8A6 6 0 0 0 6 8c0 4.499-1.411 5.956-2.738 7.326%22 /%3E%3C/svg%3E") center / contain no-repeat;
}
[data-sound="off"] #sound-toggle::before {
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d=%22M10.268 21a2 2 0 0 0 3.464 0%22 /%3E %3Cpath d=%22M17 17H4a1 1 0 0 1-.74-1.673C4.59 13.956 6 12.499 6 8a6 6 0 0 1 .258-1.742%22 /%3E %3Cpath d=%22m2 2 20 20%22 /%3E %3Cpath d=%22M8.668 3.01A6 6 0 0 1 18 8c0 2.687.77 4.653 1.707 6.05%22 /%3E%3C/svg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d=%22M10.268 21a2 2 0 0 0 3.464 0%22 /%3E %3Cpath d=%22M17 17H4a1 1 0 0 1-.74-1.673C4.59 13.956 6 12.499 6 8a6 6 0 0 1 .258-1.742%22 /%3E %3Cpath d=%22m2 2 20 20%22 /%3E %3Cpath d=%22M8.668 3.01A6 6 0 0 1 18 8c0 2.687.77 4.653 1.707 6.05%22 /%3E%3C/svg%3E");
}

/* =============================================
   RESPONSIVE — TELEFONO
   =============================================
   Sta in fondo al file perché deve poter correggere anche le regole della
   sezione "Correzioni dopo la prova a schermo": in CSS, a pari specificità,
   vince l'ultima. 620 px è la soglia già usata dal resto del progetto
   (style.css, waiter.css, kitchen.css) per "questo è un telefono". */
@media (max-width: 620px) {

    /* ── Modali a foglio ──
       Un modale centrato con 20 px di margine per lato lascia troppo poco
       spazio ai campi, e quelli alti (scheda dipendente, turno, prodotto del
       menu) uscivano dallo schermo portandosi via il footer: Salva e Annulla
       diventavano irraggiungibili. Il modale sale dal basso, il CORPO scorre,
       header e footer restano fermi — e il footer, in fondo allo schermo, è
       anche il punto più comodo per il pollice. */
    /* `max-height: 100dvh` sul velo: un elemento `fixed` con `inset: 0` su
       mobile può risultare più alto del visibile, e il foglio agganciato in
       basso finirebbe sotto la barra del browser. */
    .modal-overlay {
        padding: 0;
        align-items: flex-end;
        max-height: 100dvh;
    }

    .modal {
        max-width: none;
        max-height: 92vh;
        max-height: 92dvh;
        border-radius: var(--radius-xl) var(--radius-xl) 0 0;
        border-bottom: 0;

        /* Sul telefono la modale è un FOGLIO agganciato in basso, e l'ingresso
           del desktop non va: una riduzione di scala sposterebbe anche i bordi
           laterali, che qui invece restano fissi al bordo dello schermo.
           Il foglio fa la sua strada — sale da fondo schermo — e questa è la
           versione mobile della stessa firma: la cosa arriva da dove la si è
           chiamata, cioè dal pollice. Nessuna opacità nel percorso: un foglio
           di vetro che entra semitrasparente lascia leggere due schermate
           insieme a metà corsa. */
        animation: foglio-sale var(--dur-modale) var(--ease-luce);
    }

    .modal__header { padding: var(--space-ms) var(--space-md); }
    .modal__body { padding: var(--space-md); }
    .modal__footer { padding: var(--space-ms) var(--space-md); }

    /* ── Barra superiore ──
       Il sottotitolo ("Stato dei tavoli in tempo reale") andava a capo dentro
       una barra alta 56 px e sbordava sul contenuto. Resta il titolo, che dice
       in che sezione si è, tagliato con i puntini se non entra. */
    .topbar { gap: var(--space-ms); }
    .topbar > div:first-child { min-width: 0; }
    .topbar__subtitle { display: none; }

    /* Discendente di `.topbar` e non `.topbar__title` da sola: la stessa
       classe è usata anche come etichetta di periodo dentro una barra
       strumenti, dove `overflow: hidden` la farebbe collassare a zero. */
    .topbar .topbar__title {
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
    }

    .topbar__meta { gap: var(--space-sm); flex-shrink: 0; }

    /* ── Riquadri statistica ──
       Due colonne, non una: sono numeri corti e una colonna sola renderebbe
       la lettura dell'incasso una lunga scorsa verso il basso. */
    .grid--stats {
        grid-template-columns: repeat(2, minmax(0, 1fr));
        gap: var(--space-ms);
    }

    .stat { padding: var(--space-ms); }
    .stat__value { font-size: var(--fs-xl); }
    .stat__label { letter-spacing: 0.05em; }

    /* Un numero che non entra va a capo, non viene tagliato */
    .stat__value,
    .stat__hint { overflow-wrap: anywhere; }

    /* ── Calendario prenotazioni ──
       Sette colonne su 330 px danno 45 px per giorno: ora e nome del cliente
       non ci stanno in nessun modo. Ogni prenotazione resta come una
       barretta colorata per fascia: il calendario dice "quanto è pieno" e i
       dettagli stanno nell'elenco della giornata, che si apre toccando il
       giorno. */
    .calendar__cell { min-height: 62px; padding: var(--space-xs); }
    /* Erano 0,6 rem, cioe' 9,6 px: sotto la soglia di leggibilita' di un
       testo funzionale, ed e' lo stesso difetto corretto sulle etichette del
       menu. Le intestazioni dei giorni non sono didascalie — dicono in che
       colonna si sta. A 390 px le sette colonne hanno ~51 px a testa e "LUN"
       a 11 px ne occupa 22: il valore prudente non serviva. */
    .calendar__dayname { padding: var(--space-sm) var(--space-2xs); font-size: var(--fs-micro); letter-spacing: 0.03em; }
    .calendar__daynum { font-size: var(--fs-xs); }

    .calendar__chip {
        height: 4px;
        padding: 0;
        overflow: hidden;
        /* Su telefono la pastiglia diventa una barretta da 4px: il filo
           perimetrale non ci sta e torna la campitura piena, che a quella
           misura e' il solo canale possibile. */
        border: 0;
        background: var(--accent-info-fill);
    }

    /* IL TESTO DENTRO LA BARRETTA VA NASCOSTO, non solo ritagliato.
       Con `height: 4px` e `overflow: hidden` il nome del cliente restava
       disegnato: se ne vedevano i primi quattro pixel, cioè una fila di
       scarabocchi blu dentro ogni barretta. Rilevato guardando la schermata a
       375px. I nomi stanno nell'elenco della giornata, che si apre toccando il
       giorno: la barretta dice solo «qui c'è una prenotazione, di questa
       fascia».
       `font-size: 0` sul contenitore e non `display: none` sui figli: l'ora e il
       nome sono un NODO DI TESTO diretto della pastiglia — nascondere i figli
       toglieva solo l'icona e lasciava la scritta. Il testo resta nel DOM, dove
       lo legge chi usa un lettore di schermo. */
    .calendar__chip { font-size: 0; }
    .calendar__chip > * { display: none; }

    /* "+1 altre" andava a capo in una colonna da 39px, prendendosi due delle tre
       righe utili della cella. Resta il numero; la parola vive nel DOM per chi
       ascolta la pagina invece di guardarla. */
    .calendar__more-word {
        position: absolute;
        width: 1px;
        height: 1px;
        overflow: hidden;
        clip-path: inset(50%);
        white-space: nowrap;
    }

    /* E NON SI TOCCA. La barretta resta un <button> che apre il dettaglio della
       prenotazione: un bersaglio alto 4px e largo 31, che nessun dito centra —
       e chi provasse a toccare il giorno finirebbe per aprire una prenotazione a
       caso. Su telefono il tocco passa attraverso e arriva alla CELLA, che apre
       l'elenco della giornata: da lì ogni riga è un bersaglio vero. */
    .calendar__chip { pointer-events: none; }

    .calendar__chip--pranzo { background: var(--accent-secondary-fill); }
    .calendar__chip--cena { background: var(--accent-info-fill); }
    /* Erano 0,58 rem, 9,3 px, su un elemento che si TOCCA per aprire il
       resto della giornata. Vedi la nota su .calendar__dayname. */
    .calendar__more { font-size: var(--fs-micro); }

    /* La barra strumenti va già a capo da sé; qui si stringe solo di quel
       tanto che serve a far entrare un controllo in più per riga.
       (I separatori verticali li nasconde admin.css, già da 860 px.) */
    .toolbar { gap: var(--space-sm); margin-bottom: var(--space-ms); }

    /* Righe ordine e totali: la colonna della quantità non serve larga */
    .order-line { grid-template-columns: 28px 1fr auto auto auto; gap: var(--space-sm); }
}

/* =============================================
   TESTO SOPRA UNA CAMPITURA — la regola che chiude il mondo
   =============================================
   Difetto trovato guardando il tema chiaro: su un tavolo occupato le righe
   «2 coperti · Cameriere» e «aperto da 353 min» stavano a 2,3:1 sul rosso,
   cioè illeggibili, e la scritta «Occupato» era rosso su rosso.

   La causa non era il colore ma il MECCANISMO: le regole di prima dicevano
   `color: inherit` sulle singole righe, e `inherit` risale al GENITORE — che
   è `.table-tile__lines`, un contenitore grigio — non alla piastra colorata.
   Ereditare da un grigio dà un grigio.

   Qui la piastra impone il proprio colore a OGNI discendente, e la classe è
   ripetuta due volte nel selettore per una ragione precisa: serve a battere
   le varianti di riga (`--alert`, `--warn`, `--ok`, `--info`) che portano una
   tinta propria a pari specificità. Su una campitura quelle tinte non
   servono più — il colore del campo dice già lo stato, e una seconda tinta
   sopra non aggiunge informazione, la toglie.

   Vale per il quadro della gestione e per la mappa della sala: sono la stessa
   piastra in due ruoli. */
.table-tile--occupied.table-tile--occupied *,
.table-tile--waiting_bill.table-tile--waiting_bill *,
.table-tile--reserved.table-tile--reserved *,
.table-card--occupied.table-card--occupied *,
.table-card--waiting_bill.table-card--waiting_bill *,
.table-card--reserved.table-card--reserved * {
    color: inherit;
}

/* Le righe secondarie si tengono indietro con l'OPACITÀ e non con un grigio:
   su una campitura satura un grigio perde il contrasto, un nero all'85% no. */
.table-tile--occupied .table-tile__lines,
.table-tile--waiting_bill .table-tile__lines,
.table-tile--reserved .table-tile__lines,
.table-card--occupied .table-card__lines,
.table-card--waiting_bill .table-card__lines,
.table-card--reserved .table-card__lines { opacity: 0.88; }

/* La pastiglia di stato dentro una piastra della stessa tinta non può essere
   un'altra campitura: diventa scavata, cioè un'incisione sul campo. */
.table-tile--occupied .table-tile__state,
.table-tile--waiting_bill .table-tile__state,
.table-tile--reserved .table-tile__state,
.table-tile--occupied .badge,
.table-tile--waiting_bill .badge,
.table-tile--reserved .badge,
.table-card--occupied .badge,
.table-card--waiting_bill .badge,
.table-card--reserved .badge {
    background: var(--scavo);
    border-color: var(--bordo-campo);
    box-shadow: none;
}

/* =============================================
   LO SCORRIMENTO CHE SI VEDE
   =============================================
   Difetto trovato in cattura a 390 px: la riga dei filtri era tagliata a metà
   parola («Prenotat») senza nessun segno che scorresse. Uno scroller
   legittimo con l'affordance mancante è peggio di un troncamento: sembra un
   difetto di impaginazione, quindi nessuno prova a trascinare.

   La sfumatura sul bordo destro dice «continua». È una maschera e non una
   sovrapposizione colorata: così funziona sopra qualunque fondo — piastra,
   substrato, campitura — senza dover conoscere il colore che ha sotto. */
@media (max-width: 620px) {
    .segmented,
    .tab-bar,
    .steps {
        -webkit-mask-image: linear-gradient(to right, #000 0, #000 calc(100% - 24px), transparent 100%);
        mask-image: linear-gradient(to right, #000 0, #000 calc(100% - 24px), transparent 100%);
    }
}

/* ── L'AZIONE SOPRA UNA CAMPITURA COMMUTA AL VALORE DELLA PIASTRA ──
   Misurato in verdetto: sul tavolo prenotato il filo blu dell'azione neutra
   finiva sul fondo blu dello stato — #6e99c7 su #1d5fa8 = 2,16:1, accanto ad
   «Arrivata» che stava a 9,24:1. Sull'unico tavolo che va fatto sedere,
   l'azione abilitata leggeva come disabilitata.

   La causa era l'ORDINE, non il colore: il filo blu è definito dopo la regola
   che scava i pulsanti sulle campiture, e a pari specificità vince l'ultima.
   Qui la classe è ripetuta due volte (0,3,0) e la regola sta in coda al file,
   così la campitura vince sempre su chi non sa di starci sopra.

   Sopra una campitura l'azione non ripete l'inchiostro dello stato: si scava
   nel campo e prende il colore che il campo già impone al testo. */
.table-tile--occupied.table-tile--occupied .btn,
.table-tile--waiting_bill.table-tile--waiting_bill .btn,
.table-tile--reserved.table-tile--reserved .btn,
.table-card--occupied.table-card--occupied .btn,
.table-card--waiting_bill.table-card--waiting_bill .btn,
.table-card--reserved.table-card--reserved .btn {
    background: var(--scavo);
    border: 2px solid var(--bordo-campo);
    color: inherit;
    box-shadow: none;
}
