/* ===========================================================================
   KAILEX — foglio di stile condiviso
   ---------------------------------------------------------------------------
   Un solo sistema per tutta la piattaforma. Tipografia, spaziature, griglia e
   componenti sono UNICI e mai duplicati per tenant: un file theme-<tenant>.css,
   caricato subito dopo questo, sovrascrive esclusivamente le variabili del
   blocco "PER TENANT" più sotto.

   La verifica che la separazione tenga: se aprendo theme-studioa.css trovi
   una regola di layout, la separazione si è rotta. Lì dentro devono esserci
   solo valori, mai selettori di componenti.

   DESIGN SYSTEM KAILEX — da dove vengono queste scelte
   ----------------------------------------------------
   Colori, caratteri, raggi, ombre e movimento sono quelli del design system
   KaiLex (token `--kx-*` e alias semantici, componenti Button, Input, Badge,
   Card, Tabs): neutri freddi campionati dalla tavola del logo, un solo
   accento teal per la piattaforma, Inter Tight per titoli e interfaccia,
   forme morbide (pulsanti a pillola, schede a 16px). I blocchi qui sotto non
   ridefiniscono il sistema: ne traducono i token nei nomi che le regole di
   questo file già usano (--c-text, --accent, --radius...), così ogni
   componente segue il design system senza essere riscritto.

   Gli studi restano per-tenant come i sotto-brand del design system: cambiano
   l'accento e il logo, non il resto.

   Cosa NON viene dal sito vetrina, di proposito: l'impaginato "a vetrina"
   (video a tutto schermo, blocchi alternati, animazioni allo scroll). Uno
   strumento di lavoro deve far trovare una pratica in tre secondi: la densità
   informativa è quella di un'applicazione gestionale, non di una homepage.
   =========================================================================== */

/* ---------------------------------------------------------------------------
   FONT — serviti da NOI, non da Google Fonts
   ---------------------------------------------------------------------------
   Il design system li carica da fonts.googleapis.com; qui no. Da Google
   l'indirizzo IP di chiunque aprisse il portale finirebbe a un terzo
   extra-UE, senza base giuridica (LG München I, 20.01.2022, 3 O 17493/20). In
   un prodotto che contiene il modulo con cui uno studio dimostra la propria
   conformità privacy, sarebbe una contraddizione. Il browser non contatta
   nessuno oltre a noi, e la CSP lo garantisce: `font-src 'self'`, `style-src`
   senza eccezioni (IntestazioniSicurezza).

   KaiLex Sans (1.000) è il carattere del marchio, fornito con il design
   system in TTF: qui è lo stesso file in WOFF2, un contenitore compresso
   senza perdite — stessi glifi, stessa spaziatura. Due pesi soli, quelli che
   si usano: il 700 dei titoli e il 400 per il testo di display non in
   grassetto.

   Gli altri file sono quelli che Google serve al design system, SCARICATI UNA
   VOLTA e non modificati (Inter Tight 3.004, IBM Plex Mono 2.3): stesso
   disegno, stessa resa. Non ritoccarli — né risottoinsiemarli: IBM Plex ha un
   "Reserved Font Name", e una versione modificata non potrebbe più chiamarsi
   Plex. Licenza SIL OFL 1.1, distribuita accanto ai file
   (static/fonts/OFL-*.txt), come la licenza stessa richiede.

   Scelte, una per riga:
   - INTER TIGHT È VARIABILE: un file per sottoinsieme copre tutti i pesi, e
     Google serve lo STESSO file per 300…700; `font-weight: 300 700`
     riproduce quell'intervallo. IBM Plex Mono non lo è: un file per peso,
     400 e 500 come nel design system.
   - DUE SOTTOINSIEMI, `latin` e `latin-ext`, con gli stessi `unicode-range`
     di Google: il secondo si scarica SOLO se in pagina c'è un carattere
     che il primo non ha (un cliente di nome Łukasz, un ente di Brno). Il
     cirillico, il greco e il vietnamita non sono inclusi: un testo in quegli
     alfabeti ripiega sul font di riserva dello stack, che è esattamente il
     motivo per cui le riserve ci sono.
   - Instrument Serif, il terzo carattere del design system, non c'è: lo usa
     solo come parola d'accento nei titoli di vetrina, e nessuna pagina qui la
     ha. Una @font-face senza testo che la usa sarebbe un file morto.
   - `font-display: swap`: il testo compare subito nel font di riserva e
     cambia quando il file è arrivato, invece di restare invisibile.
   - Il numero di versione sta NEL NOME del file: queste url sono dentro il
     CSS, dove `asset()` non arriva (stesso limite dei loghi, CLAUDE.md →
     "Cache dei file statici"). Un aggiornamento del font = un nome nuovo.
   --------------------------------------------------------------------------- */
/* KaiLex Sans: un file intero per peso, niente sottoinsiemi (il design
   system lo distribuisce così). */
@font-face {
  font-family: 'KaiLex Sans';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('/fonts/kailex-sans-1.000-bold.woff2') format('woff2');
}
@font-face {
  font-family: 'KaiLex Sans';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/fonts/kailex-sans-1.000-regular.woff2') format('woff2');
}
@font-face {
  font-family: 'Inter Tight';
  font-style: normal;
  font-weight: 300 700;
  font-display: swap;
  src: url('/fonts/inter-tight-3.004-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Inter Tight';
  font-style: normal;
  font-weight: 300 700;
  font-display: swap;
  src: url('/fonts/inter-tight-3.004-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/fonts/ibm-plex-mono-2.3-400-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/fonts/ibm-plex-mono-2.3-400-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('/fonts/ibm-plex-mono-2.3-500-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('/fonts/ibm-plex-mono-2.3-500-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

:root {
  /* --- Design system: primitivi ------------------------------------------
     I valori del design system KaiLex, con i suoi nomi. Le regole di questo
     file NON li usano direttamente: passano dagli alias semantici qui sotto
     (--c-*, --accent...), che sono ciò che un tema di studio può cambiare. */
  /* Neutri, campionati dalla tavola del logo. */
  --kx-white: #FFFFFF;
  --kx-paper: #F4F7F8;
  --kx-mist: #E9EDEF;
  --kx-neutral-100: #DDE2E6;
  --kx-neutral-200: #C8CFD5;
  --kx-neutral-300: #A9B4C2;
  --kx-neutral-500: #6B7380;
  --kx-neutral-600: #555B66;
  --kx-neutral-700: #3A3F47;
  --kx-neutral-800: #1F2226;
  --kx-neutral-900: #141517;
  --kx-ink: #0A0A0A;
  /* Teal: l'accento del marchio madre. */
  --kx-teal-50: #E8F6F4;
  --kx-teal-100: #CDEDE9;
  --kx-teal-300: #6CCBC0;
  --kx-teal-500: #1FA89B;
  --kx-teal-600: #178A7F;
  --kx-teal-700: #116D64;
  --kx-teal-900: #0A3D38;
  /* Stato. */
  --kx-success-500: #2E9E6A;
  --kx-success-50: #E7F5EE;
  --kx-warning-500: #C98A2B;
  --kx-warning-50: #FAF1E2;
  --kx-danger-500: #C4413A;
  --kx-danger-50: #FAE9E8;
  --kx-info-500: #4C6FCF;
  --kx-info-50: #EBF0FB;

  /* --- Tipografia ------------------------------------------------------- */
  /* Due voci, come nel design system: KaiLex Sans — il carattere arrotondato
     del marchio — per i titoli (display e H1–H3, in grassetto), Inter Tight
     per l'interfaccia e il testo, dove conta la leggibilità. */
  --font-ui: "Inter Tight", "Inter", system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-display: "KaiLex Sans", var(--font-ui);
  --font-mono: "IBM Plex Mono", ui-monospace, Menlo, monospace;

  --text-xs: 0.75rem;
  --text-sm: 0.8125rem;
  --text-base: 0.9375rem;
  --text-md: 1.0625rem;
  --text-lg: 1.25rem;
  --text-xl: 1.5rem;
  --text-2xl: 2rem;
  --text-hero: clamp(1.75rem, 1.2rem + 1.8vw, 2.75rem);
  /* Occhiello del design system ("BY KAILEX", "CLIENT & COUNSEL TOGETHER"). */
  --text-occhiello: 0.6875rem;

  --leading-tight: 1.05;
  --leading-snug: 1.25;
  --leading-normal: 1.55;

  --tracking-wide: 0.08em;
  --tracking-wider: 0.14em;
  /* Il carattere arrotondato dei titoli si stringe appena (più il display
     dei titoli); gli occhielli sono maiuscole molto spaziate. */
  --tracking-display: -0.015em;
  --tracking-titolo: -0.01em;
  --tracking-testo: -0.005em;
  --tracking-occhiello: 0.24em;

  /* --- Spaziature: scala unica, usata ovunque al posto di valori a caso -- */
  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: 0.75rem;
  --space-4: 1rem;
  --space-5: 1.5rem;
  --space-6: 2rem;
  --space-7: 3rem;
  --space-8: 4.5rem;

  /* --- Colori condivisi (alias semantici del design system) -------------- */
  --c-bg: var(--kx-white);          /* surface-card */
  --c-bg-sunken: var(--kx-paper);   /* bg-canvas: il fondo della pagina */
  --c-bg-inverse: var(--kx-ink);    /* surface-inverse */
  --c-surface: var(--kx-white);
  --c-text: var(--kx-ink);          /* fg-1 */
  --c-text-soft: var(--kx-neutral-600);  /* fg-2 */
  /* fg-3. MISURATO: 4,78:1 sul bianco, 4,44:1 sulla carta del fondo — sulla
     carta appena sotto il 4,5:1 delle WCAG per il testo normale. È il valore
     del design system; se va alzato, va alzato lì. Resta la TERZA voce della
     scala (19,8 / 6,8 / 4,8): la gerarchia è quella del design system. */
  --c-text-faint: var(--kx-neutral-500);
  --c-text-inverse: var(--kx-paper);
  --c-border: var(--kx-neutral-100);        /* border-hairline */
  --c-border-strong: var(--kx-neutral-200); /* border-default */

  /* Colori di stato: le coppie testo/fondo del Badge del design system.
     L'attenzione usa come testo il bruno del Badge e non warning-500, che sul
     bianco darebbe 2,9:1. */
  --c-positivo: var(--kx-success-500);
  --c-positivo-bg: var(--kx-success-50);
  --c-attenzione: #9A6618;
  --c-attenzione-bg: var(--kx-warning-50);
  --c-critico: var(--kx-danger-500);
  --c-critico-bg: var(--kx-danger-50);
  --c-info: var(--kx-info-500);
  --c-info-bg: var(--kx-info-50);

  /* --- PER TENANT: sovrascritte da theme-<tenant>.css --------------------- */
  /* Accento del marchio madre (accent / accent-strong / accent-soft del
     design system). Un tema di studio lo sostituisce come fanno i sotto-brand
     del design system: cambia l'accento, non il resto. I temi lo scrivono in
     esadecimale: gli sfondi animati lo leggono con getComputedStyle e lo
     convertono per gli shader (sfondo-accesso.js). */
  --accent: var(--kx-teal-500);
  --accent-scuro: var(--kx-teal-700);
  --accent-tenue: var(--kx-teal-50);
  --tenant-nome: "KaiLex";
  /* Il lockup orizzontale CON payoff ("Client & Counsel, Together") ovunque compaia il marchio
     KaiLex: positivo su fondo chiaro, negativo su fondo scuro (titolare, 2026-10-01). È largo
     2,73 volte la sua altezza, e il payoff è piccolo dentro il disegno: per restare leggibile il
     logo ha un'altezza sua (--logo-altezza), più alta dei 2,25rem dei loghi senza payoff.
     Larghezza e altezza sono valori, non regole di layout — quindi stanno nel tema: i temi
     degli studi le riportano al proprio marchio. */
  --logo: url("/img/logo-kailex-payoff.svg");
  --logo-inverso: url("/img/logo-kailex-payoff-inverso.svg");
  --logo-altezza: 4.4rem;
  --logo-larghezza: 12rem;
  --logo-inverso-larghezza: 12rem;
  /* Nel piè di pagina lo stesso lockup scuro. */
  --logo-pie: url("/img/logo-kailex-payoff-inverso.svg");
  --logo-pie-larghezza: 12rem;

  /* --- Forme ------------------------------------------------------------- */
  /* La scala dei raggi del design system: morbida, ma non gonfia. --radius è
     il raggio di tutto ciò che non ha un componente nel design system
     (menu, suggerimenti, riquadri piccoli); pulsanti, campi e schede usano il
     gradino del loro componente (pillola, md, lg). */
  --radius-xs: 4px;
  --radius-sm: 8px;
  --radius-md: 12px;
  --radius-lg: 16px;
  --radius-xl: 24px;
  --radius: var(--radius-sm);
  --radius-pill: 999px;
  --bordo: 1px solid var(--c-border);
  /* Elevazione quasi piatta: ombre morbide, fredde, basse (shadow-1, shadow-2). */
  --ombra-lieve: 0 1px 2px rgba(10, 10, 10, 0.04), 0 1px 1px rgba(10, 10, 10, 0.03);
  --ombra-media: 0 4px 16px -4px rgba(10, 10, 10, 0.08), 0 1px 2px rgba(10, 10, 10, 0.04);
  /* Due soli livelli di elevazione, e restano due: `lieve` per ciò che è
     appoggiato alla pagina (riquadri, schede al passaggio del mouse),
     `media` per ciò che si stacca (menu, suggerimenti). Le ombre orizzontali
     della spalla delle comunicazioni non sono un terzo livello: sono la
     stessa ombra vista di lato, e restano scritte lì perché dipendono dal
     lato da cui il pannello entra. */

  /* --- Movimento ---------------------------------------------------------
     "Breve, coerente e mai puramente decorativa" (playbook §1) è una regola
     che si può rispettare solo se esiste UN posto dove le durate sono
     scritte. Prima erano venti valori sparsi fra 0,1s e 1,8s, decisi una
     regola alla volta: la scala qui sotto ha sei gradini, e ciascuno ha il
     nome di un GESTO — non di un componente.

     Due valori fuori scala (0,12s sul passaggio del mouse su una riga, 0,25s
     sull'arrivo di una bolla di chat) sono stati portati al gradino più
     vicino. È precisamente ciò per cui esiste una scala, e venti o trenta
     millesimi su un'interazione non si percepiscono.

     `--curva-standard` e `--durata-breve` sono `ease-standard` e `dur-fast`
     del design system: cambiarli qui ha cambiato il passo di tutta
     l'interfaccia in un colpo solo — che è esattamente il punto. */
  --durata-istante: 100ms;    /* micro-reazione: opacità, sfondo di una riga */
  --durata-breve: 140ms;      /* la gran parte: colore, bordo, ombra, riempimento */
  --durata-media: 220ms;      /* qualcosa entra o esce dallo schermo */
  --durata-rivela: 700ms;     /* una barra che cresce mentre si legge il dato */
  --durata-traccia: 1100ms;   /* una linea che si disegna: gesto più lungo */
  --durata-evidenzia: 1800ms; /* "questo è cambiato": si guarda, non si usa */
  --curva-standard: cubic-bezier(0.2, 0.7, 0.1, 1);
  --curva-rivela: cubic-bezier(0.2, 0.8, 0.2, 1);
  --curva-traccia: cubic-bezier(0.3, 0.7, 0.2, 1);
  /* Scaglionamento: quando più elementi entrano insieme, ciascuno parte un
     passo dopo il precedente. Il valore è il PASSO, non il ritardo: i
     ritardi si scrivono `calc(var(--passo-scaglionato) * n)`, così la
     progressione si legge ed è impossibile sbagliarne uno a metà elenco. */
  --passo-scaglionato: 40ms;

  /* --- Impilamento -------------------------------------------------------
     Tre piani soli, perché tre sono le cose che si sovrappongono davvero: la
     barra, i suggerimenti dei grafici, la spalla delle comunicazioni. Prima
     l'ordine era tenuto a mano da un commento ("sopra la barra (20) e ai
     suggerimenti (50)") — cioè da qualcosa che qualcuno avrebbe dovuto
     ricordarsi di aggiornare.

     Gli z-index locali (0…3) dentro contesti di impilamento isolati restano
     numeri nudi: non competono con nulla fuori dal loro contesto, e
     promuoverli a token farebbe credere il contrario. */
  --z-barra: 20;
  /* Il menu su schermo stretto: il velo sotto, il pannello sopra. Due piani
     e non uno, perché il velo deve coprire il contenuto MA NON il pannello
     che sta chiudendo. */
  --z-velo: 30;
  /* Il pulsante flottante dei messaggi: sopra il contenuto e il velo, sotto
     la colonna aperta a pannello e la spalla delle comunicazioni. */
  --z-flottante: 35;
  --z-laterale: 40;
  --z-suggerimento: 50;
  /* Gli esiti della barra comandi stanno sopra i suggerimenti dei grafici
     (si cerca anche stando su Statistiche) e sotto la spalla delle
     comunicazioni, che è un pannello a tutta altezza. */
  --z-comandi: 55;
  --z-spalla: 60;

  /* Anello di focus (shadow-focus del design system). Era ripetuto in due
     punti con la stessa terna di valori: se un giorno cambia lo spessore,
     deve cambiare in entrambi. */
  --anello-focus: 0 0 0 3px color-mix(in srgb, var(--accent) 28%, transparent);

  /* --- Densità -----------------------------------------------------------
     Rinviati dalla fase 0 con una ragione precisa: il blocco sarebbe stato
     inerte, perché l'attributo va su `<html>` e quel tag era scritto in
     ciascuna delle 42 pagine. Dalla fase 1 il telaio ne è proprietario, e la
     densità costa una riga.

     TRE token, non una scala globale. Ridefinire `--space-*` sotto
     `[data-densita]` avrebbe stretto TUTTO, compresa la pagina di accesso e
     la spaziatura fra i paragrafi: la densità riguarda il RITMO VERTICALE
     degli elenchi e delle schede, cioè i punti in cui si guardano venti righe
     di seguito. Altrove il respiro non è spreco.

     Comoda è il valore di sempre: chi non tocca nulla non vede differenze. */
  --pad-scheda: var(--space-4) var(--space-5);
  --pad-scheda-corpo: var(--space-5);
  --pad-cella: var(--space-4);
  --pad-riga: var(--space-3);

  /* --- Grafici ----------------------------------------------------------- */
  /* Due serie: il cremisi dello studio e un blu. Coppia verificata con uno
     script di controllo (luminosità, saturazione minima, distinguibilità per
     i tre tipi di daltonismo, contrasto sul bianco) per ENTRAMBI i cremisi
     dei due studi: passa tutti i controlli. Un grigio come seconda serie era
     stato scartato: sotto la soglia di saturazione si legge come "dato
     assente", non come una serie. La coppia con il teal del design system
     (la piattaforma senza tema di studio) NON è ancora passata da quello
     script: il design system non ha una palette per i grafici. */
  --grafico-serie-1: var(--accent);
  --grafico-serie-2: #2A6DB5;
  /* Griglia e assi recessivi: un passo sopra il fondo, mai tratteggiati. */
  --grafico-griglia: var(--c-border);
  --grafico-tenue: var(--c-border-strong);

  --larghezza-max: 78rem;
  /* Colonna di navigazione: i 248px della colonna d'inchiostro del design
     system. "Clienti e conformità", il titolo di gruppo più lungo, ci sta su
     una riga: un titolo che va a capo spezza la scansione verticale
     dell'elenco, che è l'unica cosa che una colonna fa meglio di una barra. */
  --larghezza-laterale: 15.5rem;
  /* Filo del brand in cima alla finestra: a zero, perché nel design system il
     colore entra solo dalla metà destra del marchio ("un solo momento
     d'accento per vista"). Resta un token perché la colonna appiccicata in
     alto lo sottrae dalla propria altezza. */
  --filo-brand: 0px;
  --larghezza-testo: 46rem;
}

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

/* L'attributo `hidden` deve vincere SEMPRE. Il browser lo traduce in
   `display: none` con la specificità più bassa possibile, quindi qualunque
   regola `display` di classe lo annulla: `.avviso { display: flex }` teneva
   visibile per sempre l'avviso "pratica aggiornata da qualcun altro", che
   nasce nascosto (difetto trovato guardando la pagina, settembre 2026). */
[hidden] { display: none !important; }

html {
  -webkit-text-size-adjust: 100%;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

body {
  margin: 0;
  font-family: var(--font-ui);
  font-size: var(--text-base);
  line-height: var(--leading-normal);
  letter-spacing: var(--tracking-testo);
  color: var(--c-text);
  background: var(--c-bg-sunken);
  /* Il layout a colonna con `main` elastico tiene il piè di pagina in fondo
     anche sulle pagine corte (elenco vuoto, errore), dove altrimenti
     risalirebbe a metà schermo. */
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}

img, svg { max-width: 100%; display: block; }

/* `inherit` e non un colore fisso: i link dentro la barra scura devono
   restare chiari senza una regola dedicata per ogni contesto. La
   sottolineatura è quella del design system: sottile, staccata, nel colore
   dell'accento. I link che non la vogliono (navigazione) la tolgono già. */
a {
  color: inherit;
  text-decoration-color: var(--accent);
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
}

::selection { background: var(--kx-teal-100); }

/* Accessibilità: un contorno visibile SOLO da tastiera. `:focus-visible` e
   non `:focus` — quest'ultimo disegnerebbe l'anello anche al clic del mouse,
   ed è il motivo per cui in tanti progetti si finisce per togliere
   `outline` del tutto, buttando via l'accessibilità con l'estetica. */
:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* Rispetta chi ha chiesto meno animazioni a livello di sistema operativo.
   Non è una cortesia: per alcune persone il movimento è un sintomo. */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    /* Senza questo, un'animazione in ciclo continuerebbe a ripetersi — solo
       molto più in fretta. Azzerare la durata non basta a fermarla. */
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

/* --- Tipografia ---------------------------------------------------------- */
/* Display e H1–H3 nel carattere del marchio, in grassetto; H4 è già testo
   d'interfaccia e resta in Inter Tight. */
h1, h2, h3, h4 {
  font-family: var(--font-display);
  line-height: var(--leading-snug);
  font-weight: 700;
  margin: 0 0 var(--space-3);
  letter-spacing: var(--tracking-titolo);
}

h1 { font-size: var(--text-hero); letter-spacing: var(--tracking-display); }
h2 { font-size: var(--text-xl); }
h3 { font-size: var(--text-md); }
h4 { font-size: var(--text-base); font-family: var(--font-ui); font-weight: 600; }

p { margin: 0 0 var(--space-3); }
p:last-child { margin-bottom: 0; }

/* Occhiello del design system (`.kx-eyebrow`): maiuscole piccole e molto
   spaziate sopra i titoli di sezione. */
.occhiello {
  font-size: var(--text-occhiello);
  text-transform: uppercase;
  letter-spacing: var(--tracking-occhiello);
  color: var(--c-text-soft);
  font-weight: 500;
  margin: 0 0 var(--space-2);
}

.sommario { color: var(--c-text-soft); max-width: var(--larghezza-testo); }
.testo-tenue { color: var(--c-text-soft); }
.testo-piccolo { font-size: var(--text-sm); }
.testo-minuscolo { font-size: var(--text-xs); }
.mono { font-family: var(--font-mono); font-size: var(--text-sm); }

/* Solo per lettori di schermo: usata per le etichette che servono
   all'accessibilità ma sarebbero rumore visivo (es. "cerca" sopra un campo
   che ha già una lente). `clip-path` invece di `display:none` perché
   quest'ultimo la toglierebbe anche ai lettori di schermo. */
.solo-lettori {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* --- Layout -------------------------------------------------------------- */
.contenitore {
  width: 100%;
  max-width: var(--larghezza-max);
  margin-inline: auto;
  padding-inline: var(--space-5);
}

main { flex: 1 0 auto; padding-block: var(--space-6) var(--space-8); }

.pila > * + * { margin-top: var(--space-5); }
.pila-stretta > * + * { margin-top: var(--space-3); }

/* Griglia elastica: le colonne si adattano senza media query, perché
   `auto-fit` + `minmax` fa collassare da sé il numero di colonne quando lo
   spazio non basta. Una media query per ogni griglia sarebbe stata la
   soluzione più ovvia e la più fragile. */
.griglia {
  display: grid;
  gap: var(--space-4);
  grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
}

.griglia-due {
  display: grid;
  gap: var(--space-5);
  grid-template-columns: repeat(auto-fit, minmax(20rem, 1fr));
}

/* Colonna principale + barra laterale, che scende sotto sotto i 62rem. */
.colonne-pratica {
  display: grid;
  gap: var(--space-5);
  align-items: start;
}
@media (min-width: 62rem) {
  .colonne-pratica { grid-template-columns: minmax(0, 1fr) 20rem; }
}

/* ===========================================================================
   INTESTAZIONE
   =========================================================================== */
/* ===========================================================================
   BARRA ORIZZONTALE — ora solo la console di piattaforma (/admin)
   ===========================================================================

   Era la navigazione di tutta l'applicazione; dalla fase 1 del redesign le
   pagine dello studio usano il telaio a colonna (più sotto). Queste regole
   restano perché `views/admin/intestazione.ejs` le usa ancora: la console ha
   cinque destinazioni, non quindici, e una barra le contiene benissimo.

   Sono anche il motivo per cui il telaio ha un prefisso proprio invece di
   riusare `.nav-voce`: due componenti che si somigliano ma cambiano per
   ragioni diverse: condividere le regole significherebbe che un ritocco alla
   console sposta qualcosa in dodici pagine dello studio. */
.barra {
  background: var(--c-bg);
  border-bottom: var(--bordo);
  position: sticky;
  top: 0;
  z-index: var(--z-barra);
}

/* Filo cremisi sopra la barra: il gesto più economico per portare il colore
   del brand su ogni pagina senza colorare nulla di funzionale. */
.barra::before {
  content: "";
  display: block;
  height: var(--filo-brand);
  background: var(--accent);
}

.barra-interno {
  display: flex;
  align-items: center;
  gap: var(--space-5);
  min-height: 4.25rem;
}

/* Un unico elemento nel markup: l'immagine cambia per tenant tramite la
   variabile, senza che nessun template sappia di quale studio si tratta. */
.logo {
  display: block;
  width: var(--logo-larghezza);
  height: var(--logo-altezza);
  background-image: var(--logo);
  background-repeat: no-repeat;
  background-position: left center;
  background-size: contain;
  flex-shrink: 0;
}

/* Nome dello studio letto da --tenant-nome: nessun markup duplicato. */
.nome-tenant::before { content: var(--tenant-nome); }

.barra-nav {
  display: flex;
  align-items: center;
  gap: var(--space-5);
  margin-left: auto;
}

.nav-voci {
  display: flex;
  align-items: center;
  gap: var(--space-5);
  list-style: none;
  margin: 0;
  padding: 0;
}

/* Maiuscoletto spaziato: la navigazione di entrambi gli studi.

   VOCI E CAMPANELLO CONDIVIDONO LA STESSA REGOLA, apposta. "Avvisi" era
   disallineato di 1,6px (MISURATO nel browser: centro del testo a 36,2px
   contro 37,8px delle altre voci). La causa: le voci erano elementi INLINE,
   la cui altezza la decide la riga di testo del <li>; il campanello era un
   FLEX, la cui altezza la decideva il pallino del contatore (21,6px, più alto
   della riga di testo da 19,2px). Due modelli di impaginazione diversi
   centrati nella stessa riga non producono lo stesso punto per il testo, e
   due tentativi precedenti di pareggiarli con interlinea e padding lo
   avevano solo spostato. Ora:
     1. stessa scatola per tutti (inline-flex, stesso padding, stesso bordo
        riservato), scritta UNA volta: non possono più divergere;
     2. il pallino esce dal flusso (position: absolute), quindi non può più
        influire sull'altezza di nulla. */
.nav-voce,
.campanello {
  position: relative;
  display: inline-flex;
  align-items: center;
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: var(--tracking-wide);
  font-weight: 600;
  color: var(--c-text-soft);
  text-decoration: none;
  padding-block: var(--space-2);
  border-bottom: 2px solid transparent;
  white-space: nowrap;
  transition: color var(--durata-breve) var(--curva-standard), border-color var(--durata-breve) var(--curva-standard);
}
.nav-voce:hover,
.campanello:hover { color: var(--c-text); }
.nav-voce[aria-current="page"],
.campanello[aria-current="page"] {
  color: var(--c-text);
  border-bottom-color: var(--accent);
}

/* Spazio a destra riservato al pallino: essendo fuori dal flusso non lo
   occuperebbe da sé, e finirebbe sopra l'elemento successivo. */
.campanello { padding-right: 1.9rem; }

.campanello-conteggio {
  position: absolute;
  right: 0;
  /* Centrato sul TESTO, non sulla scatola: la scatola ha 2px di bordo solo
     in basso, quindi il centro del testo sta 1px sopra il suo centro. */
  top: calc(50% - 1px);
  transform: translateY(-50%);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  line-height: 1;
  min-width: 1.35rem;
  height: 1.35rem;
  padding-inline: 0.35rem;
  border-radius: var(--radius-pill);
  background: var(--accent);
  color: #fff;
  font-size: var(--text-xs);
  font-weight: 700;
  letter-spacing: 0;
}
/* Zero notifiche: il pallino sparisce del tutto invece di mostrare "0". */
.campanello-conteggio[data-conteggio="0"] { display: none; }

.utente {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding-left: var(--space-5);
  border-left: var(--bordo);
  /* Non si stringe: a stringersi, in una riga che non basta, deve essere il
     campo di ricerca (che ha `min-width: 0`), non il nome — misurato a
     1100px, "Anna Bianchi" andava su due righe accanto a un campo largo 240. */
  flex-shrink: 0;
}

/* Avatar testuale: due iniziali. Nessuna immagine da caricare, da
   ridimensionare o da conservare — e nessun dato personale in più rispetto
   al nome che compare comunque accanto. */
.avatar {
  display: grid;
  place-items: center;
  width: 2.25rem;
  height: 2.25rem;
  border-radius: var(--radius-pill);
  background: var(--c-bg-inverse);
  color: var(--c-text-inverse);
  font-size: var(--text-xs);
  font-weight: 700;
  letter-spacing: 0.03em;
  flex-shrink: 0;
}

.utente-dati { line-height: 1.25; }
.utente-nome { font-weight: 600; font-size: var(--text-sm); }
.utente-ruolo {
  font-size: var(--text-xs);
  color: var(--c-text-faint);
  text-transform: uppercase;
  letter-spacing: var(--tracking-wide);
}

/* Schermo stretto, barra della console.

   CORREZIONE di un difetto preesistente, trovato togliendo il pulsante
   hamburger insieme alla vecchia barra dello studio. Qui c'era
   `.barra-nav { display: none }`, che contava sul pulsante per riaprire la
   navigazione — ma quel pulsante l'ha sempre avuto SOLO la barra dello
   studio: `views/admin/intestazione.ejs` non l'ha mai reso. Effetto: sotto i
   60rem la console di piattaforma restava senza navigazione e senza alcun
   modo di richiamarla.

   Ora la barra manda a capo invece di nascondersi. Con quattro voci ci
   sta, ed è la soluzione giusta proprio perché non richiede uno stato da
   aprire e chiudere: la console non ha abbastanza destinazioni da
   giustificarlo. */
@media (max-width: 60rem) {
  .barra-interno { flex-wrap: wrap; row-gap: var(--space-3); }
  .barra-nav {
    width: 100%;
    flex-wrap: wrap;
    gap: var(--space-4);
    margin-left: 0;
  }
  .nav-voci { flex-wrap: wrap; gap: var(--space-4); }
  .utente { padding-left: 0; border-left: none; margin-left: auto; }
}

/* ===========================================================================
   TELAIO DELL'APPLICAZIONE — colonna, testata, barra comandi
   ===========================================================================

   Struttura (vedi views/partials/telaio.ejs):

     body
       a.salta-contenuto          invisibile finche' non riceve il fuoco
       div.telaio                 griglia a due colonne, filo del brand in cima
         nav.telaio-laterale      appiccicata in alto, alta quanto la finestra
         div.telaio-corpo         colonna elastica: testata, contenuto, pie'
           header.telaio-testata  appiccicata in alto: comandi, avvisi, utente
           ...contenuto della vista...
           footer.pie
       button.telaio-velo         solo con il menu aperto su schermo stretto
       aside#comunicazioni        la spalla delle chat (gia' esistente)

   Perche' una griglia e non una colonna `position: fixed` con margine a
   sinistra: la griglia non richiede di ripetere la larghezza della colonna
   come margine del contenuto (due valori da tenere allineati a mano), e lo
   scorrimento resta quello del documento — quindi gli ancoraggi `#sezione`,
   il ritorno alla posizione col tasto indietro e la stampa continuano a
   funzionare senza una riga in piu'. */

.salta-contenuto {
  position: absolute;
  top: -4rem;
  left: var(--space-4);
  z-index: var(--z-comandi);
  padding: var(--space-2) var(--space-4);
  background: var(--c-bg);
  border: var(--bordo);
  border-radius: var(--radius);
  box-shadow: var(--ombra-media);
  font-size: var(--text-sm);
  font-weight: 600;
  text-decoration: none;
  transition: top var(--durata-breve) var(--curva-standard);
}
/* `:focus` e non `:focus-visible`: questo link esiste SOLO per la tastiera,
   e con `:focus-visible` in qualche browser resterebbe invisibile proprio a
   chi lo sta usando. */
.salta-contenuto:focus { top: var(--space-3); }

/* Il bersaglio della scorciatoia porta `tabindex="-1"` (fase 8): senza,
   seguire `#contenuto` sposta lo SCORRIMENTO e non il FUOCO, e il Tab
   successivo riparte dall'inizio della barra — cioè la scorciatoia non
   scorcia niente. Misurato: prima del `tabindex` il fuoco restava su `body`.
   `-1` non lo mette nell'ordine di navigazione: lo rende solo raggiungibile
   dal codice e da un frammento.

   L'anello attorno a un contenitore grande quanto la pagina non direbbe
   nulla a chi vede e disturberebbe chi usa il mouse: `<main>` non è un
   comando. Stessa scelta già fatta per il titolo di una conversazione. */
main[tabindex="-1"]:focus { outline: none; }

.telaio {
  /* `body` e' una colonna flex (vedi sopra): questo prende tutta l'altezza
     rimasta, cosi' il pie' di pagina resta in fondo anche sulle pagine corte. */
  flex: 1 0 auto;
  display: grid;
  /* `minmax(0, 1fr)` e non `1fr`: la larghezza minima predefinita di una
     colonna di griglia e' `auto`, cioe' "quanto serve al contenuto". Con una
     tabella larga (le fatture, il carico del team) la colonna si allargherebbe
     oltre la finestra invece di far scorrere la tabella. E' l'errore classico
     della griglia con contenuto non comprimibile, e si vede solo su una
     pagina densa. */
  grid-template-columns: var(--larghezza-laterale) minmax(0, 1fr);
  /* Il filo cremisi in cima alla finestra: unico gesto di colore del brand su
     ogni pagina. Sta sul contenitore della griglia — non su un elemento
     dedicato — perche' cosi' attraversa entrambe le colonne, e perche' un
     elemento appiccicato in alto non puo' risalire sopra il bordo del proprio
     blocco contenitore: la testata si ferma sotto il filo da sola. */
  border-top: var(--filo-brand) solid var(--accent);
}

.telaio-laterale {
  position: sticky;
  top: 0;
  height: calc(100vh - var(--filo-brand));
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
  /* La colonna d'inchiostro del design system. Come sul vetro dell'accesso,
     si ridefiniscono qui i TOKEN che le regole della colonna già usano: il
     testo diventa carta, i fili e i fondi tinte bianche al 5–8%. */
  --c-text: var(--kx-paper);
  --c-text-soft: var(--kx-neutral-300);
  --c-text-faint: var(--kx-neutral-300);
  --c-border: rgba(244, 247, 248, 0.08);
  /* --bordo va ridichiarato: in :root è già risolto con il filo chiaro. */
  --bordo: 1px solid var(--c-border);
  --c-bg-sunken: rgba(244, 247, 248, 0.05);
  --accent-tenue: rgba(244, 247, 248, 0.08);
  padding: 1.75rem var(--space-4);
  background: var(--c-bg-inverse);
  color: var(--c-text);
  overflow-y: auto;
  /* Arrivati in fondo all'elenco delle voci, la rotellina non deve mettersi
     a scorrere la pagina sotto. */
  overscroll-behavior: contain;
}

/* Nella colonna d'inchiostro il logo è il lockup scuro. */
.telaio-logo {
  margin: 0 0 var(--space-2);
  margin-inline: 0.625rem;
  width: var(--logo-inverso-larghezza);
  max-width: calc(100% - 1.25rem);
  background-image: var(--logo-inverso);
}

.telaio-gruppi { display: flex; flex-direction: column; gap: var(--space-5); }

/* Il primo blocco di gruppi si allunga a riempire lo spazio: e' cosi' che i
   gruppi `inFondo` (Svago) e il pie' della colonna stanno in basso senza un
   `margin-top: auto` su ciascuno — due margini automatici nella stessa
   colonna si spartirebbero lo spazio libero invece di spingere in fondo. */
.telaio-gruppi:not(.telaio-gruppi--fondo) { flex: 1 0 auto; }

.telaio-gruppi--fondo {
  padding-top: var(--space-5);
  border-top: var(--bordo);
}

.telaio-gruppo-titolo {
  margin: 0 0 var(--space-2);
  padding-inline: var(--space-3);
  font-size: var(--text-occhiello);
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: var(--tracking-occhiello);
  color: var(--c-text-soft);
}

.telaio-voci {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
}

.telaio-voce {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  /* Voce della colonna del design system: alta 40px, angoli a 10px, attiva
     con un velo chiaro e il testo in carta — nessun filo laterale. */
  min-height: 2.5rem;
  padding: var(--space-2) var(--space-3);
  border-radius: 10px;
  color: var(--c-text-soft);
  font-size: 0.875rem;
  font-weight: 500;
  text-decoration: none;
  transition: background var(--durata-breve) var(--curva-standard),
              color var(--durata-breve) var(--curva-standard);
}
.telaio-voce:hover { background: var(--c-bg-sunken); color: var(--c-text); }

/* Lo stato attivo si legge da `aria-current`, l'attributo che un lettore di
   schermo annuncia: una classe `is-attiva` sarebbe la stessa informazione
   scritta due volte, e la seconda si dimentica. */
.telaio-voce[aria-current="page"] {
  background: var(--accent-tenue);
  color: var(--c-text);
}

/* Il pallino dei non letti, nella colonna e nella testata. Non e' fuori dal
   flusso come quello della vecchia barra: qui la voce e' un flex a piena
   larghezza, quindi `margin-left: auto` lo spinge a destra senza che possa
   alzare la riga (era la causa del disallineamento di "Avvisi", misurato nel
   browser a settembre 2026). */
.telaio-conteggio {
  margin-left: auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 1.35rem;
  height: 1.35rem;
  padding-inline: 0.35rem;
  border-radius: var(--radius-pill);
  background: var(--accent);
  color: #fff;
  font-size: var(--text-xs);
  font-weight: 700;
  line-height: 1;
  letter-spacing: 0;
}
/* Zero: il pallino sparisce invece di mostrare "0". Due attributi perche' due
   contatori (avvisi e messaggi) vivono nello stesso componente. */
.telaio-conteggio[data-conteggio="0"],
.telaio-conteggio[data-conteggio-messaggi="0"] { display: none; }

.telaio-laterale-pie {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  padding-top: var(--space-4);
  border-top: var(--bordo);
}

.telaio-riduci {
  align-self: flex-start;
  background: none;
  border: 0;
  padding: var(--space-1) var(--space-3);
  font: inherit;
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: var(--tracking-wide);
  font-weight: 600;
  color: var(--c-text-faint);
  cursor: pointer;
  transition: color var(--durata-breve) var(--curva-standard);
}
.telaio-riduci:hover { color: var(--c-text); }

.telaio-ambiente {
  margin: 0;
  padding-inline: var(--space-3);
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: var(--tracking-wide);
  color: var(--c-text-faint);
}

/* --- Colonna del contenuto ---------------------------------------------- */
.telaio-corpo {
  display: flex;
  flex-direction: column;
  /* Gemello del `minmax(0, 1fr)` di sopra: senza, un figlio non comprimibile
     (una tabella) allargherebbe la colonna flex. */
  min-width: 0;
}

.telaio-testata {
  position: sticky;
  top: 0;
  z-index: var(--z-barra);
  display: flex;
  align-items: center;
  gap: var(--space-4);
  /* La barra alta 64px del design system, sul fondo della pagina. */
  min-height: 4rem;
  padding: var(--space-3) var(--space-5);
  background: var(--c-bg-sunken);
  border-bottom: var(--bordo);
  /* Sempre libera di andare a capo: finché tutto sta su una riga non cambia
     nulla, e quando non ci sta il `@container testata` più sotto decide che
     cosa scende. */
  flex-wrap: wrap;
  /* CONTAINER QUERY, non media query — difetto trovato MISURANDO a
     1000-1100px di finestra. La media query guarda la FINESTRA; la testata
     però è larga la finestra MENO la colonna (240px). Sopra i 60rem la
     colonna ricompare e toglie quei 240px proprio mentre la media query dice
     "c'è spazio": misurato a 1000px, il campo di ricerca scendeva a 140px con
     "Ctrl K" sopra il segnaposto, e il nome dell'utente andava su due righe.
     Chiedendo la larghezza alla testata stessa, la regola vale identica con
     la colonna aperta, ridotta o in modalità focus.
     `inline-size` contiene solo la larghezza: l'altezza resta quella del
     contenuto, che è ciò che deve crescere quando la barra va a capo. */
  container: testata / inline-size;
} { margin-bottom: 0; margin-right: auto; }
.telaio-accesso { display: flex; gap: var(--space-2); margin-left: auto; }

/* Pulsante del menu: da schermo largo non serve — la colonna e' sempre li' —
   tranne quando e' stata ridotta, che e' l'unico modo di riaprirla. */
.telaio-menu {
  display: none;
  background: none;
  border: var(--bordo);
  border-radius: var(--radius);
  padding: var(--space-2) var(--space-3);
  font: inherit;
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: var(--tracking-wide);
  font-weight: 600;
  cursor: pointer;
  flex-shrink: 0;
}
.telaio-menu:hover { background: var(--c-bg-sunken); }

.telaio-avvisi {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  margin-left: auto;
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-pill);
  font-size: var(--text-sm);
  font-weight: 500;
  color: var(--c-text-soft);
  text-decoration: none;
  white-space: nowrap;
  transition: background var(--durata-breve) var(--curva-standard),
              color var(--durata-breve) var(--curva-standard);
}
.telaio-avvisi:hover { background: var(--c-bg-sunken); color: var(--c-text); }
.telaio-avvisi[aria-current="page"] { background: var(--accent-tenue); color: var(--c-text); }
/* Nella testata il pallino segue la parola, non il bordo destro della voce. */
.telaio-avvisi .telaio-conteggio { margin-left: 0; }

/* Velo dietro il menu aperto. `hidden` finche' e' chiuso, e il reset globale
   `[hidden] { display: none !important }` vince su questa regola: e' il modo
   piu' corto di non far intercettare i clic a un elemento invisibile. */
.telaio-velo {
  display: none;
  position: fixed;
  inset: 0;
  z-index: var(--z-velo);
  border: 0;
  padding: 0;
  background: rgba(10, 10, 10, 0.35);
  cursor: pointer;
}

/* Pulsante flottante dei messaggi, in basso a destra: prende il posto della
   voce "Messaggi" della colonna. Pieno nell'accento, rotondo come gli
   IconButton del design system, con l'ombra dei livelli che si staccano
   (shadow-3). Il pallino dei non letti è quello della colonna, spostato
   sull'angolo. */
.messaggi-flottante {
  position: fixed;
  right: var(--space-5);
  bottom: var(--space-5);
  z-index: var(--z-flottante);
  display: inline-grid;
  place-items: center;
  width: 3.5rem;
  height: 3.5rem;
  border-radius: var(--radius-pill);
  background: var(--accent);
  color: var(--kx-white);
  box-shadow: 0 24px 48px -16px rgba(10, 10, 10, 0.18), 0 2px 6px rgba(10, 10, 10, 0.05);
  text-decoration: none;
  transition: background var(--durata-breve) var(--curva-standard), transform var(--durata-breve) var(--curva-standard);
}
.messaggi-flottante:hover { background: var(--accent-scuro); }
.messaggi-flottante:active { transform: scale(0.98); }
.messaggi-flottante-icona { display: block; }
.messaggi-flottante .telaio-conteggio {
  position: absolute;
  top: -0.25rem;
  right: -0.25rem;
  margin: 0;
  background: var(--c-bg-inverse);
  box-shadow: 0 0 0 2px var(--kx-white);
}

/* --- Barra comandi ------------------------------------------------------ */
.comandi {
  position: relative;
  display: flex;
  align-items: center;
  gap: var(--space-2);
  /* Cresce fino a 34rem e poi si ferma: un campo di ricerca larghissimo su
     uno schermo grande sembra il protagonista della pagina, e non lo e'. */
  flex: 1 1 22rem;
  max-width: 34rem;
  margin: 0;
}

.comandi-campo {
  /* Piu' bassa della regola generale dei campi: qui il campo sta in una
     barra alta 3,75rem insieme a nome, ruolo e due pulsanti. */
  padding-block: var(--space-2);
  font-size: var(--text-sm);
  min-width: 0;
}

.comandi-scorciatoia {
  position: absolute;
  right: 5.4rem;
  padding: 0.1rem var(--space-2);
  border: var(--bordo);
  border-radius: var(--radius);
  background: var(--c-bg-sunken);
  color: var(--c-text-faint);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  line-height: 1.4;
  pointer-events: none;
}

/* Nascosta appena si scrive: `visibility` e non `display`, per non togliere
   dal DOM accessibile l'elemento che il campo cita in `aria-describedby`. */
.comandi-scorciatoia.is-nascosta { visibility: hidden; }

.comandi-invia {
  flex-shrink: 0;
  background: none;
  border: var(--bordo);
  border-radius: var(--radius-pill);
  padding: var(--space-2) var(--space-3);
  font: inherit;
  font-size: var(--text-sm);
  font-weight: 500;
  cursor: pointer;
}
.comandi-invia:hover { background: var(--c-bg-sunken); }

.comandi-esiti {
  position: absolute;
  top: calc(100% + var(--space-2));
  left: 0;
  right: 0;
  z-index: var(--z-comandi);
  max-height: min(28rem, 70vh);
  overflow-y: auto;
  overscroll-behavior: contain;
  background: var(--c-bg);
  border: var(--bordo);
  border-radius: var(--radius);
  box-shadow: var(--ombra-media);
}

/* Sulla pagina /cerca lo stesso contenitore non è un pannello sospeso ma la
   pagina stessa: si spegne il posizionamento, non si riscrive il markup. */
.comandi-esiti--pagina {
  position: static;
  max-height: none;
  overflow: visible;
  border: 0;
  border-radius: 0;
  box-shadow: none;
}

.comandi-sezione {
  margin: 0;
  padding: var(--space-2) var(--space-4);
  background: var(--c-bg-sunken);
  border-bottom: var(--bordo);
  font-size: var(--text-xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: var(--tracking-wider);
  color: var(--c-text-faint);
}

.comandi-elenco { list-style: none; margin: 0; padding: 0; }

.comandi-voce {
  display: block;
  padding: var(--space-3) var(--space-4);
  border-bottom: var(--bordo);
  color: inherit;
  text-decoration: none;
}
.comandi-elenco li:last-child .comandi-voce { border-bottom: 0; }
/* `is-evidenziata` la scrive comandi.js muovendosi con le frecce: e' lo stato
   della tastiera, distinto dal passaggio del mouse, e i due non devono
   accendersi insieme (due righe evidenziate = nessuna evidenziata). */
.comandi-voce:hover,
.comandi-voce.is-evidenziata { background: var(--accent-tenue); }

.comandi-voce-titolo { font-weight: 600; font-size: var(--text-sm); }
.comandi-voce-meta {
  font-size: var(--text-xs);
  color: var(--c-text-soft);
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

.comandi-vuoto {
  margin: 0;
  padding: var(--space-4);
  font-size: var(--text-sm);
  color: var(--c-text-soft);
}

/* --- Schermo largo: la colonna si puo' ridurre -------------------------- */
/* La regola vive DENTRO la media query di proposito. Fuori, uno stato
   "ridotta" salvato in localStorage dal portatile nasconderebbe la
   navigazione anche sul telefono, dove non esiste alcun modo di riaprirla
   se non svuotando la memoria del browser. */
@media (min-width: 60.0625rem) {
  /* UNA colonna, non "zero e una".
     DIFETTO TROVATO MISURANDO: con `grid-template-columns: 0 minmax(0, 1fr)`
     e la colonna nascosta con `display: none`, il telaio resta con UN solo
     figlio — che la griglia colloca nella PRIMA colonna, quella larga zero.
     Misurato nel browser: il contenitore del contenuto passava da 1248px a
     48px (i soli margini interni), cioè la pagina spariva. Un elemento con
     `display: none` non occupa la sua cella: non esiste per la griglia. */
  .telaio[data-laterale="ridotta"] { grid-template-columns: minmax(0, 1fr); }
  .telaio[data-laterale="ridotta"] .telaio-laterale { display: none; }
  .telaio[data-laterale="ridotta"] .telaio-menu { display: inline-flex; }
}

/* --- Schermo stretto: la colonna diventa un pannello -------------------- */
@media (max-width: 60rem) {
  .telaio { grid-template-columns: minmax(0, 1fr); }

  .telaio-laterale {
    position: fixed;
    top: var(--filo-brand);
    bottom: 0;
    left: 0;
    width: min(19rem, 86vw);
    height: auto;
    z-index: var(--z-laterale);
    box-shadow: var(--ombra-media);
    /* Fuori schermo e non `display: none`: cosi' entra scorrendo, e
       soprattutto resta nel documento — un pannello che appare dal nulla non
       ha una posizione da cui il fuoco possa entrare. */
    transform: translateX(-100%);
    transition: transform var(--durata-media) var(--curva-rivela);
  }
  .telaio[data-menu="aperto"] .telaio-laterale { transform: translateX(0); }

  .telaio-velo { display: block; }
  .telaio-menu { display: inline-flex; }
  /* "Riduci" non vuol dire nulla dove la colonna e' gia' a scomparsa. */
  .telaio-riduci { display: none; }

  .telaio-testata { gap: var(--space-3); }
}

/* La barra comandi va a capo e prende tutta la riga quando la TESTATA (non la
   finestra: vedi `container` su .telaio-testata) scende sotto i 56rem. La
   soglia è misurata: a 56rem, su una riga sola, il campo resta sopra i 20rem
   accanto ad Avvisi, Vista, nome, ruolo e due pulsanti; sotto, il campo
   sarebbe il primo a pagare. */
@container testata (max-width: 56rem) {
  .comandi { order: 3; flex-basis: 100%; max-width: none; }
  .telaio-avvisi { margin-left: 0; }
  .utente { margin-left: auto; padding-left: var(--space-4); }
}

/* La scorciatoia "Ctrl K" sta DENTRO il campo, sopra il segnaposto: sotto i
   28rem di barra i due si sovrapponevano (misurato: "Cerca o c" e subito
   dopo "Ctrl K"). Anche qui conta la larghezza della testata, non della
   finestra — e sotto quella soglia, di solito, una tastiera non c'è. */
/* TELEFONO: l'avatar senza nome (Password ed Esci stanno nel menu che
   l'avatar apre, vedi "Il menu dell'utente"). Misurato a 380 e 600px, la testata
   appiccicata era alta 170px su tre righe (Menu·Avvisi·Vista / utente /
   ricerca): un quarto di uno schermo da 700px, occupato su ogni pagina. Il
   nome e il ruolo sono la parte più larga della riga dell'utente, e anche la
   meno necessaria su un telefono, che di solito ha UNA persona davanti: le
   iniziali nell'avatar bastano a riconoscersi.
   Nascosti alla VISTA, non al lettore di schermo: sono le stesse dichiarazioni
   di `.solo-lettori`, ripetute qui perché una classe non si aggiunge da una
   container query. L'avatar resta `aria-hidden`, quindi senza questo il nome
   sparirebbe del tutto per chi non vede lo schermo.
   Alternativa scartata: tenere la testata e toglierle `position: sticky` sul
   telefono — si recuperava lo spazio, ma il pulsante "Menu" spariva
   scorrendo, e per cambiare pagina bisognava tornare in cima. */
@container testata (max-width: 40rem) {
  .utente-dati {
    position: absolute;
    width: 1px; height: 1px;
    padding: 0; margin: -1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
  }
  /* Filo e rientro a sinistra separano il NOME dalle voci accanto: senza
     nome non separano più niente, e costano 16px. Misurato a 380px: Menu,
     Avvisi, Vista e avatar chiedevano 327px contro 317 disponibili — erano
     esattamente quei 16px a mandare l'avatar sulla riga successiva. */
  .utente { padding-left: 0; border-left: 0; }
}

/* Margine laterale della testata su telefono: 16px invece di 24. Una MEDIA
   query e non un @container, per l'unica ragione possibile: un container non
   può interrogare sé stesso, e questo è il padding della testata. Sotto i
   30rem la colonna è sempre a scomparsa, quindi finestra e testata hanno la
   stessa larghezza e la domanda è la stessa. Misurato a 360px (molti
   telefoni Android): senza, l'avatar andava a capo per pochi pixel. */
@media (max-width: 30rem) {
  .telaio-testata { padding-inline: var(--space-4); }
}

@container testata (max-width: 28rem) {
  .comandi-scorciatoia { display: none; }
}

/* ===========================================================================
   TESTATA DI PAGINA
   =========================================================================== */
.testata {
  background: var(--c-bg);
  border-bottom: var(--bordo);
  padding-block: var(--space-6);
}

.testata-interno {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--space-4);
}

.testata h1 { margin-bottom: var(--space-2); }
.testata-azioni { display: flex; flex-wrap: wrap; gap: var(--space-3); }

/* Filo di Arianna: l'unica navigazione "indietro" della piattaforma. Un
   pulsante "torna" in ogni pagina sarebbe stato più semplice e più povero —
   qui si vede sempre dove si è dentro la gerarchia. */
.briciole {
  display: flex;
  flex-wrap: wrap;
  /* Sulla linea di base: i collegamenti hanno il bersaglio allargato (padding-block, più
     sotto) e l'ultima briciola è testo nudo; allineate in alto la loro scritta scalerebbe. */
  align-items: baseline;
  gap: var(--space-2);
  list-style: none;
  margin: 0 0 var(--space-3);
  padding: 0;
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: var(--tracking-wide);
  color: var(--c-text-faint);
}
/* Un elenco senza punti né rientri: le voci stanno una per riga, col loro stato accanto. */
.elenco-nudo {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: var(--space-2);
}

.briciole li + li::before { content: "/"; margin-right: var(--space-2); }
.briciole a { text-decoration: none; }
.briciole a:hover { color: var(--accent); }

/* ===========================================================================
   SCHEDE
   =========================================================================== */
/* Card del design system: filo sottile, raggio lg, nessuna ombra da ferma. */
.scheda {
  background: var(--c-surface);
  border: var(--bordo);
  border-radius: var(--radius-lg);
}

.scheda-testa {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--pad-scheda);
  border-bottom: var(--bordo);
}
.scheda-testa h2, .scheda-testa h3 { margin: 0; font-size: var(--text-md); }

.scheda-corpo { padding: var(--pad-scheda-corpo); }
.scheda-corpo-fitta { padding: var(--pad-scheda); }

.scheda-pie {
  padding: var(--space-3) var(--space-5);
  border-top: var(--bordo);
  background: var(--c-bg-sunken);
  font-size: var(--text-sm);
}

/* Riquadri numerici del cruscotto. Il numero grande è ripreso dalla sezione
   "Track Record" di Atrigna, dove i numeri sono l'argomento principale. */
.riquadro {
  background: var(--c-surface);
  border: var(--bordo);
  border-radius: var(--radius-lg);
  padding: var(--space-4) var(--space-5);
  /* Il filo colorato a sinistra è l'unico segnale cromatico del riquadro:
     evita di colorare il fondo, che renderebbe il cruscotto un arcobaleno. */
  border-left: 3px solid var(--c-border-strong);
  text-decoration: none;
  display: block;
  transition: border-color var(--durata-breve) var(--curva-standard), box-shadow var(--durata-breve) var(--curva-standard);
}
a.riquadro:hover { border-left-color: var(--accent); box-shadow: var(--ombra-media); }

.riquadro-numero {
  font-family: var(--font-display);
  font-size: var(--text-2xl);
  line-height: 1;
  font-weight: 600;
}
.riquadro-etichetta {
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: var(--tracking-wide);
  color: var(--c-text-faint);
  font-weight: 600;
  margin-top: var(--space-2);
}
.riquadro--critico { border-left-color: var(--c-critico); }
.riquadro--critico .riquadro-numero { color: var(--c-critico); }
.riquadro--attenzione { border-left-color: var(--c-attenzione); }
.riquadro--attenzione .riquadro-numero { color: var(--c-attenzione); }
.riquadro--accento { border-left-color: var(--accent); }

/* ===========================================================================
   AZIONI
   =========================================================================== */
/* Button del design system: pillola alta 40px (32px la piccola), peso 500.
   Le varianti sono le sue: primario inchiostro, accento, secondario a filo,
   pericolo pieno. In un contesto operativo un'azione che modifica dati deve
   essere inequivocabilmente cliccabile, non elegante. */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  min-height: 2.5rem;
  font-family: var(--font-ui);
  font-size: 0.875rem;
  font-weight: 500;
  letter-spacing: var(--tracking-testo);
  line-height: 1.2;
  color: var(--kx-paper);
  background: var(--c-bg-inverse);
  border: 1px solid transparent;
  border-radius: var(--radius-pill);
  padding: var(--space-2) var(--space-4);
  text-decoration: none;
  cursor: pointer;
  transition: background var(--durata-breve) var(--curva-standard), border-color var(--durata-breve) var(--curva-standard), color var(--durata-breve) var(--curva-standard), transform var(--durata-breve) var(--curva-standard);
  white-space: nowrap;
}
.btn:hover { background: var(--kx-neutral-800); }
.btn:active { transform: scale(0.98); }

.btn--accento { background: var(--accent); color: var(--kx-white); }
.btn--accento:hover { background: var(--accent-scuro); }

.btn--fantasma {
  background: var(--c-surface);
  color: var(--c-text);
  border-color: var(--c-border-strong);
}
.btn--fantasma:hover { background: var(--c-bg-sunken); color: var(--c-text); }

/* Azione distruttiva: la variante `danger` del design system, piena. */
.btn--pericolo { background: var(--kx-danger-500); color: var(--kx-white); }
.btn--pericolo:hover { background: #A8463D; color: var(--kx-white); }

.btn--piccolo { min-height: 2rem; padding: var(--space-1) var(--space-3); font-size: var(--text-sm); }
/* Un'azione rara accanto a quella principale (Archivia accanto a Modifica): presente, ma senza il
   peso di un bottone (revisione viste 2026-10, E1). */
.btn--discreto { border-color: transparent; background: transparent; color: var(--c-text-soft); }
.btn--discreto:hover { border-color: var(--c-border-strong); color: var(--c-text); }

/* Spento: l'opacità del design system, e il passaggio del mouse non cambia
   nulla — un pulsante che reagisce sembra cliccabile. */
.btn:disabled, .btn[aria-disabled="true"] {
  opacity: 0.4;
  transform: none;
  cursor: not-allowed;
}
.btn:disabled:hover, .btn[aria-disabled="true"]:hover { background: var(--c-bg-inverse); }
.btn--accento:disabled:hover, .btn--accento[aria-disabled="true"]:hover { background: var(--accent); }
.btn--fantasma:disabled:hover, .btn--fantasma[aria-disabled="true"]:hover { background: var(--c-surface); }
.btn--pericolo:disabled:hover, .btn--pericolo[aria-disabled="true"]:hover { background: var(--kx-danger-500); }

/* CTA testuale: il pattern editoriale condiviso dai due studi — parola breve
   più segno rosso, mai un rettangolo pieno. Due varianti, perché i due siti
   usano una il filo sotto e l'altra la freccia. */
.cta {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--c-text);
  background: none;
  border: none;
  padding: 0;
  cursor: pointer;
  text-decoration: none;
}
.cta--filo { border-bottom: 2px solid var(--accent); padding-bottom: 0.15em; }
.cta--filo:hover { color: var(--accent); }
.cta--freccia::after {
  content: "\2192";
  color: var(--accent);
  transition: transform var(--durata-breve) var(--curva-standard);
}
.cta--freccia:hover::after { transform: translateX(0.3em); }

.riga-azioni { display: flex; flex-wrap: wrap; gap: var(--space-3); align-items: center; }

/* BARRA DELLE AZIONI di un riquadro (revisione viste 2026-10, T2): i bottoni in riga, mai impilati;
   il passo avanti a sinistra, ciò che cancella, storna o archivia spinto in fondo a destra. */
.barra-azioni { display: flex; flex-wrap: wrap; gap: var(--space-2); align-items: center; }
.barra-azioni > form { margin: 0; }
.barra-azioni-fondo { margin-left: auto !important; }

/* Una scelta e il suo bottone sulla stessa riga: il bottone allineato al campo, non all'etichetta. */
.campo-in-riga { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: var(--space-2); align-items: end; }
.campo-in-riga > .campo { margin: 0; }

/* Un form che contiene un solo pulsante non deve occupare una riga propria
   né aggiungere margini: serve solo a trasportare il metodo POST e il token
   CSRF, non è un blocco di layout. */
.form-inline { display: inline; margin: 0; }

/* Etichetta di un dato NON modificabile, con lo stesso aspetto di <label>:
   un <label> senza campo associato sarebbe un errore di accessibilità. */
.etichetta-statica {
  display: block;
  font-size: var(--text-sm);
  font-weight: 500;
  color: var(--c-text);
  margin-bottom: var(--space-2);
}

/* ===========================================================================
   MODULI
   =========================================================================== */
/* Etichetta e campo dell'Input del design system: etichetta in chiaro (non
   in maiuscoletto), campo alto 40px con raggio md; al fuoco il filo diventa
   inchiostro e compare l'anello dell'accento. */
label {
  display: block;
  font-size: var(--text-sm);
  font-weight: 500;
  color: var(--c-text);
  margin-bottom: var(--space-2);
}

/* `number` e `time` mancavano: nel contenzioso "Giorni", "Ora", "Numero RG" e "Anno" restavano
   caselle del browser, sottili e squadrate, accanto a campi arrotondati. Poi `month`, per lo stesso
   difetto nello scambio con la contabilità. */
input[type="text"], input[type="email"], input[type="password"],
input[type="search"], input[type="date"], input[type="number"], input[type="time"],
input[type="month"],
select, textarea {
  display: block;
  width: 100%;
  min-height: 2.5rem;
  font-family: var(--font-ui);
  font-size: 0.875rem;
  color: var(--c-text);
  background: var(--c-bg);
  border: 1px solid var(--c-border-strong);
  border-radius: var(--radius-md);
  padding: var(--space-2) 0.875rem;
  transition: border-color var(--durata-breve) var(--curva-standard), box-shadow var(--durata-breve) var(--curva-standard);
}

input:focus, select:focus, textarea:focus {
  outline: none;
  border-color: var(--c-text);
  box-shadow: var(--anello-focus);
}

textarea { resize: vertical; min-height: 7rem; line-height: var(--leading-normal); }

input[type="file"] {
  width: 100%;
  font-size: var(--text-sm);
  padding: var(--space-3);
  border: 1px dashed var(--c-border-strong);
  border-radius: var(--radius-md);
  background: var(--c-bg-sunken);
}

.campo { margin-bottom: var(--space-4); }
.campo:last-child { margin-bottom: 0; }
.campo-nota { font-size: var(--text-xs); color: var(--c-text-faint); margin-top: var(--space-2); }

/* Intestazione di un blocco di campi dentro un modulo lungo (anagrafica di un
   ente: registro imprese, fatturazione, dati economici). Un filo sopra invece
   di un riquadro: divide senza spezzare il modulo in schede, che a quel punto
   sembrerebbero salvabili una per una. */
.sezione-modulo {
  margin: var(--space-6) 0 var(--space-3);
  padding-top: var(--space-4);
  border-top: 1px solid var(--c-border);
  font-size: var(--text-md);
}
.sezione-modulo + .testo-piccolo { margin-top: calc(-1 * var(--space-2)); margin-bottom: var(--space-3); }
h4.sezione-modulo { font-size: var(--text-base); border-top: none; padding-top: 0; margin-top: var(--space-4); }

.campo-errore { font-size: var(--text-xs); color: var(--c-critico); margin-top: var(--space-2); font-weight: 600; }

.campi-affiancati {
  display: grid;
  gap: var(--space-4);
  grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
  /* Il gruppo si comporta come un campo solo verso l'esterno. Prima l'ultimo
     campo del gruppo perdeva il margine (`:last-child`) e il gruppo non ne
     aveva uno suo: 0px fra "Cognome" e il campo successivo, misurato nel
     riquadro della registrazione. Dentro, la spaziatura la dà solo `gap`. */
  margin-bottom: var(--space-4);
}
.campi-affiancati:last-child { margin-bottom: 0; }
.campi-affiancati > .campo { margin-bottom: 0; }

/* Barra filtri dell'elenco pratiche. */
.filtri {
  display: grid;
  gap: var(--space-3);
  grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
  align-items: end;
}
.filtri label { margin-bottom: var(--space-1); }
.filtri-azioni { display: flex; gap: var(--space-2); align-items: end; }
/* I bottoni dei filtri chiudono la riga a destra (revisione viste 2026-10, P2): prima cadevano nella
   prima cella libera, a metà riga sotto un filtro qualunque. Il contenitore dei filtri nascosti
   non occupa una cella. */
.filtri:has(> [data-elenco-nascosti]) > .filtri-azioni { grid-column: -2 / -1; justify-content: flex-end; }
.filtri > [data-elenco-nascosti] { display: contents; }

/* ===========================================================================
   AVVISI
   =========================================================================== */
.avviso {
  display: flex;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-md);
  border-left: 3px solid;
  font-size: var(--text-sm);
}
.avviso + .avviso { margin-top: var(--space-2); }
.avviso--successo { background: var(--c-positivo-bg); border-color: var(--c-positivo); color: var(--c-positivo); }
.avviso--errore { background: var(--c-critico-bg); border-color: var(--c-critico); color: var(--c-critico); }
.avviso--avviso { background: var(--c-attenzione-bg); border-color: var(--c-attenzione); color: var(--c-attenzione); }
.avviso--info { background: var(--c-info-bg); border-color: var(--c-info); color: var(--c-info); }

.zona-avvisi { margin-bottom: var(--space-5); }

/* ===========================================================================
   ETICHETTE DI STATO
   =========================================================================== */
/* Badge del design system: pillola alta 22px, testo in chiaro a peso 500,
   fondo tenue del proprio tono; il neutro è sulla nebbia (mist). */
.badge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: 22px;
  font-size: var(--text-xs);
  font-weight: 500;
  line-height: 1.2;
  padding: 0.125rem 9px;
  border-radius: var(--radius-pill);
  background: var(--kx-mist);
  color: var(--c-text-soft);
  border: 1px solid transparent;
  white-space: nowrap;
}

/* Il pallino porta il colore, lo sfondo resta neutro: sei badge a fondo
   pieno in una tabella la renderebbero illeggibile. Il colore serve a
   distinguerli a colpo d'occhio, non a decorarli. */
.badge::before {
  content: "";
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: currentColor;
  flex-shrink: 0;
}

.badge--aperta { color: var(--c-info); background: var(--c-info-bg); border-color: transparent; }
.badge--assegnata { color: var(--c-info); background: var(--c-info-bg); border-color: transparent; }
.badge--in_lavorazione { color: var(--c-attenzione); background: var(--c-attenzione-bg); border-color: transparent; }
.badge--bozza_emessa { color: var(--c-attenzione); background: var(--c-attenzione-bg); border-color: transparent; }
.badge--consegnata { color: var(--c-positivo); background: var(--c-positivo-bg); border-color: transparent; }
.badge--chiusa { color: var(--c-text-faint); background: var(--kx-mist); }

/* Priorità: nessun pallino, è un'informazione di secondo livello rispetto
   allo stato e non deve competere con esso nello stesso sguardo. */
.priorita { border-radius: var(--radius); }
.priorita::before { display: none; }
.priorita--bassa { color: var(--c-text-faint); }
.priorita--normale { color: var(--c-text-soft); }
.priorita--alta { color: var(--c-attenzione); background: var(--c-attenzione-bg); border-color: transparent; }
.priorita--urgente { color: #fff; background: var(--c-critico); border-color: transparent; }

.scadenza-critica { color: var(--c-critico); font-weight: 700; }
.scadenza-vicina { color: var(--c-attenzione); font-weight: 600; }
/* Ritardo di una consegna GIÀ AVVENUTA: un fatto storico, non un allarme su
   cui agire. Stesso colore del critico ma senza grassetto, così una riga
   archiviata non grida quanto una pratica ancora in ritardo. */
.scadenza-storica-ritardo { color: var(--c-critico); }

/* ===========================================================================
   TABELLE
   =========================================================================== */
/* Il contenitore con overflow orizzontale è ciò che rende una tabella densa
   usabile su telefono senza riprogettarla a schede: si scorre lateralmente
   invece di comprimere le colonne fino a renderle illeggibili. */
.tabella-contenitore {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}

table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--text-sm);
}

thead th {
  text-align: left;
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: var(--tracking-wide);
  color: var(--c-text-faint);
  font-weight: 700;
  padding: var(--pad-riga) var(--space-4);
  border-bottom: 1px solid var(--c-border-strong);
  white-space: nowrap;
  background: var(--c-bg);
}

tbody td {
  padding: var(--pad-cella) var(--space-4);
  border-bottom: var(--bordo);
  vertical-align: middle;
}

tbody tr:last-child td { border-bottom: none; }
tbody tr { transition: background var(--durata-breve) var(--curva-standard); }
tbody tr:hover { background: var(--c-bg-sunken); }

.cella-titolo { font-weight: 600; }
.cella-titolo a { text-decoration: none; }
.cella-titolo a:hover { color: var(--accent); }
.cella-riferimento {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--c-text-faint);
  white-space: nowrap;
}
.cella-azioni { text-align: right; white-space: nowrap; }

/* Riga di una pratica in ritardo: un filo rosso a sinistra, non un fondo
   colorato — dieci righe in ritardo non devono rendere illeggibile la
   tabella intera. */
tbody tr.riga--scaduta td:first-child { box-shadow: inset 3px 0 0 var(--c-critico); }

/* Elenco delle pratiche: LARGHEZZE MINIME delle colonne di testo.
   Difetto trovato MISURANDO a 380, 600 e 900px (e presente fino a 1200).
   Una tabella in layout automatico, quando lo spazio non basta, stringe ogni
   colonna fino al suo min-content, cioè alla PAROLA più lunga: "(fra 19
   giorni)" finiva in 35px, una parola per riga, e una riga di tabella
   arrivava a 137px d'altezza. Intanto le intestazioni, che non vanno a capo,
   tenevano larghe colonne quasi vuote ("Riferimento interno" 186px sopra
   "Sara Gallo").
   Con un minimo per colonna la tabella smette di stringersi prima di
   diventare illeggibile e, sotto quella soglia, SCORRE di lato dentro
   `.tabella-contenitore` — che è esattamente la promessa scritta sopra per
   quel contenitore, e che il layout automatico non manteneva.
   I minimi sono in rem e non in percentuale: devono dire "quanto testo ci
   sta", non "che fetta dello schermo prende". Tarati MISURANDO perché la
   tabella stia intera a 1280px di finestra con la colonna aperta (975px su
   975): alzarli fa scorrere la tabella anche su un portatile comune.
   Alternativa scartata: righe
   trasformate in schede sotto una certa larghezza — è una seconda
   impaginazione dello stesso elenco da tenere allineata alla prima. */
.tabella-pratiche thead th { white-space: normal; }
.tabella-pratiche .cella-titolo { min-width: 11rem; }
.tabella-pratiche .cella-area,
.tabella-pratiche .cella-persona,
.tabella-pratiche .cella-scadenza { min-width: 7.5rem; }
/* Il secondo dato di una cella (il referente sotto l'ente, la frase sotto la
   data di scadenza) va su una riga sua invece di mescolarsi al primo. */
.cella-sottoriga,
.tabella-pratiche .cella-scadenza .testo-minuscolo { display: block; }

/* ===========================================================================
   STATO VUOTO
   =========================================================================== */
.vuoto {
  text-align: center;
  padding: var(--space-7) var(--space-5);
  color: var(--c-text-soft);
}
.vuoto-titolo { font-family: var(--font-display); font-size: var(--text-lg); color: var(--c-text); margin-bottom: var(--space-2); }

/* ===========================================================================
   PAGINAZIONE
   =========================================================================== */
.paginazione {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  flex-wrap: wrap;
}
.paginazione-stato { font-size: var(--text-sm); color: var(--c-text-soft); }
.paginazione-link { display: flex; gap: var(--space-2); }

/* ===========================================================================
   CONVERSAZIONE
   =========================================================================== */
.thread { list-style: none; margin: 0; padding: 0; }

.messaggio {
  display: flex;
  gap: var(--space-4);
  padding: var(--space-4) 0;
  border-bottom: var(--bordo);
}
.messaggio:last-child { border-bottom: none; }

.messaggio-testa {
  display: flex;
  align-items: baseline;
  gap: var(--space-3);
  flex-wrap: wrap;
  margin-bottom: var(--space-2);
}
.messaggio-autore { font-weight: 600; }
.messaggio-data { font-size: var(--text-xs); color: var(--c-text-faint); }
/* `pre-wrap` conserva gli a capo digitati dall'utente senza usare innerHTML
   né sostituire "\n" con <br>: il testo resta testo, e l'unica difesa XSS
   che serve continua a essere l'escaping. */
.messaggio-corpo { white-space: pre-wrap; margin: 0; }

.messaggio-contenuto { min-width: 0; flex: 1; }

/* Un messaggio appena arrivato via WebSocket si evidenzia per qualche
   secondo: senza, un messaggio appeso in fondo a un thread lungo passa
   inosservato proprio in tempo reale. */
.messaggio--nuovo { animation: entra var(--durata-evidenzia) var(--curva-standard); }
@keyframes entra {
  from { background: var(--accent-tenue); }
  to { background: transparent; }
}

/* ===========================================================================
   DOCUMENTI
   =========================================================================== */
.documenti { list-style: none; margin: 0; padding: 0; }

.documento {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--pad-riga) 0;
  border-bottom: var(--bordo);
}
.documento:last-child { border-bottom: none; }

.documento-icona {
  display: grid;
  place-items: center;
  width: 2.25rem;
  height: 2.75rem;
  flex-shrink: 0;
  border: var(--bordo);
  border-radius: var(--radius);
  background: var(--c-bg-sunken);
  font-size: 0.625rem;
  font-weight: 700;
  letter-spacing: 0.02em;
  color: var(--c-text-faint);
  text-transform: uppercase;
}
.documento-dati { min-width: 0; flex: 1; }
.documento-nome { font-weight: 600; text-decoration: none; word-break: break-word; }
.documento-nome:hover { color: var(--accent); }
.documento-meta { font-size: var(--text-xs); color: var(--c-text-faint); }

/* ===========================================================================
   DIARIO DELLA PRATICA
   =========================================================================== */
.diario { list-style: none; margin: 0; padding: 0; position: relative; }

/* Il filo verticale continuo è disegnato con un bordo sull'elemento, non con
   uno pseudo-elemento per riga: una sola regola invece di una per voce, e
   nessun problema di allineamento quando le righe hanno altezze diverse. */
.diario-voce {
  position: relative;
  padding: 0 0 var(--space-4) var(--space-5);
  border-left: 1px solid var(--c-border);
}
.diario-voce:last-child { border-left-color: transparent; padding-bottom: 0; }

.diario-voce::before {
  content: "";
  position: absolute;
  left: -0.3125rem;
  top: 0.4rem;
  width: 0.5625rem;
  height: 0.5625rem;
  border-radius: 50%;
  background: var(--c-bg);
  border: 2px solid var(--c-border-strong);
}
.diario-voce:first-child::before { border-color: var(--accent); }

.diario-tipo { font-weight: 600; font-size: var(--text-sm); }
.diario-dettaglio { font-size: var(--text-sm); color: var(--c-text-soft); margin: 0; }
.diario-data { font-size: var(--text-xs); color: var(--c-text-faint); }

/* ===========================================================================
   LA PRATICA — barra delle schede e cronologia unificata (fase 3)
   =========================================================================== */

/* Le linguette sono LINK a indirizzi veri, non pulsanti che mostrano e
   nascondono pannelli: lo stile deve quindi somigliare a una navigazione, non
   a un gruppo di bottoni. Filo sotto la voce attiva, come le voci della
   vecchia barra: è la convenzione che tutti riconoscono, e non chiede colore
   di sfondo. */
.schede {
  margin-top: var(--space-5);
}

/* UNA RIGA CHE SCORRE, non una riga che va a capo — difetto trovato
   MISURANDO a 380px. Con `flex-wrap: wrap` le sette linguette della pratica
   finivano su due righe, il filo inferiore correva solo sotto la seconda e la
   voce attiva, sulla prima, restava sospesa nel vuoto: sembrava un menu
   rotto. Una fila di linguette si legge come UNA fila; quando non ci sta si
   scorre di lato, come fanno tutte le barre a schede su telefono, e la
   linguetta tagliata al bordo dice da sola che ce ne sono altre.

   Il bordo inferiore corre sotto tutte le linguette e la voce attiva lo
   "buca" con il proprio filo colorato: un contorno completo attorno alla
   linguetta attiva la farebbe sembrare un pulsante premuto. È un'ombra
   INTERNA e non un `border-bottom` su .schede, perché un contenitore che
   scorre ritaglia ciò che deborda: il vecchio trucco del `margin-bottom:
   -1px` sulla voce (filo sopra il bordo del genitore) verrebbe tagliato. Le
   linguette si dipingono sopra lo sfondo del loro contenitore, ombra interna
   compresa, quindi il filo attivo la copre senza trucchi. */
.schede-voci {
  display: flex;
  gap: var(--space-5);
  list-style: none;
  margin: 0;
  padding: 0;
  overflow-x: auto;
  scrollbar-width: thin;
  box-shadow: inset 0 -1px 0 var(--c-border);
}
.schede-voci > li { flex-shrink: 0; }

.schede-voce {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-3) 0;
  /* 2px riservati anche da spenta: senza, la linguetta attiva si
     alzerebbe di 2px rispetto alle vicine. Stessa ragione della voce di
     navigazione nella colonna. */
  border-bottom: 2px solid transparent;
  color: var(--c-text-soft);
  text-decoration: none;
  font-size: 0.875rem;
  font-weight: 500;
  white-space: nowrap;
  transition: color var(--durata-breve) var(--curva-standard),
              border-color var(--durata-breve) var(--curva-standard);
}
.schede-voce:hover { color: var(--c-text); }
/* Tabs del design system: la linguetta attiva è sottolineata in inchiostro,
   non nell'accento. */
.schede-voce[aria-current="page"] {
  color: var(--c-text);
  border-bottom-color: var(--c-text);
}

/* Il numero accanto alla linguetta: neutro, perché conta cose (documenti) e
   non allarmi. I non letti delle conversazioni sono l'eccezione e si
   distinguono per il contesto, non per il colore — che è già usato dai badge
   di stato e non deve diventare un secondo vocabolario. */
.schede-conteggio {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 1.25rem;
  height: 1.25rem;
  padding-inline: 0.3rem;
  border-radius: var(--radius-pill);
  background: var(--c-bg-sunken);
  border: var(--bordo);
  color: var(--c-text-soft);
  font-size: var(--text-xs);
  font-weight: 700;
  line-height: 1;
}
.schede-voce[aria-current="page"] .schede-conteggio {
  background: var(--accent-tenue);
  border-color: var(--accent-tenue);
  color: var(--accent-scuro);
}

/* Un blocco che comincia dopo una riga di stacco: si usa dove due moduli
   distinti vivono nella stessa scheda e il secondo non e' la continuazione
   del primo (console: dati dell'admin, poi la delega). Un bordo e non un
   `<hr>`, che nel progetto non compare da nessun'altra parte e avrebbe
   richiesto una regola propria per un caso solo. */
.blocco-separato {
  margin-top: var(--space-5);
  padding-top: var(--space-5);
  border-top: var(--bordo);
}

/* ===========================================================================
   SVAGO — attività ospitate
   ===========================================================================

   Vale la regola di registro della fase 9: **la leggerezza sta nel contenuto,
   non nei token**. Qui è letterale — il contenuto è di qualcun altro, la
   cornice è la nostra di sempre. Nessun colore, ombra o durata scritti a
   mano: un test in `tests/svago.test.ts` lo verifica su ogni regola
   `.svago*`, ed è la ragione per cui questa sezione è corta. */

.svago-riquadro {
  /* La proporzione la porta la voce del catalogo: un simulatore di acquerello
     vuole un foglio, un sistema solare vuole un panorama. Il valore arriva da
     `--svago-proporzione`, scritta dal JavaScript quando crea l'iframe; il
     ripiego serve all'invito, che c'è anche prima. */
  aspect-ratio: var(--svago-proporzione, 16 / 9);
  display: grid;
  place-items: center;
  background: var(--c-bg-sunken);
  border-bottom: var(--bordo);
}

/* A tutto schermo il riquadro diventa la finestra: il fondo scuro toglie di
   mezzo la stanza attorno, che è il punto di andare a tutto schermo. */
.svago-riquadro:fullscreen {
  aspect-ratio: auto;
  background: var(--c-bg-inverse);
}

.svago-telaio {
  width: 100%;
  height: 100%;
  border: 0;
  display: block;
}

.svago-invito {
  display: grid;
  gap: var(--space-3);
  justify-items: center;
  text-align: center;
  max-width: 34rem;
  padding: var(--space-5);
}

.svago-invito-titolo {
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--text-lg);
}

.svago-crediti {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
}

/* ===========================================================================
   AREE CLICCABILI (fase 8)
   ===========================================================================

   Le WCAG 2.2 chiedono un bersaglio di almeno 24x24 px (SC 2.5.8), con due
   scappatoie che qui non valgono: lo spazio libero attorno — le righe di un
   elenco sono adiacenti — e i link "in linea" dentro una frase, che il titolo
   di una pratica non è.

   MISURATO prima di toccare qualcosa: il titolo di una pratica nell'elenco
   era alto 17px, ed è il comando più usato di tutta l'applicazione.

   La correzione NON ingrandisce il testo e NON ingrassa le righe: sarebbe
   stato disfare la densità della fase 7 il giorno dopo averla fatta. Si
   allarga l'area SENSIBILE, non il disegno. */

/* --- Il link di riga copre la sua cella ---------------------------------- */
/*
   Dove la riga ha UN SOLO comando — il titolo, che apre il fascicolo — quel
   link si estende con uno strato invisibile su tutta la cella. Nessuno
   spostamento di pixel, e il bersaglio passa da 17px di altezza all'intera
   riga: è anche il gesto che ci si aspetta da un elenco, dove si mira alla
   riga e non alla parola.

   Vale solo dove il comando è UNO: con due link nella stessa cella lo strato
   di sopra ruberebbe i clic all'altro. Chi aggiunge un secondo link a una di
   queste celle deve togliere la regola, non aggirarla.
*/
.cella-titolo { position: relative; }
.cella-titolo > a::after {
  content: "";
  position: absolute;
  inset: 0;
}

.lista-pratiche-voce { position: relative; }
.lista-pratiche-titolo::after {
  content: "";
  position: absolute;
  inset: 0;
}
/* I badge e le date della riga restano sopra lo strato: non sono comandi, ma
   devono potersi selezionare col mouse per copiarli. */
.lista-pratiche-meta { position: relative; }

/* --- Bersagli minimi dove l'area non si può estendere --------------------- */
/* Una linguetta con un'etichetta corta ("Ore") era larga 21px, una con
   un'etichetta lunga ben di più: la dimensione del bersaglio dipendeva dalla
   parola, che è un criterio arbitrario. */
.schede-voce { min-width: 2.5rem; justify-content: center; }

/* Casella di spunta con la sua etichetta. La casella disegnata dal sistema è
   13x13px e non si ingrandisce senza ridisegnarla a mano; quello che si può
   fare — ed è anche la cosa giusta — è rendere generosa l'ETICHETTA, che
   commuta la casella esattamente come la casella. `.campo-scelta` non aveva
   nessuna regola: le due parti stavano una accanto all'altra con lo spazio
   che capita fra due elementi in linea. */
.campo-scelta {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
}
.campo-scelta label {
  display: inline-flex;
  align-items: center;
  min-height: 1.5rem;
  cursor: pointer;
}
/* Un ELENCO di caselle (i fattori di rischio dell'adeguata verifica): una per riga,
   anche le brevi — in linea salivano accanto alla precedente — e l'etichetta in testo
   corrente, perché è una frase da leggere e non il nome di un campo. In blocco, non in
   flex: un contenitore flex mangia lo spazio prima del "—" della nota. */
.elenco-scelte { display: grid; gap: var(--space-2); margin-bottom: var(--space-4); }
.elenco-scelte .campo-scelta { display: flex; align-items: baseline; }
.elenco-scelte .campo-scelta label {
  display: block;
  font-size: var(--text-sm);
  font-weight: 400;
  text-transform: none;
  letter-spacing: normal;
  color: var(--c-text);
}

/* Filo di Arianna: voci adiacenti a 8px l'una dall'altra, quindi la deroga
   sullo spazio libero non si applica. Il padding cresce verso l'alto e verso
   il basso dentro una riga che ha già il suo margine: il disegno non cambia,
   l'area sì. */
.briciole a {
  display: inline-block;
  padding-block: var(--space-1);
}

/*
   Le CTA testuali erano alte 20,8px. Da sole passerebbero per la deroga sullo
   spazio libero — nel dettaglio di una pratica il comando più vicino è a
   44px. Sul cruscotto no: il "vedi tutte" dell'intestazione sta a 17px dalla
   prima riga dell'elenco sotto, e dopo la regola qui sopra quella riga è
   diventata un bersaglio alto quanto tutta la voce. È un difetto che ha
   creato questa stessa fase, trovato rimisurando: allargare un bersaglio
   avvicina i suoi vicini.

   L'area cresce SOLO VERSO L'ALTO, e il margine negativo la restituisce al
   layout. Due ragioni, una per direzione:
   - verso l'alto e non verso il basso perché la variante col filo disegna il
     tratto dell'accento sul bordo inferiore della scatola: un padding sotto
     lo staccherebbe dalle lettere;
   - col margine negativo perché la prima versione di questa regola era un
     `min-height`, e MISURANDOLA costava 3,2px per intestazione, 13px sul
     cruscotto. Pochi, ma è altezza pagata per qualcosa che non si vede: qui
     l'area sensibile deborda e la scatola resta dov'era. Zero pixel di
     differenza, verificato. */
.cta {
  padding-top: 4px;
  margin-top: -4px;
}

/* ===========================================================================
   DENSITÀ E MODALITÀ FOCUS (fase 7)
   ===========================================================================

   Due preferenze di chi guarda, non del documento: vivono in `localStorage`
   (per browser, come la colonna ridotta) e le applica `main.js` scrivendo un
   attributo. Nessuna delle due cambia i DATI, e nessuna è ricordata dal
   server: sono gli occhi e lo schermo di quella persona. */

/* --- Densità compatta ---------------------------------------------------- */
/* Tre token e basta. Ciò che si stringe è il ritmo VERTICALE di schede,
   tabelle ed elenchi — i punti in cui si guardano venti righe di seguito.
   Il testo non rimpicciolisce: una riga più bassa si legge lo stesso, un
   carattere più piccolo no, e questa è una differenza che si sente dopo due
   ore sulla stessa pagina. */
[data-densita="compatta"] {
  --pad-scheda: var(--space-2) var(--space-5);
  --pad-scheda-corpo: var(--space-4) var(--space-5);
  --pad-cella: var(--space-2);
  --pad-riga: var(--space-2);
}

/* --- Modalità focus ------------------------------------------------------ */
/*
   Toglie la cornice e lascia il lavoro: niente colonna di navigazione, niente
   piè di pagina, contenitore più largo. Serve a chi sta ore sulla stessa
   pagina — e **è il rimedio dichiarato** al rischio annotato con la sezione
   Svago: quando si condivide lo schermo con un cliente, la colonna sparisce
   insieme a tutto il resto del contorno.

   Il pulsante "Menu" resta nella testata: la colonna si riapre da lì senza
   uscire dalla modalità, esattamente come quando è ridotta. */
.telaio[data-focus="attiva"] {
  /* Più larghezza per le tabelle dense: è il motivo per cui si entra in
     modalità focus su una pagina di fatture o di ore. */
  --larghezza-max: 96rem;
}
.telaio[data-focus="attiva"] .telaio-laterale { display: none; }
.telaio[data-focus="attiva"] .telaio-menu { display: inline-flex; }
.telaio[data-focus="attiva"] .pie { display: none; }

/* La modalità tocca SOLO ciò che il telaio possiede — la sua colonna e il suo
   piè di pagina — e non entra mai dentro `<main>`. Una versione precedente
   nascondeva anche la striscia "Riprendi dove eri" del cruscotto, considerandola
   decorazione: sbagliato, è l'unico modo di raggiungere quelle pratiche, e
   nasconderla in una pagina che serve proprio a navigare contraddice la regola
   per cui il pulsante "Menu" resta visibile. Il confine è netto e si spiega in
   una riga: togliamo la cornice, non il contenuto. */

@media (min-width: 60.0625rem) {
  .telaio[data-focus="attiva"] { grid-template-columns: minmax(0, 1fr); }
}

/* --- Il pannello "Vista" ------------------------------------------------- */
/* `<details>` nativo: apre e chiude senza JavaScript e senza stato da
   gestire. Gli interruttori dentro, invece, servono JavaScript (scrivono in
   localStorage), quindi il pannello nasce `hidden` e lo rivela `main.js` —
   un controllo che non fa nulla è peggio di un controllo assente. */
.vista { position: relative; }

.vista > summary {
  list-style: none;
  cursor: pointer;
  padding: var(--space-2) var(--space-3);
  border: var(--bordo);
  border-radius: var(--radius-pill);
  font-size: var(--text-sm);
  font-weight: 500;
  color: var(--c-text-soft);
  white-space: nowrap;
}
.vista > summary::-webkit-details-marker { display: none; }
.vista > summary:hover { background: var(--c-bg-sunken); color: var(--c-text); }
.vista[open] > summary { background: var(--c-bg-sunken); color: var(--c-text); }

.vista-pannello {
  position: absolute;
  top: calc(100% + var(--space-2));
  right: 0;
  z-index: var(--z-comandi);
  min-width: 15rem;
  padding: var(--space-4);
  display: grid;
  gap: var(--space-4);
  background: var(--c-bg);
  border: var(--bordo);
  border-radius: var(--radius);
  box-shadow: var(--ombra-media);
}

.vista-gruppo { display: grid; gap: var(--space-2); }
.vista-titolo {
  margin: 0;
  font-size: var(--text-xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: var(--tracking-wider);
  color: var(--c-text-faint);
}
.vista-scelte { display: flex; gap: var(--space-2); }

.vista-scelta {
  flex: 1 1 auto;
  padding: var(--space-2) var(--space-3);
  background: none;
  border: var(--bordo);
  border-radius: var(--radius);
  font: inherit;
  font-size: var(--text-sm);
  cursor: pointer;
  transition: background var(--durata-breve) var(--curva-standard),
              border-color var(--durata-breve) var(--curva-standard);
}
.vista-scelta:hover { background: var(--c-bg-sunken); }
/* Lo stato attivo è `aria-pressed`, l'attributo che un lettore di schermo
   annuncia: una classe sarebbe la stessa informazione scritta due volte. */
.vista-scelta[aria-pressed="true"] {
  background: var(--accent-tenue);
  border-color: var(--accent);
  font-weight: 600;
}

.vista-nota { margin: 0; font-size: var(--text-xs); color: var(--c-text-faint); }

/* --- Il menu dell'utente (avatar) ---------------------------------------- */
/* Stesso disegno del pannello "Vista" — riepilogo nella testata, pannello
   sospeso sotto, allineato a destra — perché sono due oggetti dello stesso
   tipo nella stessa barra: se si aprissero in due modi diversi, uno dei due
   sembrerebbe un errore. */
.utente-menu { position: relative; }

.utente-riepilogo {
  list-style: none;
  display: flex;
  align-items: center;
  gap: var(--space-3);
  /* Nessun margine verticale: l'avatar è già alto quanto i pulsanti accanto,
     e 4px sopra e sotto alzavano l'intera testata di 8px. */
  padding: 0 var(--space-2);
  border-radius: var(--radius);
  cursor: pointer;
  transition: background var(--durata-breve) var(--curva-standard);
}
.utente-riepilogo::-webkit-details-marker { display: none; }
.utente-riepilogo:hover,
.utente-menu[open] > .utente-riepilogo { background: var(--c-bg-sunken); }

.utente-pannello {
  position: absolute;
  top: calc(100% + var(--space-2));
  right: 0;
  z-index: var(--z-comandi);
  min-width: 12rem;
  padding: var(--space-2);
  display: grid;
  gap: var(--space-1);
  background: var(--c-bg);
  border: var(--bordo);
  border-radius: var(--radius);
  box-shadow: var(--ombra-media);
}
.utente-pannello form { margin: 0; }

/* Una voce di menu, che sia un link (Cambia password) o il pulsante di un
   form (Esci): stesso aspetto, perché per chi la usa è la stessa cosa — una
   riga da toccare. */
.utente-voce {
  display: block;
  width: 100%;
  padding: var(--space-2) var(--space-3);
  background: none;
  border: 0;
  border-radius: var(--radius);
  font: inherit;
  font-size: var(--text-sm);
  text-align: left;
  color: var(--c-text);
  text-decoration: none;
  cursor: pointer;
}
.utente-voce:hover { background: var(--c-bg-sunken); }

/* ===========================================================================
   FEEDBACK E MOVIMENTO (fase 6)
   ===========================================================================

   Tre cose, e una regola che le tiene insieme: il movimento spiega ORIGINE e
   DESTINAZIONE, non decora. Se un'animazione non risponde a "da dove viene
   questa cosa" o "dove è finita", non serve. */

/* --- 1. La traccia sull'elemento che è cambiato -------------------------- */
/*
   Il Post/Redirect/Get resta (è un principio del progetto), quindi dopo
   un'azione si arriva su una pagina nuova con la conferma in cima. Ma "Tempo
   registrato" non dice QUALE delle venti righe è quella: la riga toccata si
   accende per un istante e poi torna normale.

   Un'animazione e non uno stato permanente: deve dire "guarda qui, adesso",
   non marcare la riga finché qualcuno non la toglie. Dura
   `--durata-evidenzia` (1,8s), che è il token nato apposta per "questo è
   cambiato: si guarda, non si usa".

   L'attributo lo scrive il SERVER (`data-appena-cambiato`, dalla chiave
   consumata dalla sessione): nessun JavaScript, e la cosa funziona anche per
   chi lo ha disattivato. */
/* Riusa `entra`, il fotogramma già definito più sotto per le bolle di chat
   appena arrivate: è la stessa idea — un velo dell'accento che svanisce — e
   due keyframes identici con due nomi diversi sarebbero due cose da tenere
   allineate. */
[data-appena-cambiato] {
  animation: entra var(--durata-evidenzia) var(--curva-standard);
}

/* Chi ha chiesto meno animazioni non vede il lampeggio — il blocco globale
   `prefers-reduced-motion` azzera la durata — e non perde nulla: la conferma
   in cima alla pagina resta, ed è quella primaria. Qui si dà comunque un
   segno statico, che non si muove: un filo a sinistra per qualche istante
   non è possibile senza animazione, quindi resta il solo messaggio. */

/* --- 2. Scheletro di caricamento ---------------------------------------- */
/*
   Solo dove chi aspetta guarda il VUOTO. L'elenco pratiche non ce l'ha di
   proposito: là la cornice resta e i risultati si attenuano ("mantieni la
   cornice", vedi elenco-pratiche.js) — uno scheletro al posto di dati già
   visibili sarebbe un passo indietro, non avanti.

   Lo scheletro serve alla BARRA COMANDI, dove il pannello si apre su niente
   mentre la risposta arriva. */
.scheletro {
  /* `color-mix` no: il progetto non ha altre occorrenze e il colore va
     definito in modo che un tema possa cambiarlo. Il grigio della superficie
     incassata è già quello giusto. */
  background: var(--c-bg-sunken);
  border-radius: var(--radius);
  /* L'altezza la decide chi lo usa: una riga di testo, un titolo, un blocco. */
  height: 0.85rem;
  animation: scheletro-respiro var(--durata-evidenzia) var(--curva-standard) infinite;
}
@keyframes scheletro-respiro {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.45; }
}

.scheletro--titolo { height: 1.05rem; width: 45%; }
.scheletro--riga { width: 80%; }
.scheletro--corta { width: 30%; }

.comandi-scheletro { padding: var(--space-3) var(--space-4); display: grid; gap: var(--space-2); }
.comandi-scheletro + .comandi-scheletro { border-top: var(--bordo); }

/* --- 3. La riga che compare --------------------------------------------- */
/*
   Un documento che arriva in tempo reale (o alla fine di un caricamento)
   compare in fondo a un elenco che l'utente sta già guardando: senza un
   accenno di movimento, la pagina "salta" e non si capisce che cosa sia
   cambiato. Stessa animazione già usata dalle bolle di chat: entra dal basso
   di pochi pixel e si rivela.

   Il nome della classe dice quando si applica, non che cosa fa: la scrive
   `pratica.js` sugli elementi che ha appena aggiunto. */
.documento--nuovo { animation: entra var(--durata-media) var(--curva-rivela); }

/* --- Lo stato detto al cliente (fase 5) ---------------------------------- */
/* Non una card ma una fascia: risponde alla prima domanda e poi si toglie di
   mezzo. Il bordo a sinistra dice DI CHI È LA MOSSA — l'unica informazione
   che un badge di stato non porta mai — e il colore non è l'unico portatore:
   la frase lo dice a parole. */
.stato-cliente {
  padding: var(--space-4) var(--space-5);
  background: var(--c-surface);
  border: var(--bordo);
  border-left: 3px solid var(--c-border-strong);
  border-radius: var(--radius);
}
/* Tocca allo studio: nessuna urgenza per chi legge, tono neutro. */
.stato-cliente[data-tocca="studio"] { border-left-color: var(--grafico-serie-2); }
/* Tocca al cliente: è l'unico caso in cui la pagina gli sta chiedendo qualcosa. */
.stato-cliente[data-tocca="cliente"] { border-left-color: var(--accent); background: var(--accent-tenue); }
.stato-cliente[data-tocca="nessuno"] { border-left-color: var(--c-border-strong); }

.stato-cliente-frase {
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--text-md);
  line-height: var(--leading-snug);
}
.stato-cliente-attesa { margin: var(--space-2) 0 0; font-size: var(--text-sm); color: var(--c-text-soft); }

/* --- Gerarchia delle Statistiche (fase 4) -------------------------------- */
/* Undici sezioni allo stesso livello non dicono quali rispondono alla stessa
   domanda. Tre gruppi con un titolo, e un indice che ci salta.

   ANCORE e non schede, qui: le sezioni delle statistiche si LEGGONO INSIEME
   (la puntualità del team accanto al carico, il carico accanto alle ore), e
   spezzarle in pagine separate spezzerebbe il confronto che la pagina esiste
   per permettere. */
.indice-sezioni {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-4);
  font-size: var(--text-sm);
}
.indice-sezioni a {
  color: var(--c-text-soft);
  text-decoration: none;
  border-bottom: 1px solid var(--c-border-strong);
  padding-bottom: 2px;
}
.indice-sezioni a:hover { color: var(--c-text); border-bottom-color: var(--accent); }

/* Il titolo di gruppo non è una scheda: è un'intestazione sopra le schede,
   quindi niente sfondo né bordo — solo il registro tipografico dei titoli. */
.titolo-gruppo {
  margin: var(--space-5) 0 0;
  font-family: var(--font-display);
  font-size: var(--text-lg);
  font-weight: 500;
  /* `scroll-margin-top`: l'indice salta qui, e senza questo il titolo
     finirebbe sotto la testata appiccicata in alto. Misurata sulla somma di
     testata (3,75rem) e filo del brand, con un po' d'aria. */
  scroll-margin-top: 5.5rem;
}
.titolo-gruppo:first-of-type { margin-top: 0; }

/* --- Quadro di conformità (scheda cliente, fase 4) ----------------------- */
/* Una striscia, non una scheda: dice lo STATO di due adempimenti e porta
   dov'è la sostanza. Se fosse una card avrebbe lo stesso peso visivo delle
   sezioni vere, e la scheda Anagrafica tornerebbe ad avere due protagonisti. */
.quadro-conformita {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--space-5);
  padding: var(--space-3) var(--space-5);
  background: var(--c-bg);
  border: var(--bordo);
  border-left: 3px solid var(--c-border-strong);
  border-radius: var(--radius);
  font-size: var(--text-sm);
}
.quadro-conformita-voce { display: flex; align-items: baseline; gap: var(--space-2); }
.quadro-conformita .cta { margin-left: auto; }

/* Il tono "tutto a posto". Esisteva il rosso e l'ambra (scadenza-critica,
   scadenza-vicina) ma non il verde: un quadro che può solo allarmare non è un
   quadro, è un avviso. */
.stato-positivo { color: var(--c-positivo); font-weight: 600; }

/* --- Cronologia unificata ----------------------------------------------- */
/* Stesso filo verticale del diario, ma disegnato con un elemento dedicato
   (`.cronologia-segno`) invece di uno pseudo-elemento: qui il pallino cambia
   aspetto in base alla FONTE della voce, e uno pseudo-elemento non può
   portare un attributo da cui lo stile legga quale sia. */
.cronologia {
  list-style: none;
  margin: 0;
  padding: var(--space-4) var(--space-5);
}

.cronologia-voce {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: var(--space-4);
  padding-bottom: var(--space-4);
}
.cronologia-voce:last-child { padding-bottom: 0; }

/* Il segno: un filo che scende e un pallino. Il filo è un bordo sinistro
   sull'elemento, quindi si allunga da sé quando la voce è alta. */
.cronologia-segno {
  position: relative;
  width: 0;
  border-left: 1px solid var(--c-border);
  margin-left: 0.28rem;
}
.cronologia-voce:last-child .cronologia-segno { border-left-color: transparent; }

.cronologia-segno::before {
  content: "";
  position: absolute;
  left: -0.31rem;
  top: 0.35rem;
  width: 0.5625rem;
  height: 0.5625rem;
  border-radius: 50%;
  background: var(--c-bg);
  border: 2px solid var(--c-border-strong);
}

/* La FONTE distingue i pallini, ma non è l'unica informazione: ogni voce dice
   a parole che cosa è successo ("Messaggio interno", "45 minuti registrati").
   Il colore aiuta a scorrere, non a capire — e la pagina resta leggibile in
   bianco e nero. */
.cronologia-voce[data-fonte="pratica"] .cronologia-segno::before { border-color: var(--accent); }
.cronologia-voce[data-fonte="conversazione"] .cronologia-segno::before { border-color: var(--grafico-serie-2); }
.cronologia-voce[data-fonte="ore"] .cronologia-segno::before {
  /* Le ore sono l'unica fonte "piena": sono un consumo, non un evento, e nel
     leggere una cronologia si vuole distinguerle a colpo d'occhio. */
  background: var(--c-border-strong);
  border-color: var(--c-border-strong);
}

.cronologia-titolo { margin: 0; font-weight: 600; font-size: var(--text-sm); }
.cronologia-dettaglio { margin: var(--space-1) 0 0; font-size: var(--text-sm); color: var(--c-text-soft); }
.cronologia-meta {
  margin: var(--space-1) 0 0;
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  font-size: var(--text-xs);
  color: var(--c-text-faint);
}

/* ===========================================================================
   NOTIFICHE
   =========================================================================== */
.notifiche { list-style: none; margin: 0; padding: 0; }

.notifica {
  display: flex;
  align-items: flex-start;
  gap: var(--space-4);
  padding: var(--space-4) var(--space-5);
  border-bottom: var(--bordo);
}
.notifica:last-child { border-bottom: none; }
/* Non letta: fondo appena diverso più un filo cremisi. Il grassetto da solo
   non basterebbe a distinguerle in un elenco lungo. */
.notifica--non-letta { background: var(--accent-tenue); box-shadow: inset 3px 0 0 var(--accent); }
.notifica-testo { margin: 0; }
.notifica-meta { font-size: var(--text-xs); color: var(--c-text-faint); margin-top: var(--space-1); }
.notifica-azioni { margin-left: auto; display: flex; gap: var(--space-2); flex-shrink: 0; }

/* ===========================================================================
   ELENCHI DESCRITTIVI
   =========================================================================== */
.dati { margin: 0; display: grid; gap: var(--space-3); }
.dati-voce { display: grid; gap: var(--space-1); }
.dati-etichetta {
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: var(--tracking-wide);
  color: var(--c-text-faint);
  font-weight: 600;
}
.dati-valore { margin: 0; font-weight: 500; }

/* Prospetto di una parcella (revisione viste 2026-10, F1): etichetta e importo sulla stessa riga,
   importi incolonnati a destra come su una fattura; i totali staccati da un filo. */
.dati--prospetto { max-width: 28rem; margin-left: auto; gap: var(--space-2); }
.dati--prospetto .dati-voce { grid-template-columns: 1fr auto; align-items: baseline; gap: var(--space-4); }
.dati--prospetto .dati-valore { text-align: right; font-variant-numeric: tabular-nums; }
.dati--prospetto .dati-voce--totale { border-top: 1px solid var(--c-border); padding-top: var(--space-2); }

/* ===========================================================================
   PAGINE DI ACCESSO
   =========================================================================== */
/* SCENA UNICA CON RIQUADRO (settembre 2026, dopo un test d'uso: "la
   separazione netta fra l'area bianca del modulo e la grafica a sinistra
   rende tutto poco armonico").

   Prima: due colonne, pannello scuro animato | modulo su fondo bianco, con un
   taglio verticale netto a metà schermo. Ora lo sfondo animato occupa TUTTA
   la pagina e il modulo galleggia sopra in un riquadro chiaro, a destra. Il
   testo editoriale (marchio, citazione, nota) resta a sinistra, direttamente
   sullo sfondo: è la stessa gerarchia di prima, senza il confine. Il
   riquadro è di vetro scuro (seconda iterazione, vedi più sotto).

   Tre strati, dal basso:
     .accesso-vetrina  la scena: fondo scuro + canvas, in `position: absolute`
                       sull'intera pagina (fuori dal flusso, così non occupa
                       spazio nella griglia);
     testo editoriale  dentro la vetrina, a sinistra;
     .accesso-modulo   il riquadro di vetro, nel flusso, sopra la scena.

   Alternative per cambiare l'aspetto senza toccare il markup:
     - riquadro al centro invece che a destra: `justify-content: center` su
       .accesso nel blocco ≥ 56rem (e nascondere la citazione, che finirebbe
       sotto il riquadro);
     - vetro più o meno trasparente: --vetro-velo in .accesso-modulo
       (sotto 0,25 le linee animate iniziano a disturbare i campi);
     - animazione più discreta: alzare le opacità della velatura (::after).

   Sotto i 56rem il testo editoriale sparisce (il logo passa nel riquadro) e
   sotto i 40rem sparisce anche il canvas: su telefono lo schermo serve al
   modulo, e un'animazione continua consuma batteria per un ornamento. */
.accesso {
  position: relative;
  isolation: isolate;
  min-height: 100vh;
  display: grid;
  align-items: center;
  justify-content: center;
  padding: var(--space-6) var(--space-4);
  background: var(--c-bg-inverse);
  color: var(--c-text-inverse);
}
@media (min-width: 56rem) {
  .accesso {
    justify-content: end;
    padding: var(--space-7) clamp(var(--space-6), 7vw, 8rem);
  }
}

.accesso-vetrina {
  position: absolute;
  inset: 0;
  z-index: 0;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  padding: var(--space-8) var(--space-7);
  /* Senza canvas (registrazione, telefono) resta un fondo scuro con un alone
     del colore dello studio: la pagina non è mai un rettangolo nero piatto. */
  background:
    radial-gradient(60rem 40rem at 20% 110%, color-mix(in srgb, var(--accent) 22%, transparent), transparent 70%),
    var(--c-bg-inverse);
  color: var(--c-text-inverse);
}

.accesso-vetrina .logo {
  background-image: var(--logo-inverso);
  width: var(--logo-inverso-larghezza);
  height: var(--logo-altezza);
}
.accesso-citazione {
  font-family: var(--font-display);
  font-size: var(--text-xl);
  line-height: var(--leading-snug);
  max-width: 24rem;
}
.accesso-citazione::before {
  content: "";
  display: block;
  width: 3rem;
  height: 3px;
  background: var(--accent);
  margin-bottom: var(--space-5);
}
/* Le frasi a rotazione (public/js/frasi-accesso.js): tutte nella stessa
   cella della griglia, così il riquadro prende l'altezza della più lunga e il
   resto della pagina non salta a ogni cambio. Il filo d'accento (::before)
   sta nella riga sopra. Si alterna l'opacità; con `prefers-reduced-motion`
   lo script non ruota e la transizione si azzera (in cima al file). */
.accesso-frasi { display: grid; }
.accesso-frasi::before { grid-row: 1; }
.accesso-frase {
  grid-row: 2;
  grid-column: 1;
  margin: 0;
  opacity: 0;
  visibility: hidden;
  transition: opacity 450ms ease, visibility 0s linear 450ms;
}
.accesso-frase--attiva {
  opacity: 1;
  visibility: visible;
  transition: opacity 450ms ease, visibility 0s;
}
.accesso-nota { font-size: var(--text-sm); color: rgba(244, 247, 248, 0.6); max-width: 24rem; }

@media (max-width: 55.99rem) {
  .accesso-vetrina > .logo,
  .accesso-nota { display: none; }
}
/* La citazione richiede spazio vero accanto al riquadro (30rem + margini):
   sotto i 64rem finirebbe schiacciata o sotto il modulo, e si toglie. */
@media (max-width: 63.99rem) {
  .accesso-citazione { display: none; }
}
@media (max-width: 39.99rem) {
  .accesso-particelle { display: none; }
}

/* --- Sfondo a particelle (public/js/sfondo-particelle.js) ----------------
   Tre strati impilati nella scena (ora a tutta pagina, vedi sopra):
     0. il canvas, che occupa tutto il pannello e riceve mouse e tocco;
     1. una velatura sfumata (::after) che scurisce l'alto e il basso, dove
        stanno logo e nota: senza, il testo chiaro su linee cremisi in
        movimento diventerebbe illeggibile;
     2. i contenuti testuali, con `pointer-events: none` perché il
        trascinamento sopra la citazione deve ruotare la scena, non
        selezionare il testo.
   Variante più sobria, se un giorno l'animazione risultasse troppo presente:
   alzare le opacità della velatura, o limitare il canvas alla metà
   inferiore del pannello (`inset: 50% 0 0 0`). */
.accesso-vetrina {
  /* Niente `position` qui: la vetrina è già `absolute` a tutta pagina (vedi
     sopra), e un `relative` in questa regola successiva la rimetteva nel
     flusso della griglia — difetto visto nella prima prova della scena unica. */
  overflow: hidden;
  /* Nuovo contesto di impilamento: gli z-index qui sotto valgono solo
     dentro la scena e non competono con il riquadro del modulo. */
  isolation: isolate;
}
.accesso-particelle {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 0;
  cursor: grab;
  /* Il gesto di trascinamento su tablet deve ruotare la scena, non
     scorrere la pagina. Sotto i 56rem il pannello è nascosto, quindi su
     telefono lo scorrimento non è mai toccato. */
  touch-action: none;
}
.accesso-particelle:active { cursor: grabbing; }
.accesso-vetrina::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  /* Alto e basso (logo e nota) come prima, più una sfumatura verso destra:
     le linee in movimento passano DIETRO il riquadro attenuate, così l'occhio
     resta sul modulo. */
  background:
    linear-gradient(to bottom, var(--c-bg-inverse) 0%, transparent 22%),
    linear-gradient(to top, var(--c-bg-inverse) 0%, transparent 30%),
    linear-gradient(to right, transparent 45%, rgba(10, 10, 10, 0.55) 100%);
}
.accesso-vetrina > :not(canvas) {
  position: relative;
  z-index: 2;
  pointer-events: none;
}

/* Strumenti di regolazione (solo sviluppo): selettore fra i due sfondi e
   pannello dello sfondo attivo. Specificità più alta della regola
   precedente: tornano cliccabili e si posizionano in alto a destra senza
   entrare nel flusso a colonna del pannello scuro. */
.accesso-vetrina > .sfondo-strumenti {
  position: absolute;
  top: var(--space-4);
  /* Al centro in alto: a destra finirebbero sotto il riquadro del modulo. */
  left: 50%;
  transform: translateX(-50%);
  z-index: 3;
  pointer-events: auto;
  width: 16rem;
  display: grid;
  gap: var(--space-2);
  font-size: var(--text-xs);
}

/* Interruttore a due posizioni. Lo stato è `aria-pressed`, lo stesso
   attributo che legge un lettore di schermo: nessuna classe "attivo" da
   tenere allineata a mano. */
.sfondo-scelta {
  display: grid;
  grid-template-columns: 1fr 1fr;
  border: 1px solid rgba(244, 247, 248, 0.2);
  border-radius: var(--radius);
  overflow: hidden;
  background: rgba(0, 0, 0, 0.55);
}
.sfondo-scelta button {
  font: inherit;
  font-family: var(--font-mono);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  padding: var(--space-2);
  border: 0;
  background: transparent;
  color: rgba(244, 247, 248, 0.65);
  cursor: pointer;
}
.sfondo-scelta button:hover { color: var(--c-text-inverse); }
.sfondo-scelta button[aria-pressed="true"] { background: var(--accent); color: #fff; }
.sfondo-scelta button:disabled { opacity: 0.35; cursor: not-allowed; }

.particelle-pannello {
  background: rgba(0, 0, 0, 0.55);
  backdrop-filter: blur(6px);
  border: 1px solid rgba(244, 247, 248, 0.15);
  border-radius: var(--radius);
}
.particelle-pannello summary {
  cursor: pointer;
  padding: var(--space-2) var(--space-3);
  font-family: var(--font-mono);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: rgba(244, 247, 248, 0.75);
}
.particelle-controlli {
  display: grid;
  gap: var(--space-3);
  padding: var(--space-2) var(--space-3) var(--space-3);
  /* Il pannello del flusso ha una ventina di controlli: scorre al suo
     interno invece di uscire dal fondo dello schermo. */
  max-height: calc(100vh - 8rem);
  overflow-y: auto;
}
.particelle-gruppo {
  display: grid;
  gap: var(--space-3);
  margin: 0;
  padding: 0;
  border: 0;
  min-width: 0;
}
.particelle-gruppo legend {
  padding: 0 0 var(--space-2);
  font-family: var(--font-mono);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--accent);
}
.particelle-voce { display: grid; gap: var(--space-1); }
.particelle-voce span { display: flex; justify-content: space-between; }
.particelle-voce output { font-family: var(--font-mono); color: var(--accent); }
.particelle-voce--spunta { display: flex; align-items: center; gap: var(--space-2); }
/* `accent-color` colora slider e caselle con il cremisi dello studio senza
   ridisegnarli da zero: una proprietà, nessuno pseudo-elemento per browser. */
.particelle-voce input { accent-color: var(--accent); width: 100%; margin: 0; }
.particelle-voce--spunta input { width: auto; }
.particelle-azioni { display: flex; gap: var(--space-2); }
.particelle-azioni .btn { color: var(--c-text-inverse); border-color: rgba(244, 247, 248, 0.3); }
.particelle-azioni .btn:hover { background: rgba(244, 247, 248, 0.1); color: var(--c-text-inverse); }

/* IL RIQUADRO "A GOCCIA D'ACQUA" (seconda iterazione, settembre 2026).

   Prima era un riquadro bianco quasi opaco: ordinato, ma uno stacco netto sul
   fondo scuro ("togliere lo stacco di bianco, con una trasparenza o un effetto
   goccia d'acqua che dia tridimensionalità"). Ora è VETRO SCURO:

   1. TRASPARENZA CON SFOCATURA. `backdrop-filter` sfoca e satura ciò che sta
      dietro: le linee animate restano visibili come colore diffuso, mai come
      tratti netti dietro il testo dei campi. Il velo scuro sotto la sfocatura è
      deliberato: un vetro chiaro e molto trasparente farebbe scorrere le linee
      sotto le lettere della password.
   2. BORDO DI LUCE. Un filo chiaro in alto e più tenue in basso (ombre
      `inset`): è ciò che l'occhio legge come spessore, come il bordo di una
      goccia colpito dalla luce.
   3. RIFLESSO. `::after` è una macchia di luce ellittica la cui posizione
      (--luce-x, --luce-y) segue il puntatore (public/js/riquadro-accesso.js):
      il riquadro sembra una superficie curva che riflette. Senza JavaScript,
      o con "riduci movimento", resta fermo in alto a sinistra.
   4. PROFONDITÀ. Ombra esterna ampia e morbida, e un alone del colore dello
      studio in basso a destra, dentro il vetro.

   TOKEN RIDEFINITI SUL RIQUADRO. Invece di riscrivere le regole di campi,
   etichette, avvisi, pulsanti e tabelle per il fondo scuro, si ridefiniscono
   qui le VARIABILI che quelle regole già usano (--c-text, --c-bg, --c-border
   ...): valgono solo dentro il riquadro, e tutto il resto dell'applicazione
   non cambia. Contrasti verificati sul caso peggiore (velo più chiaro):
   testo ≥ 12:1, etichette ≈ 8:1, note ≈ 5:1 (soglia WCAG AA 4,5:1).

   Leve per regolare l'effetto: --vetro-velo (più alto = più scuro e leggibile),
   --vetro-sfocatura, --vetro-riflesso (intensità della luce).

   Ripiego: senza supporto a backdrop-filter il velo diventa quasi opaco, così
   la leggibilità non dipende da una proprietà che manca. */
.accesso-modulo {
  --vetro-velo: 0.34;
  --vetro-sfocatura: 22px;
  --vetro-riflesso: 0.2;
  /* Posizione del riflesso: questi sono i valori di partenza (in alto a
     sinistra), quelli che restano senza JavaScript o con "riduci movimento".
     riquadro-accesso.js li sovrascrive nello style inline dell'elemento, che
     vince su questa regola. Dichiararli qui, invece di lasciarli solo come
     riserva dentro var(), dà alla variabile un'origine leggibile nel CSS. */
  --luce-x: 18%;
  --luce-y: 0%;

  /* Token del tema, versione "su vetro scuro". */
  --c-text: var(--kx-paper);
  --c-text-soft: rgba(244, 247, 248, 0.8);
  --c-text-faint: rgba(244, 247, 248, 0.62);
  --c-bg: rgba(255, 255, 255, 0.07);
  --c-bg-sunken: rgba(255, 255, 255, 0.06);
  --c-surface: rgba(255, 255, 255, 0.05);
  --c-border: rgba(255, 255, 255, 0.14);
  --c-border-strong: rgba(255, 255, 255, 0.26);
  --accent-tenue: color-mix(in srgb, var(--accent) 38%, transparent);
  /* Su fondo scuro: i colori di stato del Toast del design system. */
  --c-critico: #EC8B82;
  --c-critico-bg: color-mix(in srgb, var(--kx-danger-500) 20%, transparent);
  --c-positivo: var(--kx-teal-300);
  --c-positivo-bg: color-mix(in srgb, var(--kx-success-500) 28%, transparent);
  --c-attenzione: #E3B76B;
  --c-attenzione-bg: color-mix(in srgb, var(--kx-warning-500) 26%, transparent);
  --c-info: var(--kx-neutral-300);
  --c-info-bg: color-mix(in srgb, var(--kx-info-500) 30%, transparent);

  position: relative;
  z-index: 1;
  /* È un <main>: annulla il `padding-block` generico delle pagine, che nel
     riquadro lasciava ~100px vuoti in fondo. Lo spazio interno lo dà
     .accesso-modulo-interno. */
  padding: 0;
  width: min(100%, 30rem);
  margin-block: auto;
  color: var(--c-text);
  isolation: isolate;
  border-radius: var(--radius-xl);
  background:
    /* luce diffusa dall'alto, come su una superficie curva */
    linear-gradient(160deg, rgba(255, 255, 255, 0.16) 0%, rgba(255, 255, 255, 0.04) 38%, rgba(255, 255, 255, 0.015) 100%),
    /* alone dello studio, dentro il vetro */
    radial-gradient(22rem 16rem at 100% 100%, color-mix(in srgb, var(--accent) 24%, transparent), transparent 70%),
    rgba(10, 10, 10, var(--vetro-velo));
  -webkit-backdrop-filter: blur(var(--vetro-sfocatura)) saturate(165%);
  backdrop-filter: blur(var(--vetro-sfocatura)) saturate(165%);
  border: 1px solid rgba(255, 255, 255, 0.16);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.38),     /* orlo di luce in alto */
    inset 0 -1px 0 rgba(255, 255, 255, 0.07),    /* orlo tenue in basso */
    inset 0 0 40px rgba(255, 255, 255, 0.03),    /* spessore del vetro */
    0 2px 4px rgba(0, 0, 0, 0.25),
    0 40px 100px -20px rgba(0, 0, 0, 0.7);        /* distacco dalla scena */
  overflow: hidden;
}
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .accesso-modulo { --vetro-velo: 0.9; }
}

/* Il riflesso: sopra il vetro, sotto il contenuto, trasparente ai clic. */
.accesso-modulo::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background: radial-gradient(
    30rem 18rem at var(--luce-x) var(--luce-y),
    rgba(255, 255, 255, var(--vetro-riflesso)),
    transparent 60%
  );
  transition: background-position var(--durata-media) var(--curva-standard);
}
/* Il filo cremisi non è più una barra piena sul bordo (su un vetro sembrerebbe
   un nastro adesivo): diventa un breve tratto sopra l'occhiello, come quello
   della citazione a sinistra. */
.accesso-modulo::before {
  content: "";
  display: block;
  width: 3rem;
  height: 3px;
  margin: var(--space-6) var(--space-6) 0;
  border-radius: 3px;
  background: var(--accent);
  box-shadow: 0 0 12px color-mix(in srgb, var(--accent) 70%, transparent);
}
@media (max-width: 39.99rem) {
  .accesso-modulo::before { margin: var(--space-5) var(--space-4) 0; }
}

/* Campi: incassati nel vetro (ombra interna), più chiari al fuoco. */
.accesso-modulo input[type="text"],
.accesso-modulo input[type="email"],
.accesso-modulo input[type="password"] {
  border-radius: var(--radius-md);
  box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.35);
  caret-color: #fff;
}
.accesso-modulo input::placeholder { color: rgba(244, 247, 248, 0.45); }
.accesso-modulo input:focus {
  background: rgba(255, 255, 255, 0.11);
  border-color: color-mix(in srgb, var(--accent) 70%, #fff);
  box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.35), var(--anello-focus);
}
/* Compilazione automatica del browser: Chrome dipinge i campi di azzurro
   chiaro, con testo scuro, e non lascia cambiare lo sfondo. Il rimedio
   standard è un'ombra interna piena che lo copre, e un colore del testo
   forzato. Piena e non trasparente: la trasparenza lascerebbe vedere
   l'azzurro sotto. */
.accesso-modulo input:-webkit-autofill,
.accesso-modulo input:-webkit-autofill:hover,
.accesso-modulo input:-webkit-autofill:focus {
  -webkit-text-fill-color: var(--kx-paper);
  -webkit-box-shadow: 0 0 0 100px var(--kx-neutral-800) inset;
  box-shadow: 0 0 0 100px var(--kx-neutral-800) inset;
  transition: background-color 9999s ease-out 0s;
}

/* Blocchi interni (collegamento in registrazione, avvisi): vetro nel vetro. */
.accesso-modulo .scheda {
  background: rgba(255, 255, 255, 0.05);
  border-color: rgba(255, 255, 255, 0.14);
  border-radius: var(--radius-lg);
}
.accesso-modulo .avviso { border-radius: var(--radius-md); }

/* Il logo dentro il riquadro è su fondo scuro: variante chiara. */
.accesso-logo-modulo { background-image: var(--logo-inverso); width: var(--logo-inverso-larghezza); }

.accesso-modulo-interno { padding: var(--space-4) var(--space-6) var(--space-6); }
@media (max-width: 39.99rem) {
  .accesso-modulo-interno { padding: var(--space-5) var(--space-4); }
}
/* Logo dello studio dentro il riquadro: solo quando il testo editoriale a
   sinistra non c'è (schermi stretti), altrimenti sarebbe ripetuto. */
.accesso-logo-modulo { margin-bottom: var(--space-4); }
@media (min-width: 56rem) {
  .accesso-logo-modulo { display: none; }
}
/* Il blocco "Hai già un account in un altro studio?" della registrazione
   non deve toccare i pulsanti sotto. */
.accesso-modulo details { margin-bottom: var(--space-5); }
/* La tabella delle credenziali di prova è larga: nel riquadro scorre in
   orizzontale invece di allargarlo. */
.accesso-modulo .demo { margin-top: var(--space-5); }
.accesso-modulo .demo .tabella-contenitore { overflow-x: auto; }
.accesso-modulo .demo {
  background: rgba(227, 183, 107, 0.08);
  border-color: rgba(227, 183, 107, 0.55);
  border-radius: var(--radius-lg);
}
.accesso-modulo .demo th,
.accesso-modulo .demo td { border-color: rgba(255, 255, 255, 0.1); color: var(--c-text-soft); }

/* ===========================================================================
   CREDENZIALI DI PROVA (solo sviluppo)
   =========================================================================== */
/* Bordo tratteggiato e fondo giallino: deve essere impossibile scambiare
   questo blocco per parte dell'interfaccia vera. Non compare mai con
   NODE_ENV=production (vedi routes/auth.ts), ma se un giorno comparisse per
   errore si deve notare subito. */
.demo {
  margin-top: var(--space-6);
  border: 1px dashed var(--c-attenzione);
  border-radius: var(--radius);
  background: var(--c-attenzione-bg);
  padding: var(--space-4);
}
.demo-titolo {
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: var(--tracking-wide);
  font-weight: 700;
  color: var(--c-attenzione);
  margin-bottom: var(--space-2);
}
.demo table { font-size: var(--text-xs); }
.demo td, .demo th { padding: var(--space-2); }
.demo tbody tr:hover { background: transparent; }
.demo-tabella { width: 100%; table-layout: auto; }
/* Con la vetrina le utenze sono venticinque: senza un tetto il riquadro diventava alto tre
   schermi, la scena di sfondo (che copre l'intera pagina) lo seguiva, e su uno schermo largo il
   canvas animato arrivava a quindici milioni di pixel ridisegnati a ogni fotogramma. Si scorre
   dentro il riquadro, la pagina resta alta una finestra. */
.demo-scorre {
  max-height: min(16rem, 30vh);
  overflow-y: auto;
  overscroll-behavior: contain;
}
.demo-scorre thead th { position: sticky; top: 0; z-index: 1; background: var(--c-bg-inverse); }
.demo-tabella td { vertical-align: middle; }
.demo-tabella td:last-child { width: 1%; text-align: right; }
.demo-nome, .demo-riga { display: block; }
.demo-riga { overflow-wrap: anywhere; }
.demo-studio th {
  text-align: left;
  padding-top: var(--space-3);
  color: var(--c-attenzione);
  text-transform: none;
  letter-spacing: normal;
}

/* ===========================================================================
   PIÈ DI PAGINA
   =========================================================================== */
.pie {
  flex-shrink: 0;
  background: var(--c-bg-inverse);
  color: rgba(244, 247, 248, 0.7);
  padding-block: var(--space-6);
  font-size: var(--text-sm);
}
.pie-interno {
  /* Il pulsante dei messaggi è fisso nell'angolo in basso a destra: senza questo spazio
     copriva "Ambiente riservato — …" quando la pagina arriva in fondo. */
  padding-inline-end: calc(3.5rem + var(--space-5));
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-5);
  justify-content: space-between;
  align-items: center;
}
.pie .logo { background-image: var(--logo-pie); width: var(--logo-pie-larghezza); }
.pie a { color: rgba(244, 247, 248, 0.7); text-decoration: none; }
.pie a:hover { color: #fff; }
.pie-marchio { font-size: var(--text-xs); letter-spacing: var(--tracking-wide); text-transform: uppercase; }

/* ===========================================================================
   STAMPA
   ---------------------------------------------------------------------------
   Vale la pena esistere: la scheda di una pratica è esattamente il genere di
   documento che in uno studio finisce in un fascicolo cartaceo. Si tolgono
   navigazione, moduli e pulsanti — su carta sono rumore — e si lascia il
   contenuto su fondo bianco.
   =========================================================================== */
@media print {
  .barra, .pie, .testata-azioni, form, .btn, .cta, .zona-avvisi, .filtri { display: none !important; }
  body { background: #fff; }
  .scheda { border: none; box-shadow: none; page-break-inside: avoid; }
  main { padding: 0; }
  a[href]::after { content: ""; }
}

/* ==========================================================================
 * STEP 2/3 — canali di comunicazione e stadi documentali
 * ========================================================================== */

/* Etichetta del canale di un messaggio di pratica (interno vs cliente):
   visibile solo allo staff. Colori dal semaforo, non nuovi valori. */
.etichetta-canale {
  font-size: 0.7rem;
  font-weight: 600;
  padding: 0.05rem 0.4rem;
  border-radius: var(--radius);
  text-transform: uppercase;
  letter-spacing: 0.03em;
}
.etichetta-canale--interna { background: var(--c-attenzione-bg); color: var(--c-attenzione); }
.etichetta-canale--esterna { background: var(--c-info-bg); color: var(--c-info); }

/* Un messaggio interno si stacca leggermente da quelli col cliente, così lo
   staff distingue a colpo d'occhio i due canali nello stesso thread. */
.messaggio--interna { background: var(--c-attenzione-bg); border-radius: var(--radius); }

/* Riga di badge sopra i metadati di un documento (stadio, condiviso, validato). */
.documento-badge { display: flex; flex-wrap: wrap; gap: 0.35rem; margin: 0.25rem 0; }

/* Riga d'azioni compatta (valida/condividi su un documento). */
.riga-azioni--fitta { gap: 0.4rem; margin-top: 0.35rem; }

/* --- Flusso documentale (step 4) ----------------------------------------- */
/* Stepper orizzontale: dove sta il DELIVERABLE. Solo staff. */
.flusso-doc {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem 1.25rem;
  margin: 0 0 1rem;
  padding: 0;
}
.flusso-fase {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  font-size: 0.8rem;
  color: var(--c-text-faint);
  position: relative;
}
.flusso-pallino {
  width: 10px;
  height: 10px;
  border-radius: var(--radius-pill);
  border: 2px solid var(--c-border-strong);
  background: transparent;
  flex: none;
}
.flusso-fase--fatto { color: var(--c-positivo); }
.flusso-fase--fatto .flusso-pallino { background: var(--c-positivo); border-color: var(--c-positivo); }
.flusso-fase--corrente { color: var(--accent); font-weight: 600; }
.flusso-fase--corrente .flusso-pallino { border-color: var(--accent); background: var(--accent-tenue); }

/* Gruppi di documenti per stadio. */
.documento-gruppo { margin-bottom: 1rem; }
.documento-gruppo-testa { display: flex; align-items: baseline; gap: 0.5rem; margin-bottom: 0.35rem; }
.documento-gruppo-testa h3 { font-size: 0.9rem; margin: 0; }

/* --- Area di piattaforma (/admin) ---------------------------------------- */
/* Marchio testuale: l'area admin non ha tenant, quindi niente logo a tema. */
.marchio {
  font-weight: 700;
  font-size: var(--text-sm);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  text-decoration: none;
  color: var(--c-text);
}
.marchio-occhiello { color: var(--accent); font-weight: 600; }

/* Contenitore stretto per login/errore di piattaforma. */
.stretto { max-width: 34rem; margin-inline: auto; }

/* Form a griglia responsiva (creazione admin). */
.griglia-form {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));
  gap: var(--space-3);
  align-items: end;
}


/* ===========================================================================
   GRAFICI DEL CRUSCOTTO
   ---------------------------------------------------------------------------
   Geometria: src/services/grafici.ts. Markup: views/partials/grafico-*.ejs.
   Interazione: public/js/grafici.js. Qui solo l'aspetto.

   Regole di fondo, valide per tutti i grafici:
   - i SEGNI (barre, linee, punti) portano il colore della serie; i TESTI
     (valori, etichette, assi) restano nei colori del testo — un numero
     scritto in cremisi si confonderebbe con un avviso;
   - linee di 2px, barre sottili (≤ 24px), griglia a 1px continua e tenue:
     il dato è l'unica cosa che può "alzare la voce";
   - le animazioni d'ingresso sono solo CSS, e la regola globale su
     `prefers-reduced-motion` (in cima al file) le annulla.
   =========================================================================== */

/* Due colonne su schermo largo, una su schermo stretto. `minmax(24rem…)` e
   non 20rem: con 20rem, a larghezza piena ne entravano tre e le due schede
   di barre lasciavano un buco vuoto accanto a sé. */
.griglia-grafici {
  display: grid;
  gap: var(--space-5);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 24rem), 1fr));
}
@media (min-width: 62rem) {
  .griglia-grafici { grid-template-columns: 1fr 1fr; }
}
/* L'andamento nel tempo ha bisogno di larghezza: dodici mesi in 20rem
   diventerebbero illeggibili. Occupa tutta la riga. */
.scheda--grafico-largo { grid-column: 1 / -1; }
.scheda-testa p { margin: var(--space-1) 0 0; }

/* --- Barre orizzontali --------------------------------------------------- */
.grafico-barre {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: var(--space-1);
}

/* Ogni riga è un link su tre colonne: etichetta | barra | valore. La
   larghezza dell'etichetta è uguale per tutte le righe perché tutte le barre
   partano dallo stesso punto: barre che iniziano in punti diversi non si
   confrontano. */
.grafico-barra {
  display: grid;
  grid-template-columns: minmax(7rem, 38%) minmax(0, 1fr) 2.5rem;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-2);
  margin-inline: calc(-1 * var(--space-2));
  border-radius: var(--radius-xs);
  text-decoration: none;
  color: var(--c-text);
  transition: background-color var(--durata-breve) var(--curva-standard);
}
/* L'area sensibile è la riga intera, non i pochi pixel della barra. */
.grafico-barra:hover,
.grafico-barra.is-attivo { background: var(--c-bg-sunken); }

.grafico-barra-etichetta {
  font-size: var(--text-sm);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.grafico-barra-valore {
  font-size: var(--text-sm);
  font-weight: 600;
  text-align: right;
  /* Cifre a larghezza fissa: in una colonna di numeri le unità restano
     allineate fra una riga e l'altra. */
  font-variant-numeric: tabular-nums;
}

.grafico-barra-traccia {
  display: block;
  width: 100%;
  height: 0.75rem;
  /* Il "binario" vuoto dietro la barra: fa leggere la lunghezza come parte
     di un intero, senza bisogno di un asse. */
  background: var(--c-bg-sunken);
  border-radius: var(--radius-xs);
  overflow: visible;
}
.grafico-barra:hover .grafico-barra-traccia,
.grafico-barra.is-attivo .grafico-barra-traccia { background: var(--c-border); }
.grafico-barra-riempimento {
  fill: var(--grafico-serie-1);
  /* La barra cresce da sinistra all'apertura. `transform-box: fill-box` fa
     sì che l'origine sia il bordo sinistro del rettangolo stesso, non
     l'angolo dell'SVG. */
  transform-box: fill-box;
  transform-origin: left center;
  animation: grafico-cresci var(--durata-rivela) var(--curva-rivela) both;
  transition: fill var(--durata-breve) var(--curva-standard);
}
.grafico-barra:hover .grafico-barra-riempimento,
.grafico-barra.is-attivo .grafico-barra-riempimento { fill: var(--accent-scuro); }

/* Ingresso a cascata: ogni barra parte un attimo dopo la precedente. */
.grafico-barre li:nth-child(2) .grafico-barra-riempimento { animation-delay: calc(var(--passo-scaglionato) * 1); }
.grafico-barre li:nth-child(3) .grafico-barra-riempimento { animation-delay: calc(var(--passo-scaglionato) * 2); }
.grafico-barre li:nth-child(4) .grafico-barra-riempimento { animation-delay: calc(var(--passo-scaglionato) * 3); }
.grafico-barre li:nth-child(5) .grafico-barra-riempimento { animation-delay: calc(var(--passo-scaglionato) * 4); }
.grafico-barre li:nth-child(6) .grafico-barra-riempimento { animation-delay: calc(var(--passo-scaglionato) * 5); }
.grafico-barre li:nth-child(n+7) .grafico-barra-riempimento { animation-delay: calc(var(--passo-scaglionato) * 6); }

@keyframes grafico-cresci {
  from { transform: scaleX(0); }
  to { transform: scaleX(1); }
}

/* --- Barre di confronto (redditività: valore del tempo vs fatturato) ------
   Due barre per riga invece di una. La riga è un link unico, come in
   .grafico-barra, ma impilata in verticale: con due barre affiancate su tre
   colonne (etichetta | barra | numero) i titoli dei mandati — lunghi, e non
   una parola come "In lavorazione" — avrebbero mangiato la metà della
   larghezza proprio dove serve la lunghezza delle barre.
   Alternativa scartata: due colonne di barre affiancate (valore | fatturato).
   Confronta bene dentro la riga, male fra le righe, perché ogni colonna si
   normalizzerebbe da sé. */
.grafico-confronto {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  /* `minmax(0, 1fr)` e non il `1fr` implicito. DIFETTO TROVATO MISURANDO su
     una finestra stretta vera: a 380px le Statistiche avevano 141px di
     scorrimento orizzontale, e la colpa non era di una barra troppo lunga.
     La traccia della barra è un `<svg>` senza attributo `width`, e un SVG
     senza dimensioni dichiarate vale **300px intrinseci**. In una griglia il
     minimo automatico di una traccia è il min-content dei suoi elementi:
     quei 300px risalivano la catena — svg → riga → voce → li → lista —
     e nessun anello poteva stringersi sotto di essi. Alle larghezze da
     scrivania la colonna era comunque più larga di 300px e non si vedeva
     nulla.
     Stesso idioma del telaio, per la stessa ragione: `1fr` NON vuol dire
     "prendi lo spazio che c'è", vuol dire "minmax(auto, 1fr)". */
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-1);
}
.grafico-confronto-voce {
  display: block;
  padding: var(--space-2);
  margin-inline: calc(-1 * var(--space-2));
  border-radius: var(--radius);
  text-decoration: none;
  color: var(--c-text);
  transition: background-color var(--durata-breve) var(--curva-standard);
}
.grafico-confronto-voce:hover,
.grafico-confronto-voce.is-attivo { background: var(--c-bg-sunken); }

.grafico-confronto-testa {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-3);
  font-size: var(--text-sm);
  margin-bottom: var(--space-1);
}
.grafico-confronto-titolo {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* Il tipo di mandato: a destra, tenue, senza andare a capo. È lo stesso dato
   della colonna "Tipo" della tabella sotto. */
.grafico-confronto-nota {
  font-size: var(--text-xs);
  color: var(--c-text-soft);
  white-space: nowrap;
  flex: none;
}

/* Barra e importo su una riga. La colonna dell'importo ha larghezza FISSA:
   così tutte le barre finiscono nello stesso punto e le lunghezze si
   confrontano davvero, anche fra righe con importi di cifre diverse. */
.grafico-confronto-riga {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 6.5rem;
  align-items: center;
  gap: var(--space-3);
}
.grafico-confronto-riga + .grafico-confronto-riga { margin-top: 3px; }

.grafico-confronto-traccia {
  display: block;
  width: 100%;
  height: 0.625rem;
  background: var(--c-bg-sunken);
  border-radius: var(--radius-xs);
  overflow: visible;
}
.grafico-confronto-voce:hover .grafico-confronto-traccia,
.grafico-confronto-voce.is-attivo .grafico-confronto-traccia { background: var(--c-border); }

.grafico-confronto-riempimento {
  /* Stessa animazione di ingresso delle barre orizzontali: cresce da
     sinistra, con l'origine sul bordo del rettangolo e non dell'SVG. */
  transform-box: fill-box;
  transform-origin: left center;
  animation: grafico-cresci var(--durata-rivela) var(--curva-rivela) both;
}
/* Coppia di colori: il cremisi del tema per il tempo speso (il costo, ciò
   che lo studio mette), il blu della serie 2 per il fatturato. Non verde e
   rosso: uno scostamento negativo non è un errore da segnalare, è un dato da
   leggere — e la coppia rosso/verde è la prima a cadere con i daltonismi. */
.grafico-confronto-riempimento--valore-tempo { fill: var(--grafico-serie-1); }
.grafico-confronto-riempimento--fatturato { fill: var(--grafico-serie-2); }
.grafico-campione--valore-tempo { background: var(--grafico-serie-1); }
.grafico-campione--fatturato { background: var(--grafico-serie-2); }
.grafico-tooltip-chiave--valore-tempo { background: var(--grafico-serie-1); }
.grafico-tooltip-chiave--fatturato { background: var(--grafico-serie-2); }

.grafico-confronto-valore {
  font-size: var(--text-xs);
  font-weight: 600;
  text-align: right;
  font-variant-numeric: tabular-nums;
}

/* --- Linee --------------------------------------------------------------- */
.grafico-linee { margin: 0; }

.grafico-legenda {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-4);
  font-size: var(--text-xs);
  color: var(--c-text-soft);
  margin-bottom: var(--space-3);
}
.grafico-legenda--compatta { margin: 0; }
.grafico-legenda-voce { display: inline-flex; align-items: center; gap: var(--space-2); }
/* Chiave a forma di LINEA per il grafico a linee, a forma di BLOCCO per le
   barre: la leggenda imita il segno che spiega. */
.grafico-legenda-chiave { width: 1.25rem; height: 0.5rem; overflow: visible; }
.grafico-campione { width: 0.625rem; height: 0.625rem; border-radius: 1px; display: inline-block; }
.grafico-campione--ritardo { background: var(--c-critico); }
.grafico-campione--in-tempo { background: var(--grafico-serie-2); }

/* Griglia a tre colonne (asse | piano | etichette di fine) e due righe
   (grafico | mesi). I quattro SVG del partial ci si incastrano. */
.grafico-linee-corpo {
  display: grid;
  grid-template-columns: 2rem minmax(0, 1fr) 2.25rem;
  grid-template-rows: 13rem 1.75rem;
  /* Container query più sotto: le etichette dei mesi si diradano in base
     alla larghezza DEL GRAFICO, non dello schermo. */
  container-type: inline-size;
}
.grafico-asse-y { grid-column: 1; grid-row: 1; }
.grafico-piano { grid-column: 2; grid-row: 1; }
.grafico-etichette-fine { grid-column: 3; grid-row: 1; }
.grafico-asse-x { grid-column: 2; grid-row: 2; }

.grafico-asse-y,
.grafico-piano,
.grafico-etichette-fine,
.grafico-asse-x {
  display: block;
  width: 100%;
  height: 100%;
  /* I testi a y=0% e y=100% sporgono di mezza riga: non vanno tagliati. */
  overflow: visible;
}

.grafico-asse-y text,
.grafico-asse-x text {
  font-size: 0.6875rem;
  fill: var(--c-text-faint);
  font-variant-numeric: tabular-nums;
}
.grafico-etichette-fine text {
  font-size: var(--text-xs);
  font-weight: 600;
  fill: var(--c-text);
}

.grafico-griglia {
  stroke: var(--grafico-griglia);
  stroke-width: 1;
  /* Senza, nel piano stirato una linea da 1 sarebbe spessa l'1% dell'altezza.
     Con `non-scaling-stroke` lo spessore è in pixel veri. */
  vector-effect: non-scaling-stroke;
}
.grafico-griglia--base { stroke: var(--grafico-tenue); }

.grafico-tratto {
  fill: none;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
  vector-effect: non-scaling-stroke;
}
.grafico-tratto--1 { stroke: var(--grafico-serie-1); }
.grafico-tratto--2 { stroke: var(--grafico-serie-2); }

/* Punti: tratti di lunghezza zero con estremità tonde (vedi il partial),
   8px di diametro — sotto quella misura un punto non si vede sulla linea. */
.grafico-punto {
  stroke-width: 8;
  stroke-linecap: round;
  fill: none;
  vector-effect: non-scaling-stroke;
}
.grafico-punto--attivo { stroke-width: 10; }

.grafico-mirino {
  stroke: var(--c-text-faint);
  stroke-width: 1;
  vector-effect: non-scaling-stroke;
  opacity: 0;
  transition: opacity var(--durata-istante) var(--curva-standard);
}
.grafico-mirino.is-visibile { opacity: 1; }

/* Aree sensibili: una colonna intera per mese, invisibile finché non la si
   attraversa. Il lettore mira a un mese, non a una linea di 2px. */
.grafico-colonna {
  fill: transparent;
  cursor: crosshair;
  outline: none;
}
/* Il fuoco da tastiera qui era il solo `fill: var(--accent-tenue)`: un velo
   quasi bianco su fondo bianco, cioè circa 1,06:1 contro lo stato spento —
   un indicatore che tecnicamente c'è e praticamente non si vede. Ora anche un
   contorno dell'accento. `non-scaling-stroke` perché il piano del grafico è
   deformato (`preserveAspectRatio="none"`): senza, il tratto sarebbe spesso
   in orizzontale e sottile in verticale. */
.grafico-colonna:focus-visible {
  fill: var(--accent-tenue);
  stroke: var(--accent);
  stroke-width: 2;
  vector-effect: non-scaling-stroke;
}

/* Le linee "si disegnano" da sinistra: si anima la maschera, non la linea.
   Animare il tratteggio della linea (il trucco classico) non funziona con
   `non-scaling-stroke`, che calcola il tratteggio in pixel. */
.grafico-rivela {
  transform-box: fill-box;
  transform-origin: left center;
  animation: grafico-cresci var(--durata-traccia) var(--curva-traccia) both;
}

@container (max-width: 34rem) {
  .grafico-etichetta-secondaria { display: none; }
}

.grafico-dati { margin-top: var(--space-3); font-size: var(--text-sm); }
.grafico-dati summary { cursor: pointer; color: var(--c-text-soft); font-size: var(--text-xs); }
.grafico-dati table { margin-top: var(--space-2); }
.cella-numero { text-align: right; font-variant-numeric: tabular-nums; }
/* Una precisazione sotto il titolo di colonna («chi riceve»): minuscola, non maiuscoletto. */
.th-nota { display: block; font-size: var(--text-xs); font-weight: 400; text-transform: none; letter-spacing: 0; color: var(--c-text-faint); }
/* Riga di testa di un gruppo in una tabella (un mese nel registro delle ore): stacca il blocco
   e ne porta il totale. */
.riga-gruppo th,
.riga-gruppo td { background: var(--c-bg-sunken); font-weight: 600; }
.riga-gruppo th { text-align: left; text-transform: capitalize; }

/* --- Carico del team: barra impilata dentro la tabella ------------------- */
.colonna-carico { width: 40%; }
.grafico-carico {
  display: block;
  width: 100%;
  min-width: 6rem;
  height: 0.625rem;
  background: var(--c-bg-sunken);
  border-radius: var(--radius);
}
.grafico-carico-ritardo { fill: var(--c-critico); }
.grafico-carico-in-tempo { fill: var(--grafico-serie-2); }
/* Lo stacco fra i due segmenti è del colore del FONDO della scheda: separa
   senza aggiungere un bordo, che sarebbe inchiostro che non è dato. */
.grafico-carico-stacco { stroke: var(--c-surface); stroke-width: 2; }
.grafico-carico rect {
  transform-box: fill-box;
  transform-origin: left center;
  animation: grafico-cresci var(--durata-rivela) var(--curva-rivela) both;
}

/* --- Tooltip -------------------------------------------------------------- */
.grafico-tooltip {
  position: absolute;
  z-index: var(--z-suggerimento);
  pointer-events: none;
  min-width: 8rem;
  max-width: 16rem;
  padding: var(--space-2) var(--space-3);
  background: var(--c-bg-inverse);
  color: var(--c-text-inverse);
  border-radius: var(--radius);
  box-shadow: var(--ombra-media);
  font-size: var(--text-xs);
  line-height: 1.5;
}
.grafico-tooltip[hidden] { display: none; }
.grafico-tooltip-titolo {
  color: rgba(244, 247, 248, 0.65);
  margin-bottom: var(--space-1);
}
.grafico-tooltip-riga { display: flex; align-items: center; gap: var(--space-2); }
.grafico-tooltip-riga strong { font-size: var(--text-sm); font-variant-numeric: tabular-nums; }
.grafico-tooltip-chiave { width: 0.75rem; height: 2px; border-radius: 1px; flex: none; }
.grafico-tooltip-chiave--1 { background: var(--grafico-serie-1); }
.grafico-tooltip-chiave--2 { background: var(--grafico-serie-2); }

/* ===========================================================================
   STATO DEI PERMESSI (pagina Persone)
   ---------------------------------------------------------------------------
   Stato e azione sono due elementi distinti: il pallino + la parola dicono
   com'è il permesso ADESSO, il pulsante accanto dice cosa succede cliccando.
   Mai il colore da solo: "Attivo" / "Non attivo" è scritto.
   =========================================================================== */
/* La matrice dei permessi ha otto colonne: con le intestazioni su una riga sola ("Consegna e
   validazione") l'ultima usciva dalla scheda e si raggiungeva solo scorrendo di lato. */
.tabella-permessi thead th { white-space: normal; vertical-align: bottom; }
.tabella-permessi th,
.tabella-permessi td { padding-inline: var(--space-3); }
.permesso-cella {
  /* Sempre in riga e senza a capo (revisione viste 2026-10, A1): con le sezioni per destinatario
     le colonne sono al più sette, e stato e pulsante affiancati tengono la riga bassa e allineata.
     Prima la matrice unica aveva quindici colonne e la cella andava in colonna. */
  display: flex;
  flex-wrap: nowrap;
  align-items: center;
  gap: var(--space-2);
  white-space: nowrap;
}
.permesso-stato {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--text-xs);
  font-weight: 600;
  white-space: nowrap;
}
.permesso-stato::before {
  content: "";
  width: 0.5rem;
  height: 0.5rem;
  border-radius: 50%;
  border: 1.5px solid currentColor;
}
.permesso-stato--attivo { color: var(--c-positivo); }
.permesso-stato--attivo::before { background: currentColor; }
.permesso-stato--spento { color: var(--c-text-faint); font-weight: 500; }
.permesso-stato--grado { color: var(--c-text-soft); }
.permesso-stato--grado::before { background: currentColor; }

/* --- Filtri arrivati da calendario o statistiche ------------------------- */
/* Non hanno un menu nel modulo: si dichiarano qui, ognuno cliccabile per
   toglierlo. Un elenco ristretto senza dire perché sembra un elenco rotto. */
.filtri-speciali {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
}
.filtro-chip {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-1) var(--space-3);
  border: 1px solid var(--c-border-strong);
  border-radius: var(--radius-pill);
  background: var(--c-surface);
  font-size: var(--text-xs);
  text-decoration: none;
  color: var(--c-text);
}
.filtro-chip:hover { border-color: var(--accent); color: var(--accent); }


/* ===========================================================================
   CRUSCOTTO ESSENZIALE
   =========================================================================== */

/* Riquadri: al massimo cinque, sulla stessa riga su schermo largo. */
/* 9rem e non 11rem: il cruscotto del partner ha sette riquadri, e con 11rem il settimo
   restava da solo nella seconda riga su qualunque schermo da ufficio. */
.griglia--riquadri { grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr)); }

/* Un riquadro che NON è un link (statistiche di sintesi): nessun effetto al
   passaggio del mouse, che prometterebbe un clic che non porta da nessuna
   parte. */
.riquadro--statico { cursor: default; }

/* --- Liste brevi di pratiche --------------------------------------------- */
/* Al posto delle tabelle a tre colonne: nel cruscotto serve riconoscere la
   pratica e capire quanto è urgente, non confrontare colonne. Titolo sopra,
   scadenza e stato sotto, una riga sottile fra una voce e l'altra. */
.lista-pratiche { list-style: none; margin: 0; padding: 0; }
.lista-pratiche-voce {
  display: grid;
  gap: var(--space-1);
  padding: var(--pad-riga) var(--space-5);
  border-bottom: var(--bordo);
}
.lista-pratiche-voce:last-child { border-bottom: 0; }
/* Il filo a sinistra, come nei riquadri: l'unico segnale cromatico. */
.lista-pratiche-voce--critica { box-shadow: inset 3px 0 0 var(--c-critico); }
.lista-pratiche-titolo {
  font-weight: 600;
  text-decoration: none;
  color: var(--c-text);
}
.lista-pratiche-titolo:hover { color: var(--accent); }
.lista-pratiche-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2) var(--space-3);
  font-size: var(--text-sm);
}
.vuoto--compatto { padding: var(--space-5); }

/* ===========================================================================
   CRUSCOTTO — briefing "Adesso", ripresa, calendario a fianco (fase 2)
   =========================================================================== */

/* "Adesso" e il calendario si guardano INSIEME: "cosa faccio ora" e "cosa
   scade nei prossimi giorni" sono la stessa decisione presa da due lati.
   Due terzi / un terzo, e non 50/50: la colonna delle azioni contiene frasi
   e pulsanti, il calendario una griglia di numeri che non ha bisogno di
   larghezza. Sotto i 68rem vanno una sotto l'altra — con "Adesso" per primo,
   che è l'ordine del markup e quindi anche quello della tastiera. */
.griglia-adesso {
  display: grid;
  gap: var(--space-5);
  grid-template-columns: minmax(0, 2fr) minmax(0, 1fr);
}
@media (max-width: 68rem) {
  .griglia-adesso { grid-template-columns: minmax(0, 1fr); }
}

/* Il filo dell'accento in cima alla scheda: è l'unico elemento della pagina
   che si vuole guardare per primo, e basta una riga di colore invece di un
   riquadro colorato che urlerebbe. */
.scheda--adesso { border-top: 2px solid var(--accent); }

.briefing { list-style: none; margin: 0; padding: 0; }

.briefing-voce {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  padding: var(--space-4) var(--space-5);
  border-bottom: var(--bordo);
  /* Bordo sinistro riservato anche quando il tono è neutro: senza, le voci
     critiche si sposterebbero di 3px rispetto alle altre, e lo spostamento
     si nota più del colore. Stessa scelta della voce di navigazione. */
  border-left: 3px solid transparent;
}
.briefing-voce:last-child { border-bottom: 0; }

/* Il TONO arriva dal servizio (`briefing.ts`) come dato, non come classe:
   qui si legge con un selettore di attributo, così non esistono due nomi per
   lo stesso stato. Il colore non è mai l'unico portatore dell'informazione —
   la frase dice già "oltre la data di consegna" — ed è il motivo per cui la
   riga resta leggibile anche stampata in bianco e nero. */
.briefing-voce[data-tono="critico"] { border-left-color: var(--c-critico); background: var(--c-critico-bg); }
.briefing-voce[data-tono="attenzione"] { border-left-color: var(--c-attenzione); }
.briefing-voce[data-tono="neutro"] { border-left-color: var(--c-border-strong); }

.briefing-testo { flex: 1 1 auto; min-width: 0; }

.briefing-titolo {
  margin: 0;
  font-weight: 600;
  /* Non `--font-display`: è una frase operativa, non un titolo. Il serif dei
     titoli qui rallenterebbe la lettura di cinque righe in fila. */
  font-size: var(--text-md);
  line-height: var(--leading-snug);
}

.briefing-dettaglio {
  margin: var(--space-1) 0 0;
  font-size: var(--text-sm);
  color: var(--c-text-soft);
}

/* Il pulsante non si restringe: "Apri l'elenco" su due righe in una lista di
   azioni è il modo più rapido di far sembrare disordinata una colonna. */
.briefing-voce .btn { flex: 0 0 auto; }

@media (max-width: 40rem) {
  /* Su schermo stretto l'azione va sotto il testo e a tutta larghezza: di
     fianco resterebbero poche decine di pixel per la frase. */
  .briefing-voce { flex-wrap: wrap; }
  .briefing-voce .btn { width: 100%; text-align: center; }
}

/* --- Riprendi da dove avevi lasciato ------------------------------------ */
/* Una riga di link, non una scheda: è una scorciatoia, e una scheda le
   darebbe lo stesso peso visivo di un elenco di pratiche in ritardo. */
.riprendi {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
}

.riprendi-etichetta {
  font-size: var(--text-xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: var(--tracking-wide);
  color: var(--c-text-faint);
}

.riprendi-voci {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  list-style: none;
  margin: 0;
  padding: 0;
}

.riprendi-voce {
  display: flex;
  align-items: baseline;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-3);
  background: var(--c-surface);
  border: var(--bordo);
  border-radius: var(--radius);
  text-decoration: none;
  font-size: var(--text-sm);
  transition: border-color var(--durata-breve) var(--curva-standard);
}
.riprendi-voce:hover { border-color: var(--c-text); }

/* Il titolo di una pratica può essere lungo: si taglia, e il riferimento
   accanto resta sempre visibile perché è ciò che la identifica. */
.riprendi-titolo {
  max-width: 22ch;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-weight: 500;
}
.riprendi-meta {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--c-text-faint);
  flex-shrink: 0;
}

/* L'azione di uno stato vuoto: staccata dal testo, mai un pulsante pieno —
   uno stato vuoto è un invito, non un'urgenza. */
.vuoto-azione { margin: var(--space-4) 0 0; }


.vuoto--compatto .vuoto-titolo { font-size: var(--text-base); margin: 0; }

/* --- Calendario delle scadenze -------------------------------------------- */
.calendario { display: grid; gap: var(--space-4); }
.calendario-titolo {
  margin: 0 0 var(--space-2);
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: var(--tracking-wide);
  color: var(--c-text-faint);
  font-weight: 600;
}
.calendario-giorni {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  /* Sette colonne uguali, lunedì → domenica. `minmax(0, 1fr)` e non `1fr`:
     senza lo zero, una colonna con un contenuto più largo (il mese, "+3")
     si allargherebbe a spese delle altre e i giorni non sarebbero più in
     colonna fra le due settimane. */
  grid-template-columns: repeat(7, minmax(0, 1fr));
  gap: var(--space-2);
}
.calendario-giorno {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: var(--space-2);
  min-height: 4.75rem;
  /* Sette colonne nella scheda laterale sono larghe poco più di 40px: con il margine interno
     orizzontale pieno "MAR" e "DOM" uscivano dal bordo. */
  padding: var(--space-2) var(--space-1);
  align-items: center;
  text-align: center;
  min-width: 0;
  overflow: hidden;
  border: var(--bordo);
  border-radius: var(--radius);
  background: var(--c-surface);
  color: var(--c-text);
  text-decoration: none;
  transition: border-color var(--durata-breve) var(--curva-standard), box-shadow var(--durata-breve) var(--curva-standard), transform var(--durata-breve) var(--curva-standard);
}
.calendario-giorno--festivo { background: var(--c-bg-sunken); }
.calendario-giorno--passato { color: var(--c-text-faint); }
/* Oggi: bordo nel colore dello studio, sopra più spesso — come il filo dei
   riquadri, ma in orizzontale. */
.calendario-giorno--oggi {
  border-color: var(--accent);
  box-shadow: inset 0 3px 0 var(--accent);
}
a.calendario-giorno--con-scadenze:hover,
a.calendario-giorno--con-scadenze:focus-visible {
  border-color: var(--c-text);
  box-shadow: var(--ombra-media);
  transform: translateY(-1px);
}

.calendario-intestazione { display: flex; align-items: baseline; gap: var(--space-1); flex-wrap: wrap; }
.calendario-nome {
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: var(--tracking-wide);
  color: var(--c-text-faint);
}
.calendario-numero {
  font-family: var(--font-display);
  font-size: var(--text-lg);
  font-weight: 600;
  line-height: 1;
}
.calendario-giorno--oggi .calendario-numero { color: var(--accent); }
.calendario-mese { font-size: var(--text-xs); color: var(--c-text-faint); }

.calendario-marcatori { display: flex; flex-wrap: wrap; align-items: center; gap: 3px; min-height: 0.5rem; }
.marcatore {
  display: inline-block;
  width: 0.5rem;
  height: 0.5rem;
  border-radius: 50%;
  flex: none;
}
/* Tre toni distinti anche dalla FORMA, non solo dal colore: il rosso del
   ritardo e il cremisi dello studio, fianco a fianco, erano quasi
   indistinguibili. Pieni = richiedono attenzione (ritardo, oggi); anello
   vuoto = pianificazione. */
.marcatore--ritardo { background: var(--c-critico); }
.marcatore--oggi { background: var(--c-attenzione); }
.marcatore--futura { background: transparent; box-shadow: inset 0 0 0 1.5px var(--c-text-soft); }
.marcatore-eccedenza { font-size: var(--text-xs); font-weight: 600; color: var(--c-text-soft); margin-left: 2px; }

/* Su telefono i giorni diventano stretti: si toglie il nome del giorno
   (resta nell'aria-label) e si stringono i margini, i numeri restano. */
@media (max-width: 36rem) {
  .calendario-giorni { gap: 3px; }
  .calendario-giorno { padding: var(--space-1); min-height: 3.75rem; }
  .calendario-nome, .calendario-mese { display: none; }
  .calendario-numero { font-size: var(--text-base); }
  .marcatore { width: 0.375rem; height: 0.375rem; }
}

/* ===========================================================================
   STATISTICHE — aggiunte
   =========================================================================== */
.filtri--compatti { grid-template-columns: repeat(auto-fit, minmax(12rem, 16rem)); }

/* Colonne impilate: colori per chiave di serie. "In ritardo" usa il colore di
   stato critico (riservato, sempre accompagnato dalla parola). */
.grafico-segmento { transform-box: fill-box; }
.grafico-segmento--in-tempo { fill: var(--grafico-serie-2); }
.grafico-segmento--ritardo { fill: var(--c-critico); }
.grafico-stacco {
  stroke: var(--c-surface);
  stroke-width: 2;
  vector-effect: non-scaling-stroke;
}
.grafico-tooltip-chiave--in-tempo { background: var(--grafico-serie-2); }
.grafico-tooltip-chiave--ritardo { background: var(--c-critico); }
/* Fatturabile / non fatturabile (statistiche di timesheet). Coppia NEUTRA di
   proposito: il tempo non fatturabile è un fatto normale — formazione, lavoro
   interno — non un allarme. Usare qui il rosso critico direbbe "errore" dove
   non c'è, e soprattutto lo consumerebbe: in questo progetto --c-critico è
   riservato ai ritardi e compare sempre accompagnato dalla parola. */
.grafico-segmento--fatturabile { fill: var(--grafico-serie-2); }
.grafico-segmento--non-fatturabile { fill: var(--c-text-soft); }
.grafico-campione--fatturabile { background: var(--grafico-serie-2); }
.grafico-campione--non-fatturabile { background: var(--c-text-soft); }
.grafico-tooltip-chiave--fatturabile { background: var(--grafico-serie-2); }
.grafico-tooltip-chiave--non-fatturabile { background: var(--c-text-soft); }
/* La colonna attiva si "solleva" con un velo leggero: le aree sensibili
   stanno sopra le barre, quindi un riempimento semitrasparente le scurisce
   appena senza nasconderle. */
.grafico-colonne .grafico-colonna.is-attivo { fill: rgba(10, 10, 10, 0.05); }
/* Le colonne salgono dal basso invece di allargarsi da sinistra. */
.grafico-rivela--verticale {
  transform-origin: center bottom;
  animation-name: grafico-sali;
}
@keyframes grafico-sali {
  from { transform: scaleY(0); }
  to { transform: scaleY(1); }
}

/* Misura con valore accanto (puntualità per professionista). */
.misura { display: flex; align-items: center; gap: var(--space-3); }
.misura .grafico-carico { flex: 1; }
.misura-valore { font-size: var(--text-sm); font-weight: 600; font-variant-numeric: tabular-nums; min-width: 2.75rem; text-align: right; }


/* --- Stato della scadenza (migrazione 006) ------------------------------- */
/* Proposta del cliente vs impegno dello studio: detto a parole, con un
   pallino pieno o vuoto come secondo segnale. */
.scadenza-stato {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  margin-left: var(--space-2);
  font-size: var(--text-xs);
  white-space: nowrap;
}
.scadenza-stato::before {
  content: "";
  width: 0.4rem;
  height: 0.4rem;
  border-radius: 50%;
  border: 1.5px solid currentColor;
}
.scadenza-stato--confermata { color: var(--c-positivo); }
.scadenza-stato--confermata::before { background: currentColor; }
.scadenza-stato--proposta { color: var(--c-attenzione); }
.avviso--compatto { padding: var(--space-2) var(--space-3); font-size: var(--text-sm); }

/* Avanzamento non ancora possibile: il passo successivo e cosa manca,
   al posto del pulsante. Bordo tratteggiato = "da completare", non errore. */
.avanzamento-bloccato {
  padding: var(--space-3);
  border: 1px dashed var(--c-border-strong);
  border-radius: var(--radius);
  background: var(--c-bg-sunken);
}
.avanzamento-bloccato .etichetta-statica { margin-bottom: var(--space-1); }
.avanzamento-bloccato p { margin: 0; color: var(--c-text-soft); }

/* ===========================================================================
   ELENCO PRATICHE INTERATTIVO (public/js/elenco-pratiche.js)
   =========================================================================== */
/* Durante il caricamento i risultati restano visibili ma attenuati:
   nessuno scheletro vuoto, nessun salto di impaginazione. */
[data-elenco-risultati] { transition: opacity var(--durata-breve) var(--curva-standard); }
[data-elenco-risultati][aria-busy="true"] { opacity: 0.55; }

/* La riga della pratica che ha il focus (j/k da tastiera o Tab): evidenziata
   con lo stesso filo dello studio usato altrove, così si vede dove si è. */
tbody tr:focus-within { background: var(--accent-tenue); }
tbody tr:focus-within td:first-child { box-shadow: inset 3px 0 0 var(--accent); }

.scorciatoie { margin: 0; }
kbd {
  display: inline-block;
  min-width: 1.4em;
  padding: 0 0.35em;
  border: 1px solid var(--c-border-strong);
  border-bottom-width: 2px;
  border-radius: var(--radius);
  background: var(--c-surface);
  font-family: var(--font-mono);
  font-size: 0.85em;
  line-height: 1.5;
  text-align: center;
  color: var(--c-text);
}

/* ===========================================================================
   CARICAMENTO DOCUMENTI (public/js/carica-documenti.js)
   =========================================================================== */
/* La zona diventa un bersaglio visibile solo con JavaScript attivo (classe
   aggiunta dallo script): senza, resta un normale campo file. */
.zona-rilascio--attiva {
  padding: var(--space-4);
  border: 1.5px dashed var(--c-border-strong);
  border-radius: var(--radius);
  background: var(--c-surface);
  transition: border-color var(--durata-breve) var(--curva-standard), background-color var(--durata-breve) var(--curva-standard);
}
.zona-rilascio--sopra {
  border-color: var(--accent);
  background: var(--accent-tenue);
}
.zona-rilascio-suggerimento { margin: 0 0 var(--space-2); font-size: var(--text-sm); color: var(--c-text-soft); }

.caricamenti { list-style: none; margin: var(--space-3) 0 0; padding: 0; display: grid; gap: var(--space-2); }
.caricamenti:empty { display: none; }
.caricamento {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: var(--space-1) var(--space-3);
  align-items: center;
  font-size: var(--text-sm);
}
.caricamento-nome { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 600; }
.caricamento-dimensione { color: var(--c-text-faint); font-variant-numeric: tabular-nums; }
.caricamento-barra {
  width: 100%;
  height: 0.375rem;
  appearance: none;
  border: 0;
  border-radius: var(--radius-xs);
  background: var(--c-bg-sunken);
  overflow: hidden;
}
.caricamento-barra::-webkit-progress-bar { background: var(--c-bg-sunken); }
.caricamento-barra::-webkit-progress-value { background: var(--grafico-serie-2); transition: width var(--durata-istante) linear; }
.caricamento-barra::-moz-progress-bar { background: var(--grafico-serie-2); }
.caricamento-stato { font-size: var(--text-xs); color: var(--c-text-soft); text-align: right; font-variant-numeric: tabular-nums; }
.caricamento--fatto .caricamento-barra::-webkit-progress-value { background: var(--c-positivo); }
.caricamento--fatto .caricamento-barra::-moz-progress-bar { background: var(--c-positivo); }
.caricamento--fatto .caricamento-stato { color: var(--c-positivo); font-weight: 600; }
.caricamento--errore .caricamento-stato { color: var(--c-critico); font-weight: 600; }
.caricamento--errore .caricamento-barra { opacity: 0.4; }


/* ===========================================================================
   CONSOLE DI PIATTAFORMA (views/admin)
   ---------------------------------------------------------------------------
   Stesso sistema del resto dell'applicazione; poche aggiunte. La barra è
   scura (fondo invertito) perché la console deve essere riconoscibile a colpo
   d'occhio come ALTRO rispetto allo studio: chi opera qui agisce sui dati di
   terzi, e confondere le due aree sarebbe un errore con conseguenze.
   =========================================================================== */
.barra--piattaforma { background: var(--c-bg-inverse); border-bottom-color: var(--c-bg-inverse); }
/* Il marchio della console: il lockup negativo con payoff, e "Piattaforma" accanto. Più basso che
   nella colonna degli studi, perché sta in una barra. */
.marchio--logo { display: inline-flex; align-items: center; gap: var(--space-3); }
.marchio--logo .logo {
  height: 3.25rem;
  width: calc(3.25rem * 2.73);
  background-image: var(--logo-inverso);
}
.barra--piattaforma .marchio,
.barra--piattaforma .utente-nome { color: var(--c-text-inverse); }
.barra--piattaforma .nav-voce,
.barra--piattaforma .utente-ruolo { color: rgba(244, 247, 248, 0.65); }
.barra--piattaforma .nav-voce:hover,
.barra--piattaforma .nav-voce[aria-current="page"] { color: var(--c-text-inverse); }
.barra--piattaforma .btn--fantasma { color: var(--c-text-inverse); border-color: rgba(244, 247, 248, 0.3); }
.barra--piattaforma .btn--fantasma:hover { background: rgba(244, 247, 248, 0.1); color: var(--c-text-inverse); }
.barra--piattaforma .utente { border-left-color: rgba(244, 247, 248, 0.2); }

/* Pagine fuori dal telaio degli studi (anticamera, pagina iniziale): il marchio in alto, sopra il
   riquadro. */
.pagina-sola-marchio { margin-bottom: var(--space-5); }

/* Pagine con un solo riquadro centrato (login, errore): lo spazio in alto che
   prima era un attributo style=, bloccato dalla CSP. */
.pagina-sola { padding-top: var(--space-8); }

.stato-studio {
  display: inline-block;
  padding: 0 var(--space-2);
  border-radius: var(--radius-pill);
  font-size: var(--text-xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: var(--tracking-wide);
}
.stato-studio--attivo { background: var(--c-positivo-bg); color: var(--c-positivo); }
.stato-studio--sospeso { background: var(--c-attenzione-bg); color: var(--c-attenzione); }

tbody tr.riga--tenue td { color: var(--c-text-faint); }

.etichetta-in-linea {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  text-transform: none;
  letter-spacing: 0;
  font-size: var(--text-sm);
  color: var(--c-text);
}
.etichetta-in-linea input { width: auto; }
input[type="color"] { width: 4rem; height: 2.25rem; padding: 2px; }

.dettagli-modulo > summary { cursor: pointer; font-weight: 600; margin-bottom: var(--space-3); }

.modulo-permesso { display: flex; gap: var(--space-2); align-items: center; flex-wrap: wrap; }
.modulo-permesso input[type="text"] { flex: 1; min-width: 12rem; }

/* --- Password temporanea, mostrata una volta --------------------------- */
.credenziali-dati { display: grid; gap: var(--space-4); margin: 0; }
.credenziali-dati dd { margin: 0; }
.credenziali-password {
  font-size: var(--text-xl);
  letter-spacing: 0.05em;
  padding: var(--space-3) var(--space-4);
  border: 1px dashed var(--c-border-strong);
  border-radius: var(--radius);
  background: var(--c-bg-sunken);
  user-select: all;
}

/* --- Registro di piattaforma ------------------------------------------- */
.registro { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-4); }
.registro-voce {
  padding-left: var(--space-4);
  border-left: 3px solid var(--c-border-strong);
}
/* Il filo colora la FAMIGLIA di azione; il testo dice comunque quale. */
.registro-voce--studio { border-left-color: var(--grafico-serie-2); }
.registro-voce--account { border-left-color: var(--accent); }
.registro-voce--admin { border-left-color: var(--c-text-soft); }
.registro-testa { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--space-2) var(--space-3); }
.registro-azione { font-weight: 600; }
.registro-studio { font-size: var(--text-xs); }
.registro-data { font-size: var(--text-xs); color: var(--c-text-faint); margin-left: auto; }
.registro-descrizione { margin: var(--space-1) 0; }
.registro-motivazione { margin: var(--space-1) 0; font-size: var(--text-sm); }
.registro-motivazione .etichetta-statica { display: inline; margin-right: var(--space-2); }
.registro-modifiche { margin: var(--space-2) 0; font-size: var(--text-sm); width: auto; }
.registro-modifiche th, .registro-modifiche td { padding: var(--space-1) var(--space-3); }
.registro-autore { margin: 0; }

/* ==========================================================================
 * COMUNICAZIONI — spalla laterale e pagina intera (step 6)
 * ==========================================================================
 * Un componente, due modi (views/comunicazioni/guscio.ejs):
 *   .comunicazioni--pannello  spalla fissa a destra o a sinistra, sopra la
 *                             pagina, che resta usabile (non è una finestra
 *                             modale: si scrive guardando la pratica);
 *   .comunicazioni--pagina    /comunicazioni, due colonne su schermo largo.
 *
 * Il registro visivo resta quello del gestionale (bianco, nero editoriale,
 * accento dello studio), ma le bolle hanno angoli arrotondati: è la forma
 * che chiunque riconosce come "chat", e qui la riconoscibilità vale più della
 * coerenza con gli angoli quasi vivi del resto dell'interfaccia.
 *
 * Tre viste, una alla volta, scelte dall'attributo data-vista sulla radice:
 * lo stato vive in UN attributo letto dal CSS, non in classi da tenere
 * allineate a mano.
 *
 * Leve per cambiare l'aspetto, tutte qui sotto: larghezza della spalla
 * (--com-larghezza), colore delle bolle proprie (--com-bolla-mia), raggio
 * delle bolle (--com-raggio), fondo dell'area messaggi (--com-fondo-messaggi).
 */
:root { --com-larghezza: 26rem; }

.comunicazioni {
  --com-raggio: 0.9rem;
  --com-bolla-mia: var(--accent-tenue);
  --com-bolla-altrui: var(--c-surface);
  --com-fondo-messaggi: var(--c-bg-sunken);
  background: var(--c-surface);
  color: var(--c-text);
}

/* --- Spalla laterale ------------------------------------------------------ */
.comunicazioni--pannello {
  position: fixed;
  top: 0;
  bottom: 0;
  right: 0;
  z-index: var(--z-spalla);
  width: min(var(--com-larghezza), 100vw);
  display: flex;
  flex-direction: column;
  border-left: var(--bordo);
  box-shadow: -12px 0 32px rgba(10, 10, 10, 0.12);
  transform: translateX(100%);
  visibility: hidden;
  /* Chiudendo, `visibility` cambia DOPO la transizione (ritardo = durata):
     il pannello scivola via, e solo allora esce dall'ordine di tabulazione. */
  transition: transform var(--durata-media) var(--curva-standard), visibility 0s linear var(--durata-media);
}
.comunicazioni--pannello[data-lato="sinistra"] {
  right: auto;
  left: 0;
  border-left: none;
  border-right: var(--bordo);
  box-shadow: 12px 0 32px rgba(10, 10, 10, 0.12);
  transform: translateX(-100%);
}
.comunicazioni--pannello[data-aperto="true"] {
  transform: translateX(0);
  visibility: visible;
  transition: transform var(--durata-media) var(--curva-standard), visibility 0s;
}
.comunicazioni--pannello[data-senza-transizione] { transition: none; }

/* Schermi molto larghi: la pagina fa spazio alla spalla invece di finirle
   sotto. Sotto questa soglia la spalla copre il margine della pagina, che è
   comunque centrata e con bordi ampi. */
@media (min-width: 100rem) {
  html[data-comunicazioni-aperte="destra"] body { padding-right: var(--com-larghezza); }
  html[data-comunicazioni-aperte="sinistra"] body { padding-left: var(--com-larghezza); }
}

.com-vista {
  display: none;
  flex-direction: column;
  flex: 1;
  min-height: 0; /* senza, un figlio flex non può scorrere dentro di sé */
}
.comunicazioni[data-vista="elenco"] .com-vista--elenco,
.comunicazioni[data-vista="conversazione"] .com-vista--conversazione,
.comunicazioni[data-vista="nuova"] .com-vista--nuova { display: flex; }

/* Il contenuto dei frammenti riempie la vista. */
.com-conversazione,
.com-nuova {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-height: 0;
}

/* --- Pagina intera ------------------------------------------------------- */
/* La conversazione a tutta pagina occupa lo spazio che resta, SENZA numeri
   magici.

   Prima: `height: calc(100vh - 9rem)`, dove 9rem era la somma a mano di barra
   e margini. MISURATO nel browser dopo il passaggio al telaio (testata più
   bassa della vecchia barra): restavano 46,8px vuoti sotto la chat, con la
   pagina che non scorreva — cioè spazio buttato, non un difetto vistoso, ma
   il tipo di scarto che si ripresenta ad ogni ritocco della cornice.

   Ora la misura la fa il layout: `.telaio-corpo` è una colonna flessibile,
   `main` prende lo spazio rimasto, e questa pagina lo passa al suo unico
   figlio. `min-height: 0` serve perché un elemento flessibile, per
   impostazione predefinita, non scende sotto la propria altezza di contenuto:
   senza, una conversazione lunga farebbe crescere la pagina invece di
   scorrere dentro di sé. Se domani la testata cambia altezza, qui non c'è
   nulla da aggiornare. */
.com-pagina {
  padding-block: var(--space-5);
  display: flex;
  flex-direction: column;
  min-height: 0;
}
.comunicazioni--pagina {
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  height: auto;
  min-height: 28rem;
  border: var(--bordo);
}
.comunicazioni--pagina .com-solo-pannello { display: none; }

@media (min-width: 56rem) {
  .comunicazioni--pagina {
    display: grid;
    grid-template-columns: minmax(18rem, 24rem) 1fr;
  }
  /* L'elenco resta sempre a sinistra, la destra mostra la vista scelta. */
  .comunicazioni--pagina .com-vista--elenco {
    display: flex;
    grid-column: 1;
    grid-row: 1;
    border-right: var(--bordo);
  }
  .comunicazioni--pagina .com-vista--conversazione,
  .comunicazioni--pagina .com-vista--nuova,
  .comunicazioni--pagina .com-vista--vuota {
    grid-column: 2;
    grid-row: 1;
  }
  .comunicazioni--pagina[data-vista="elenco"] .com-vista--vuota {
    display: flex;
    align-items: center;
    justify-content: center;
    text-align: center;
    color: var(--c-text-soft);
    background: var(--com-fondo-messaggi);
  }
  .comunicazioni--pagina .com-vista--vuota p { margin: 0; }
  .comunicazioni--pagina .com-indietro:not(.com-indietro--sempre) { display: none; }
}

/* --- Testata di ogni vista ---------------------------------------------- */
.com-testa {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  min-height: 3.5rem;
  padding: var(--space-2) var(--space-3) var(--space-2) var(--space-4);
  border-bottom: var(--bordo);
  flex-shrink: 0;
}
.com-testa--conversazione,
.com-nuova .com-testa { padding-left: var(--space-2); }
.com-titolo {
  margin: 0;
  font-size: var(--text-md);
  line-height: var(--leading-snug);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.com-titolo:focus { outline: none; }
.com-testa-dati { flex: 1; min-width: 0; }
.com-vista--elenco .com-titolo { flex: 1; }
.com-sottotitolo {
  margin: 0;
  font-size: var(--text-xs);
  color: var(--c-text-soft);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.com-strumenti { display: flex; align-items: center; gap: 0.15rem; flex-shrink: 0; }

.com-icona {
  display: inline-grid;
  place-items: center;
  width: 2.25rem;
  height: 2.25rem;
  padding: 0;
  border: none;
  border-radius: var(--radius-pill);
  background: transparent;
  color: var(--c-text-soft);
  cursor: pointer;
  text-decoration: none;
}
.com-icona:hover { background: var(--c-bg-sunken); color: var(--c-text); }
.com-icona svg,
.com-invia svg,
.com-documento svg {
  width: 1.15rem;
  height: 1.15rem;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
  flex-shrink: 0;
}
.com-icona--primaria { background: var(--accent); color: #fff; }
.com-icona--primaria:hover { background: var(--accent-scuro); color: #fff; }

/* --- Ricerca e filtri --------------------------------------------------- */
.com-cerca { padding: var(--space-3) var(--space-4) var(--space-2); flex-shrink: 0; }
.com-cerca input {
  width: 100%;
  padding: 0.5rem 0.85rem;
  border: var(--bordo);
  border-radius: var(--radius-pill);
  background: var(--c-bg-sunken);
  font: inherit;
  font-size: var(--text-sm);
}
.com-filtri {
  display: flex;
  gap: 0.35rem;
  padding: 0 var(--space-4) var(--space-3);
  overflow-x: auto;
  flex-shrink: 0;
  border-bottom: var(--bordo);
}
.com-filtro {
  padding: 0.25rem 0.7rem;
  border: var(--bordo);
  border-radius: var(--radius-pill);
  background: var(--c-surface);
  color: var(--c-text-soft);
  font: inherit;
  font-size: var(--text-xs);
  font-weight: 600;
  white-space: nowrap;
  cursor: pointer;
}
.com-filtro[aria-pressed="true"] {
  background: var(--c-text);
  border-color: var(--c-text);
  color: var(--c-bg);
}

/* --- Storico ------------------------------------------------------------ */
.com-scorrimento { flex: 1; min-height: 0; overflow-y: auto; }
.com-elenco { list-style: none; margin: 0; padding: 0; }
.com-voce {
  display: flex;
  gap: var(--space-3);
  align-items: flex-start;
  padding: var(--space-3) var(--space-4);
  color: inherit;
  text-decoration: none;
  border-bottom: 1px solid var(--c-bg-sunken);
}
a.com-voce:hover { background: var(--c-bg-sunken); }
.com-voce--attiva,
a.com-voce--attiva:hover { background: var(--accent-tenue); }
.com-voce-corpo { display: flex; flex-direction: column; gap: 0.05rem; flex: 1; min-width: 0; }
.com-voce-riga { display: flex; align-items: center; gap: var(--space-2); min-width: 0; }
.com-voce-titolo {
  flex: 1;
  min-width: 0;
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.com-voce-ora { font-size: var(--text-xs); color: var(--c-text-faint); white-space: nowrap; }
.com-voce-ora--nuova { color: var(--accent); font-weight: 700; }
.com-voce-sotto,
.com-voce-anteprima {
  font-size: var(--text-sm);
  color: var(--c-text-soft);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.com-voce-sotto { font-size: var(--text-xs); color: var(--c-text-faint); }
.com-voce-anteprima { flex: 1; min-width: 0; }
.com-voce-chi { color: var(--c-text); font-weight: 600; }

.com-non-letti {
  display: inline-grid;
  place-items: center;
  min-width: 1.35rem;
  height: 1.35rem;
  padding-inline: 0.35rem;
  border-radius: var(--radius-pill);
  background: var(--accent);
  color: #fff;
  font-size: var(--text-xs);
  font-weight: 700;
  line-height: 1;
  flex-shrink: 0;
}

/* Avatar tondo, colore per TIPO di conversazione. Il tipo è sempre detto
   anche a parole (sottotitolo, fascia del pubblico): il colore aiuta soltanto
   a scorrere l'elenco. */
.com-avatar {
  display: grid;
  place-items: center;
  width: 2.6rem;
  height: 2.6rem;
  border-radius: 50%;
  flex-shrink: 0;
  background: var(--c-bg-sunken);
  color: var(--c-text-soft);
  font-size: var(--text-xs);
  font-weight: 700;
  letter-spacing: 0.02em;
}
.com-avatar--colleghi { background: var(--accent-tenue); color: var(--accent-scuro); }
.com-avatar--interna { background: var(--c-attenzione-bg); color: var(--c-attenzione); }
.com-avatar--esterna { background: var(--c-info-bg); color: var(--c-info); }
.com-avatar--piattaforma { background: var(--c-bg-inverse); color: var(--c-text-inverse); }
.com-testa .com-avatar { width: 2.25rem; height: 2.25rem; }

/* --- Conversazione ------------------------------------------------------ */
/* Il PUBBLICO della conversazione, sempre in vista sopra i messaggi. */
.com-pubblico {
  margin: 0;
  padding: 0.45rem var(--space-4);
  font-size: var(--text-xs);
  border-bottom: var(--bordo);
  background: var(--c-bg-sunken);
  color: var(--c-text-soft);
  flex-shrink: 0;
}
.com-pubblico--interna { background: var(--c-attenzione-bg); color: var(--c-attenzione); }
.com-pubblico--esterna { background: var(--c-info-bg); color: var(--c-info); }

.com-scorrimento--messaggi {
  background: var(--com-fondo-messaggi);
  padding: var(--space-2) var(--space-3) var(--space-4);
}
.com-messaggi {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
}
.com-giorno {
  align-self: center;
  margin: var(--space-3) 0 var(--space-1);
}
.com-giorno span {
  display: inline-block;
  padding: 0.15rem 0.7rem;
  border-radius: var(--radius-pill);
  background: var(--c-surface);
  border: var(--bordo);
  font-size: var(--text-xs);
  color: var(--c-text-soft);
}
.com-messaggio { display: flex; }
.com-messaggio--seguito { margin-top: -0.15rem; }
.com-messaggio--mio { justify-content: flex-end; }

.com-bolla {
  max-width: min(85%, 34rem);
  padding: 0.45rem 0.7rem 0.3rem;
  border-radius: var(--com-raggio);
  border-top-left-radius: 0.25rem;
  background: var(--com-bolla-altrui);
  border: var(--bordo);
  box-shadow: var(--ombra-lieve);
}
.com-messaggio--mio .com-bolla {
  background: var(--com-bolla-mia);
  border-color: transparent;
  border-top-left-radius: var(--com-raggio);
  border-top-right-radius: 0.25rem;
}
.com-messaggio--seguito .com-bolla { border-radius: var(--com-raggio); }
.com-messaggio--nuovo .com-bolla { animation: com-arriva var(--durata-media) ease-out; }
@keyframes com-arriva {
  from { opacity: 0; transform: translateY(6px); }
  to { opacity: 1; transform: none; }
}

.com-autore {
  margin: 0 0 0.1rem;
  font-size: var(--text-xs);
  font-weight: 700;
  color: var(--accent-scuro);
}
.com-testo {
  margin: 0;
  white-space: pre-wrap;
  overflow-wrap: anywhere; /* un indirizzo lunghissimo non allarga la bolla */
  line-height: var(--leading-snug);
}
.com-ora {
  display: block;
  margin-top: 0.1rem;
  text-align: right;
  font-size: 0.7rem;
  color: var(--c-text-faint);
}
.com-documento {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  margin-top: 0.35rem;
  padding: 0.4rem 0.55rem;
  border-radius: 0.5rem;
  background: rgba(10, 10, 10, 0.05);
  color: var(--c-text);
  font-size: var(--text-sm);
  text-decoration: none;
  overflow-wrap: anywhere;
}
.com-documento:hover { background: rgba(10, 10, 10, 0.09); }

/* --- Composizione ------------------------------------------------------- */
.com-scrivi {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: end;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-3);
  border-top: var(--bordo);
  background: var(--c-surface);
  flex-shrink: 0;
}
.com-scrivi textarea {
  width: 100%;
  min-height: 2.5rem;
  max-height: 10rem;
  padding: 0.55rem 0.9rem;
  border: var(--bordo);
  border-radius: 1.25rem;
  background: var(--c-bg-sunken);
  font: inherit;
  line-height: var(--leading-snug);
  resize: none;
}
.com-invia {
  display: grid;
  place-items: center;
  width: 2.5rem;
  height: 2.5rem;
  border: none;
  border-radius: 50%;
  background: var(--accent);
  color: #fff;
  cursor: pointer;
}
.com-invia:hover { background: var(--accent-scuro); }
.com-invia:disabled { opacity: 0.55; cursor: progress; }
.com-errore {
  grid-column: 1 / -1;
  margin: 0;
  font-size: var(--text-xs);
  color: var(--c-critico);
}
.com-sola-lettura {
  margin: 0;
  padding: var(--space-3) var(--space-4);
  border-top: var(--bordo);
  font-size: var(--text-sm);
  color: var(--c-text-soft);
  text-align: center;
  flex-shrink: 0;
}

/* --- Nuova conversazione ------------------------------------------------ */
.com-sezione-titolo {
  margin: 0;
  padding: var(--space-3) var(--space-4) var(--space-1);
  font-family: var(--font-ui);
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: var(--tracking-wide);
  color: var(--c-text-faint);
}
.com-canali { display: flex; flex-wrap: wrap; gap: 0.35rem; margin-top: 0.35rem; }
.com-canale {
  padding: 0.2rem 0.65rem;
  border-radius: var(--radius-pill);
  font-size: var(--text-xs);
  font-weight: 600;
  text-decoration: none;
  background: var(--c-bg-sunken);
  color: var(--c-text);
}
.com-canale--interna { background: var(--c-attenzione-bg); color: var(--c-attenzione); }
.com-canale--esterna { background: var(--c-info-bg); color: var(--c-info); }
.com-canale:hover { text-decoration: underline; }

/* --- Stati vuoti --------------------------------------------------------- */
.com-vuoto,
.com-caricamento {
  margin: 0;
  padding: var(--space-6) var(--space-4);
  text-align: center;
  font-size: var(--text-sm);
  color: var(--c-text-soft);
}
.com-vuoto p { margin: 0; }
.com-vuoto-titolo { margin: 0 0 var(--space-1); font-weight: 600; color: var(--c-text); }

/* --- Pulsante "Messaggi" in barra: stesso contatore di "Avvisi" ------------ */
.nav-voce--contatore { padding-right: 1.9rem; }
.campanello-conteggio[data-conteggio-messaggi="0"] { display: none; }

/* --- Scheda "Conversazioni" nella pagina della pratica -------------------- */
.canali-pratica { list-style: none; margin: 0; display: grid; gap: var(--space-4); }
.canale-pratica { display: flex; align-items: center; gap: var(--space-3); }
.canale-pratica-dati { flex: 1; min-width: 0; }
.canale-pratica-dati p { margin: 0; }
.canale-pratica-titolo { display: flex; align-items: center; gap: var(--space-2); font-weight: 600; }

@media print {
  .comunicazioni--pannello { display: none; }
}

/* ===========================================================================
   SOGGETTI DEL FASCICOLO E CONFLITTI (migrazione 014)
   ---------------------------------------------------------------------------
   Il colore qui segue la regola già adottata per i ritardi: `--c-critico` è
   riservato a ciò che richiede una decisione, non a ciò che è semplicemente
   diverso. Un conflitto DIRETTO è critico; uno POTENZIALE è attenzione; una
   verifica senza riscontri è neutra e non deve rubare lo sguardo.
   =========================================================================== */
.elenco-piatto { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-2); }

.badge--derogato { color: var(--c-critico); background: var(--c-critico-bg); border-color: transparent; }
.badge--senza-conflitto { color: var(--c-positivo); background: var(--c-positivo-bg); border-color: transparent; }
.badge--diretto { color: var(--c-critico); background: var(--c-critico-bg); border-color: transparent; }
.badge--potenziale { color: var(--c-attenzione); background: var(--c-attenzione-bg); border-color: transparent; }

/* Un riscontro è una riga da LEGGERE, non un avviso da scorrere: il filo
   colorato a sinistra lo lega alla sua gravità senza riempire di fondo pieno
   un elenco che può contenerne dieci. */
.riscontri { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-3); }
.riscontro {
  border-left: 3px solid var(--c-border-strong);
  padding: var(--space-2) var(--space-4);
  background: var(--c-bg-sunken);
  border-radius: 0 var(--radius) var(--radius) 0;
}
.riscontro--diretto { border-left-color: var(--c-critico); }
.riscontro--potenziale { border-left-color: var(--c-attenzione); }
.riscontro-testo { margin: 0; font-size: var(--text-sm); }
.riscontro-dove { margin: var(--space-1) 0 0; font-size: var(--text-xs); color: var(--c-text-faint); }

/* Gruppo di campi che descrivono UNA cosa sola (un titolare effettivo, 015):
   il bordo tiene insieme le righe che vanno lette come un blocco, e il
   `legend` dice quale delle quattro si sta compilando. Senza, quattro gruppi
   identici uno sotto l'altro diventano una colonna di campi indistinguibili. */
.gruppo-campi {
  border: 1px solid var(--c-border);
  border-radius: var(--radius);
  padding: var(--space-4);
  margin: 0 0 var(--space-4);
}
.gruppo-campi:last-child { margin-bottom: 0; }
.gruppo-campi > legend {
  padding: 0 var(--space-2);
  color: var(--c-text-soft);
  font-weight: 600;
}

/* CONTROLLO DI GESTIONE — il conto top-down (SAGOMA-CONTROLLO-GESTIONE §11.2). Il peso della riga dice
   che cosa è: sezione, voce, subtotale, totale. Lo scostamento a sfavore è rosso, a favore verde; il segno
   resta scritto, il colore non è mai l'unico segnale. */
.tabella-controllo .riga-sezione td {
  padding-top: var(--space-4);
  font-weight: 700;
  color: var(--c-text-soft);
  text-transform: uppercase;
  letter-spacing: .04em;
  font-size: .78rem;
}
.tabella-controllo .riga-dettaglio td:first-child { padding-left: var(--space-5); color: var(--c-text-soft); font-size: .9em; }
.tabella-controllo .riga-nota td { color: var(--c-text-soft); font-size: .9em; }
.tabella-controllo .riga-subtotale td { font-weight: 600; border-top: 1px solid var(--c-border); }
.tabella-controllo .riga-totale td { font-weight: 700; border-top: 2px solid var(--c-text); }
.tabella-controllo .riga-percentuale td { color: var(--c-text-soft); }
.valore-sfavorevole { color: var(--c-critico); }
.valore-favorevole { color: var(--c-positivo); }

/* CONTROLLO DI GESTIONE — il piano bottom-up (SAGOMA-CONTROLLO-GESTIONE §14). Stesso lessico del conto
   top-down e dei grafici delle statistiche: riquadri col filo, tabelle a peso di riga, piano 0-100 stirato.
   Le cinque serie della composizione dei ricavi partono dall'accento e restano nella tavolozza del design
   system; il rosso è riservato a ciò che supera una soglia. */
.riquadro-nota {
  margin-top: var(--space-1);
  font-size: var(--text-xs);
  color: var(--c-text-soft);
  font-variant-numeric: tabular-nums;
}
.riquadro-numero--medio { font-size: var(--text-xl); }

.badge--favorevole { color: var(--c-positivo); background: var(--c-positivo-bg); border-color: transparent; }
.badge--sfavorevole { color: var(--c-critico); background: var(--c-critico-bg); border-color: transparent; }

.bu-serie-1, .bu-campione-1 { fill: var(--grafico-serie-1); background: var(--grafico-serie-1); }
.bu-serie-2, .bu-campione-2 { fill: var(--grafico-serie-2); background: var(--grafico-serie-2); }
.bu-serie-3, .bu-campione-3 { fill: var(--kx-teal-300); background: var(--kx-teal-300); }
.bu-serie-4, .bu-campione-4 { fill: var(--kx-warning-500); background: var(--kx-warning-500); }
.bu-serie-5, .bu-campione-5 { fill: var(--kx-neutral-300); background: var(--kx-neutral-300); }

/* La barra della composizione: un solo binario, i tratti affiancati, separati da un filo del fondo. */
.bu-composizione { padding-bottom: 0; }
.bu-composizione-barra {
  display: block;
  width: 100%;
  height: 0.875rem;
  border-radius: var(--radius-pill);
  background: var(--c-bg-sunken);
  overflow: hidden;
}
.bu-composizione-barra rect {
  stroke: var(--c-surface);
  stroke-width: 2;
  transform-box: fill-box;
  transform-origin: left center;
  animation: grafico-cresci var(--durata-rivela) var(--curva-rivela) both;
}
.bu-composizione-legenda { list-style: none; padding: 0; margin: var(--space-3) 0 0; }

.tabella-bu tbody td { vertical-align: top; }
.tabella-bu .bu-riga-consuntivo td {
  background: var(--c-bg-sunken);
  color: var(--c-text-soft);
  font-style: italic;
}

/* Un KPI fuori soglia: il colore e un pallino, e per chi non vede il colore un testo per i lettori. */
.bu-fuori { color: var(--c-critico); font-weight: 600; }
.bu-fuori::before {
  content: "";
  display: inline-block;
  width: 6px;
  height: 6px;
  margin-right: 6px;
  border-radius: 50%;
  background: currentColor;
  vertical-align: middle;
}
.tabella-bu-kpi td:first-child { min-width: 14rem; }

/* La sensibilità: la riga della capacità attuale è il punto di riferimento della tavola. */
.tabella-bu-sensibilita .bu-riga-capacita td { background: var(--accent-tenue); }
.tabella-bu-sensibilita .bu-riga-capacita td:first-child { box-shadow: inset 3px 0 0 var(--accent); }
.bu-badge-capacita { margin-left: var(--space-2); color: var(--accent-scuro); background: var(--c-surface); }
.tabella-bu-sensibilita .bu-colonna-griglia { color: var(--c-text-soft); }

/* La cassa: lo stesso corpo dei grafici a linee, con un asse più largo perché porta importi. */
.bu-cassa { margin-top: var(--space-2); }
.bu-cassa-corpo {
  grid-template-columns: 6rem minmax(0, 1fr) 0.75rem;
  grid-template-rows: 15rem 1.75rem;
}
.bu-colonna {
  transform-box: fill-box;
  transform-origin: center bottom;
  animation: bu-sali var(--durata-rivela) var(--curva-rivela) both;
}
.bu-colonna--entrata { fill: var(--grafico-serie-2); }
.bu-colonna--uscita { fill: var(--kx-neutral-300); transform-origin: center top; }
.bu-campione-entrata { background: var(--grafico-serie-2); }
.bu-campione-uscita { background: var(--kx-neutral-300); }
@keyframes bu-sali {
  from { transform: scaleY(0); }
  to { transform: scaleY(1); }
}

/* Il modulo del piano: chiuso dietro la sua testata, si apre senza JavaScript. */
.bu-modulo > summary { cursor: pointer; list-style: none; }
.bu-modulo > summary::-webkit-details-marker { display: none; }
.bu-modulo > summary::after {
  content: "+";
  margin-left: auto;
  font-size: var(--text-xl);
  line-height: 1;
  color: var(--c-text-soft);
}
.bu-modulo[open] > summary::after { content: "−"; }
.bu-modulo > summary:hover h2 { color: var(--accent-scuro); }
.tabella-bu-modulo td { padding: var(--space-1) var(--space-2); }
.tabella-bu-modulo input[type="text"], .tabella-bu-modulo select { width: 100%; }
.tabella-bu-modulo td:first-child input { min-width: 8rem; }
.tabella-bu-modulo td:nth-child(2) select { min-width: 8.5rem; }
.bu-campo-nota { grid-column: span 2; }
@media (max-width: 40rem) {
  .bu-campo-nota { grid-column: auto; }
}

/* I piedi delle tabelle del controllo (totali): stessa cella del corpo. Senza, il totale partiva dal
   bordo della scheda, sfalsato rispetto alle righe sopra. */
tfoot td { padding: var(--pad-cella) var(--space-4); }

/* La capacità ha undici colonne: celle più strette, cifre senza a capo. Sotto i ~70rem la tabella
   scorre dentro il suo contenitore, come promette .tabella-contenitore. */
.tabella-bu th, .tabella-bu td { padding-inline: var(--space-2); }
.tabella-bu th:first-child, .tabella-bu td:first-child { padding-left: var(--space-5); }
.tabella-bu th:last-child, .tabella-bu td:last-child { padding-right: var(--space-5); }
.tabella-bu td.cella-numero { white-space: nowrap; }
.tabella-bu td:first-child { min-width: 9rem; }
.tabella-bu-sensibilita .bu-testa-gruppi th { border-bottom: 0; padding-bottom: 0; text-align: center; }
.tabella-bu-sensibilita .bu-testa-gruppi th.bu-colonna-griglia,
.tabella-bu-sensibilita tr > .bu-colonna-griglia:nth-child(6) { border-left: var(--bordo); }
/* Un fieldset ha di natura min-width: min-content: senza azzerarlo la tabella delle figure lo allarga oltre
   la scheda invece di scorrere nel suo contenitore. Nelle griglie del modulo lo spazio lo dà il gap: il
   margine dell'ultimo campo sfalserebbe la riga. */
.bu-modulo .gruppo-campi { min-width: 0; }
.bu-modulo .griglia-form { row-gap: var(--space-4); }
.bu-modulo .griglia-form .campo { margin-bottom: 0; }
.tabella-bu-modulo input[type="text"] { min-width: 4rem; }
.tabella-bu-modulo th { padding-inline: var(--space-2); }

/* Senza la colonna di navigazione (pagina d'errore resa fuori dal contesto dello studio, anticamera) il
   corpo occupa tutta la griglia: prima finiva nella traccia della colonna, largo 15rem, e la pagina 404 si
   leggeva una parola per riga. */
.telaio:not(:has(> .telaio-laterale)) { grid-template-columns: minmax(0, 1fr); }

/* CONTROLLO — lo scambio con la contabilità (§13): due moduli gemelli, entrata e uscita. */
.cg-titolo-scambio { margin: 0 0 var(--space-1); font-size: var(--text-md); }

/* Il cruscotto top-down ha dieci colonne di importi: celle più strette, cifre senza a capo, così la
   panoramica sta in larghezza su uno schermo da ufficio invece di scorrere. */
.tabella-controllo th, .tabella-controllo td { padding-inline: var(--space-3); }
.tabella-controllo td.cella-numero { white-space: nowrap; }

/* IL MIO PROFILO: i permessi come etichette, che vanno a capo senza punti elenco. */
.profilo-permessi { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: var(--space-2); }

/* --- Ore e attività (SAGOMA-ORE-E-ATTIVITA) ------------------------------- */
/* I giorni da completare: date in riga, a capo quando serve, senza pallini;
   quelle in ritardo sono badge, le altre testo tenue. */
.giorni-scoperti {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

/* Lo stralcio di una voce: il motivo si scrive solo dopo aver scelto di
   stralciare, così la tabella delle ore resta una riga per voce. */
.stralcio > summary {
  list-style: none;
  cursor: pointer;
  display: inline-block;
  padding: var(--space-1) var(--space-3);
  border: var(--bordo);
  border-radius: var(--radius-pill);
  font-size: var(--text-sm);
  font-weight: 500;
}
.stralcio > summary::-webkit-details-marker { display: none; }
.stralcio[open] > summary { background: var(--c-bg-sunken); }
.stralcio > form { margin-top: var(--space-2); }
