/* =====================================================================
   Mat:Pete Tools — sistema condiviso.  Servito da /ui.css
   =====================================================================

   Perché esiste. Fino al 2026-08-19 la stessa palette era copiata in
   sette file, uno per tool. Copiata, quindi divergente: `tracking`
   aveva corretto `--border-strong` e `--ink-tertiary` per rispettare
   WCAG e la correzione non è mai arrivata negli altri sei, dove il
   bordo dei campi stava a 1,40:1 contro i 3:1 richiesti. Un token
   condiviso non è ordine estetico: è il posto dove una correzione di
   accessibilità si fa una volta e vale per tutti.

   Da dove viene lo stile. Dalle landing di acquisizione (PTDJA,
   Next.js + Tailwind): superfici quasi nere e fredde, Geist, filetti
   invece di ombre, letter-spacing 0, titoli di peso 500. Cosa NON
   viene dalle landing, e perché: le landing sono arie e persuasione
   (pulsanti a pillola alti 52px, sezioni da 64px, titoli in clamp
   fino a 52px), i tool sono densità e confronto. Qui i controlli sono
   alti 38px, i pannelli distano 24px e la scala tipografica è fissa:
   una pillola da 52px in una barra filtri con cinque controlli non
   sta in orizzontale, e un clamp su una cella di tabella non compra
   niente.

   Attenzione a cosa vuol dire densità, perché la prima versione di
   questo file lo ha sbagliato: densità è quante cose stanno a schermo
   e quanto spazio le separa, NON quanto sono piccole le lettere. Il
   testo era partito da 14px di base con 12 e 11 per il servizio, ed
   era illeggibile. Il pavimento adesso è 12px e vale solo per i tick
   di un asse.

   Regole d'uso, vincolanti.
   1. Il CSS di un tool usa questi token e definisce variabili locali
      al proprio componente. NON ridefinisce i token in :root. Se
      serve un valore nuovo, entra qui.
   2. Un colore, un significato, in tutta la suite. Il violetto è
      l'interattività e non entra mai in un grafico. Blu e arancio
      sono dati e non escono mai da un grafico. Verde, ambra e rosso
      sono stati, sempre accompagnati da un glifo o da una parola.
   3. Il colore non è mai l'unico canale di un'informazione.
   4. Ogni controllo ha un :focus-visible visibile sulla superficie su
      cui appare.

   Vincoli tecnici: nessun framework, nessun build step, nessun
   nesting CSS. color-mix() è ammesso.
   ===================================================================== */

:root {
  /* I picker nativi di input[type=date] e le scrollbar seguono questo.
     Senza, il calendario di `tracking` viene reso in chiaro dentro un
     campo scuro. */
  color-scheme: dark;

  /* ---- Superfici: una sola rampa, fredda, dalle landing --------------
     Prima c'erano due temperature che non appartenevano allo stesso
     sistema: fondo #090a15 (blu-nero) e pannelli #1e1e1e (grigio
     neutro). I pannelli sembravano incollati da un altro progetto. */
  --bg: #0a0a0b;            /* fondo pagina, = --color-ground delle landing */
  --surface-1: #121215;     /* card, pannello */
  --surface-2: #1a1a1e;     /* campo, intestazione di tabella, hover di riga */
  --surface-3: #232329;     /* popover, tooltip, toast, riga selezionata */
  --surface-4: #2c2c33;     /* premuto, thumb della scrollbar */
  --surface-inset: #0d0d10; /* pre e code: legge come un pozzo, non come un rilievo */

  /* ---- Filetti e bordi ---------------------------------------------- */
  --line: rgba(255, 255, 255, 0.08);        /* separatori decorativi */
  --line-strong: rgba(255, 255, 255, 0.16); /* separatori che vanno visti */
  --border-field: #70707a;                  /* 3,5:1 su --surface-2. OBBLIGATORIO sul
                                               bordo di ogni campo e di ogni controllo
                                               non pieno: è il bordo che dice "qui si
                                               scrive" (WCAG 1.4.11) */
  --border-field-hover: #8b8b95;

  /* ---- Testo --------------------------------------------------------
     Quattro gradini, con un ruolo dichiarato. --ink-4 non è mai testo
     portante: è l'unico sotto 4,5:1 e serve solo a cose che si
     intravedono (placeholder, griglia di un grafico). */
  --ink: #f2f3f5;    /* 16,8:1  primario */
  --ink-2: #c8cbd0;  /* 11,5:1  secondario, corpo dei paragrafi */
  --ink-3: #9096a0;  /*  6,3:1  aiuto, meta, intestazioni di tabella, tick degli assi */
  --ink-4: #6b7180;  /*  3,8:1  MAI testo che porta informazione */

  /* ---- Accento: un solo colore per l'interattività -------------------
     Violetto delle landing, scurito per passare AA con testo bianco.
     Il violetto delle landing (#8b5cf6) con testo bianco a 15px sta a
     3,53:1 e non passa: quel difetto non si eredita.
     Il mint delle landing NON è l'accento: è a un passo dal verde di
     successo, e in tool che vivono di verdetti (OK / spiegato / da
     indagare) un badge OK in mint leggerebbe come cliccabile. */
  --accent: #6d4fd6;        /* riempimento primario, bianco sopra: 5,6:1 */
  --accent-hover: #7f63e4;
  --accent-active: #5c3fc0;
  --accent-ink: #ffffff;    /* testo sopra --accent */
  --accent-text: #b39cff;   /* 8,1:1  link, anello di focus, tab attiva */
  --accent-quiet: color-mix(in srgb, var(--accent) 18%, var(--surface-1));
  --accent-faint: color-mix(in srgb, var(--accent) 10%, var(--surface-1));

  /* ---- Semantici: solo stati, sempre con glifo o parola accanto ------
     Prima esistevano due dialetti incompatibili: in tre tool --warning
     era ambra, in tre altri era il lime che nei primi significava
     "azione primaria". Il codice colore appreso in un tool veniva
     smentito in quello a fianco. */
  --success: #34d399; /*  9,7:1 */
  --warning: #fbbf24; /* 11,2:1 */
  --danger: #f87171;  /*  6,8:1 */
  --info: #64a8ff;    /*  7,1:1  blu da TESTO: vive in badge e messaggi, dove il
                                 requisito è il contrasto (4,5:1) e conviene stare
                                 chiari. Il blu dei dati (--viz-1) è un altro, più
                                 profondo, perché un segno dentro un grafico ha il
                                 requisito opposto: deve stare nella banda di
                                 luminosità del fondo scuro, o abbaglia. Due blu con
                                 due lavori diversi e misure diverse, non due blu
                                 uguali con due nomi. */
  --success-bg: color-mix(in srgb, var(--success) 14%, var(--surface-1));
  --warning-bg: color-mix(in srgb, var(--warning) 14%, var(--surface-1));
  --danger-bg: color-mix(in srgb, var(--danger) 14%, var(--surface-1));
  --info-bg: color-mix(in srgb, var(--info) 14%, var(--surface-1));
  --danger-ink: #1a0607; /* testo su --danger pieno */

  /* ---- Dati: non escono mai da un grafico ----------------------------
     DUE serie categoriali, non tre, e i valori sono calcolati, non
     scelti a occhio (vedi test/ui-contrasto.test.mjs, che li rimisura).
     Blu e arancio sono la coppia sicura per il daltonismo: separazione
     ΔE 29,5 in visione normale e 26 in tritanopia, contrasto 5,9:1 e
     5,8:1 sul pannello.

     Perché due e non tre: le categorie vere di queste dashboard sono i
     canali, e i canali si mostrano a piccoli multipli, dove ogni
     riquadro ha una serie sola. Una terza tinta sarebbe un colore in
     cerca di un lavoro. Una quarta categoria, allo stesso modo, non è
     un quarto colore: sono small multiples o un filtro.

     I valori di prima (#64a8ff, #ffb066) stavano fuori dalla banda di
     luminosità per fondo scuro (L 0,73 e 0,82 contro 0,48 a 0,67): su
     un fondo quasi nero erano lastre luminose che rubavano la scena al
     resto della pagina. E l'ardesia #5c6f92 aveva croma 0,06, cioè
     leggeva come grigio: non era una categoria, era contesto. Come
     contesto infatti resta, sotto il suo nome vero. */
  --viz-1: #0294fc; /* blu    L 0,655  C 0,185 */
  --viz-2: #cc7d1b; /* arancio L 0,66  C 0,14  */
  --viz-context: #5c6f92; /* ardesia: serie di sfondo, non una categoria */
  --viz-3: var(--viz-context); /* compatibilità: i tool che lo citano ancora */
  --viz-prev: var(--ink-4); /* periodo precedente: sempre questo, 1px tratteggiato */
  --viz-track: var(--surface-2);
  --viz-grid: color-mix(in srgb, var(--ink) 7%, transparent);

  /* Rampa sequenziale, per step ordinati: funnel, profondità di
     lettura, heatmap. Non è un gradiente decorativo: l'ordine dei
     gradini è l'ordine del dato. */
  --ramp-1: #a8cfff;
  --ramp-2: #8ab9f5;
  --ramp-3: #6b9fe6;
  --ramp-4: #5183c9;
  --ramp-5: #3d6aa8; /* gradino più scuro ammesso: 3,6:1 sulla track */

  /* Divergente: solo quando esiste un punto medio dichiarato. */
  --div-neg: var(--danger);
  --div-mid: var(--ink-4);
  --div-pos: var(--success);

  /* Il brand è una categoria di dato, non l'identità della pagina.
     Il chip porta sempre anche la sigla in testo: prima era assegnato
     con nth-child(odd/even), cioè per posizione nel DOM, quindi
     diceva il falso. */
  --brand-ptdja: var(--viz-1);
  --brand-mat: var(--viz-2);

  /* ---- Tipografia ---------------------------------------------------
     Geist come le landing. Fuori Oswald: è un carattere da titolo
     (condensato) usato come carattere di interfaccia, e in maiuscolo a
     11-13px su ogni pulsante e ogni intestazione di tabella costava
     leggibilità dove serve leggere in fretta. */
  --font-sans: "Geist", -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, Roboto, Arial, sans-serif;
  --font-mono: "Geist Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;

  /* I nomi sono ruoli, non taglie: nessuno deve scegliere a occhio fra
     12 e 13px. Prima la base era 15px in cinque file, 16 in due, 17 in
     uno, e i titoli di pagina 26, 28 o 34px. */
  /* La scala è stata alzata di un gradino pieno il 2026-08-19, e il motivo va
     scritto perché non torni indietro da sola. La prima versione partiva da 14px
     di base con 12 e 11 per il testo di servizio: sulla carta era "densità da
     strumento di lavoro", a schermo era illeggibile. E non era un dettaglio di
     bordo: --fs-meta era usato 44 volte e --fs-tick 15, quindi quasi tutto il
     testo di servizio della suite stava a 11 e 12 pixel.
     La densità si fa con le spaziature e con il numero di cose a schermo, non
     rimpicciolendo le lettere: quello riduce solo quante persone possono leggerle.
     Il pavimento adesso è 12px, e vale solo per i tick di un asse; il testo che
     si legge davvero non scende sotto i 13. */
  --fs-tick: 12px;  /* tick degli assi, legenda, didascalia di sparkline */
  --fs-meta: 13px;  /* badge, chip, intestazione di tabella, timestamp */
  --fs-data: 14px;  /* celle, cifre mono, code block */
  --fs-ui: 16px;    /* base: corpo, etichette, pulsanti, campi */
  --fs-body: 18px;  /* paragrafi di spiegazione */
  --fs-title: 20px; /* titolo di card o pannello */
  --fs-page: 28px;  /* titolo di pagina strumento, valore KPI */
  --fs-hub: 36px;   /* h1 dell'hub, e nient'altro */

  --lh-tight: 1.15;
  --lh-snug: 1.35;
  --lh-normal: 1.5;
  --lh-read: 1.6;

  --tr-tight: -0.02em; /* solo da 24px in su */
  --tr-caps: 0.06em;   /* solo micro maiuscole di 1 a 3 parole */

  --fw-normal: 400;
  --fw-medium: 500;
  --fw-bold: 600;

  /* ---- Spazio: otto gradini, uso vincolato -------------------------- */
  --sp-1: 4px;  /* etichetta a campo, glifo a testo */
  --sp-2: 8px;  /* dentro una riga, padding verticale di cella */
  --sp-3: 12px; /* fra campi di una barra filtri, padding orizzontale di cella */
  --sp-4: 16px; /* padding di pannello, gap fra campi di un form */
  --sp-5: 24px; /* gap fra pannelli, padding di card dell'hub */
  --sp-6: 32px; /* padding superiore di pagina strumento */
  --sp-7: 48px; /* fra gruppi, ritmo dell'hub */
  --sp-8: 64px; /* chiusura di pagina */

  /* ---- Larghezze ---------------------------------------------------- */
  --w-tool: 1320px; /* pagina strumento: le tabelle di riconciliazione hanno bisogno
                       di questo spazio. Prima 1020px con tabelle a sette colonne che
                       scrollavano mentre restavano 400px di viewport vuoti */
  --w-hub: 1080px;
  --w-prose: 72ch;  /* testo di aiuto: la misura resta 45 a 75 caratteri */
  --w-form: 560px;

  /* ---- Raggi -------------------------------------------------------- */
  --r-1: 4px;      /* swatch, code in linea, badge */
  --r-2: 8px;      /* pulsante, campo, select, tab */
  --r-3: 12px;     /* card, pannello, popover, toast */
  --r-full: 999px; /* solo pallino di stato e chip filtro rimovibile */

  /* ---- Altezze dei controlli ---------------------------------------- */
  /* Cresciute insieme alla scala tipografica: 16px di testo dentro un controllo
     alto 34 stava stretto, e un campo stretto si legge come un campo pieno. */
  --h-sm: 30px; /* azione in linea dentro una riga di tabella */
  --h: 38px;    /* default */
  --h-lg: 44px; /* azione primaria in fondo a un form */

  /* ---- Elevazione: solo ciò che galleggia davvero -------------------
     Su fondo scuro l'ombra non si vede: la profondità la fa il salto
     di superficie. Restano tooltip, toast e popover. */
  --shadow-pop: 0 8px 24px -8px rgba(0, 0, 0, 0.75);
  --shadow-modal: 0 24px 64px -16px rgba(0, 0, 0, 0.85);

  /* ---- Tempo -------------------------------------------------------- */
  --dur-1: 120ms; /* colore su hover e focus, tooltip */
  --dur-2: 180ms; /* comparsa di popover, toast, chip */
  --dur-3: 260ms; /* apertura di pannello o riga espansa */
  --ease-out: cubic-bezier(0.22, 0.8, 0.24, 1); /* dalle landing */
  --ease-in-out: cubic-bezier(0.4, 0, 0.2, 1);

  /* ---- Focus: un solo trattamento in tutta la suite ------------------ */
  --focus-ring: 2px solid var(--accent-text);
  --focus-offset: 2px;

  --skeleton: color-mix(in srgb, var(--ink) 8%, var(--surface-1));
}

/* Puntatore grossolano: i controlli salgono al pavimento di 44px
   (WCAG 2.5.5) senza ridisegnare il layout desktop. */
@media (pointer: coarse) {
  :root {
    --h-sm: 36px;
    --h: 44px;
    --h-lg: 48px;
  }
}

/* Un solo blocco per tutta la suite: prima esisteva solo in
   dashboard-report. Le transizioni di colore e opacità restano, non
   producono movimento. */
@media (prefers-reduced-motion: reduce) {
  :root {
    --dur-2: 0.01ms;
    --dur-3: 0.01ms;
  }
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-property: color, background-color, border-color, opacity, outline-color !important;
  }
  html {
    scroll-behavior: auto;
  }
}

/* =====================================================================
   Base
   ===================================================================== */

* {
  box-sizing: border-box;
}

html,
body {
  margin: 0;
  padding: 0;
}

body {
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font-sans);
  font-size: var(--fs-ui);
  font-weight: var(--fw-normal);
  line-height: var(--lh-normal);
  letter-spacing: 0;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

h1,
h2,
h3,
h4 {
  margin: 0;
  font-weight: var(--fw-medium);
  line-height: var(--lh-snug);
}

p {
  margin: 0;
}

a {
  color: var(--accent-text);
  text-decoration-color: color-mix(in srgb, var(--accent-text) 45%, transparent);
  text-underline-offset: 3px;
}

a:hover {
  text-decoration-color: currentColor;
}

/* `small` è relativo (0,8em di default), quindi si moltiplica per il gradino in
   cui vive: dentro una riga già a 13px diventava 10,4, cioè sotto qualunque
   pavimento ragionevole, ed è il motivo per cui il testo di servizio risultava
   illeggibile anche dopo aver alzato la scala. Qui prende un minimo assoluto: si
   rimpicciolisce solo finché resta leggibile, e sotto i 12px non va. */
small {
  font-size: max(var(--fs-tick), 0.9em);
}

::selection {
  background: var(--accent);
  color: var(--accent-ink);
}

/* Un solo trattamento di focus, su :focus-visible e non su :focus, così
   non compare al click del mouse. Prima tre tool facevano
   `outline: none` sui campi sostituendolo con un bordo da 1px, che è un
   segnale più debole di quello rimosso. */
:focus-visible {
  outline: var(--focus-ring);
  outline-offset: var(--focus-offset);
}

/* =====================================================================
   Utilità
   ===================================================================== */

/* Il meccanismo di visibilità di sette pagine su dieci: il JS aggiunge
   e toglie questa classe in oltre cento punti. Non si rinomina. */
.hidden {
  display: none !important;
}

/* L'attributo `hidden` è l'altro meccanismo in uso (landing-kit,
   reconciliator-tracking, la cornice condivisa). La regola del browser
   è `[hidden] { display: none }` a specificità zero, quindi qualunque
   componente che dichiara un display la batte: un `.btn` con `hidden`
   resta visibile. Trovato a schermo sul pulsante Amministrazione della
   cornice, non leggendo il codice. */
[hidden] {
  display: none !important;
}

/* Visibile solo agli screen reader. */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* Salta al contenuto: primo elemento nel DOM, invisibile finché non
   riceve il focus (WCAG 2.4.1). Serve perché l'header è sticky. */
.skip-link {
  position: absolute;
  top: var(--sp-2);
  left: var(--sp-2);
  z-index: 100;
  padding: var(--sp-2) var(--sp-3);
  background: var(--surface-3);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-2);
  color: var(--ink);
  font-size: var(--fs-ui);
  text-decoration: none;
  transform: translateY(-200%);
}

.skip-link:focus-visible {
  transform: translateY(0);
}

.mono {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
}

/* Ogni cifra che va confrontata con un'altra sta in mono tabulare,
   allineata a destra. Prima i valori KPI erano in Oswald, che non ha
   cifre tabulari: colonne di numeri che non incolonnano. */
.num {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  text-align: right;
  white-space: nowrap;
}

.ink-subtle {
  color: var(--ink-3);
}

/* Assenza di dato, mai confusa con lo zero: 0 è un valore, n.d. è il
   suo contrario. */
.nd {
  color: var(--ink-4);
  font-family: var(--font-mono);
}

/* =====================================================================
   Cornice: header, main, footer, toolbar
   ===================================================================== */

.app-header {
  position: sticky;
  top: 0;
  z-index: 10;
  background: var(--bg); /* pieno, non trasparente: le righe di tabella ci passano sotto */
  border-bottom: 1px solid var(--line-strong);
}

.app-header__inner {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  min-height: 48px;
  max-width: var(--w-tool);
  margin: 0 auto;
  padding: 0 var(--sp-4);
}

.brand-mark {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  color: var(--ink);
  font-size: var(--fs-ui);
  font-weight: var(--fw-medium);
  text-decoration: none;
  border-radius: var(--r-2);
}

.brand-mark:hover {
  color: var(--ink);
}

.brand-mark__sign {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  flex-shrink: 0;
}

.brand-mark__chip {
  width: 10px;
  height: 10px;
  border-radius: 2px;
  background: var(--accent-text);
}

.brand-mark__eq rect {
  fill: var(--ink-3);
}

.brand-mark__word {
  white-space: nowrap;
}

/* Briciola: dove sono nella suite. L'ultimo segmento porta
   aria-current="page" ed è l'unico in --ink. */
.crumb {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  min-width: 0;
  color: var(--ink-3);
  font-size: var(--fs-meta);
}

.crumb::before {
  content: "";
  align-self: stretch;
  width: 1px;
  margin: 0 var(--sp-1);
  background: var(--line-strong);
}

.crumb a {
  position: relative;
  color: var(--ink-3);
  text-decoration: none;
}

/* Il ritorno all'hub è alto quanto la sua riga di testo, cioè 19px: sotto i 24
   di WCAG 2.5.8, ed è la via di fuga della pagina, cioè il link che più deve
   essere facile da prendere. Si allarga l'area sensibile, non il testo. */
.crumb a::after {
  content: "";
  position: absolute;
  inset: -8px -6px;
}

.crumb a:hover {
  color: var(--ink);
}

.crumb [aria-current="page"] {
  color: var(--ink);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Zona di servizio in alto a destra: identità, amministrazione, uscita.
   È il posto dove la gente si aspetta di trovarle. */
.app-header__side {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  margin-left: auto;
}

.app-header__who {
  max-width: 22ch;
  overflow: hidden;
  color: var(--ink-3);
  font-size: var(--fs-meta);
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Su schermo stretto la cornice si accorcia invece di accartocciarsi. Senza
   queste regole la briciola non cede spazio e finisce sotto i pulsanti a
   destra: visto a 390px dentro test/visual/mobile.html, non deducibile
   ridimensionando la finestra, che non scende sotto i 757px. */
@media (max-width: 640px) {
  .app-header__who {
    display: none;
  }
  /* Resta il nome del tool, che è il "dove sono". La via di casa non si perde:
     è il marchio a sinistra, che è un link. */
  .crumb > a,
  .crumb > [aria-hidden="true"] {
    display: none;
  }
}

@media (max-width: 460px) {
  .brand-mark__word {
    display: none;
  }
}

.app-main {
  max-width: var(--w-tool);
  margin: 0 auto;
  padding: var(--sp-6) var(--sp-4) var(--sp-8);
}

/* Il vertice della pagina va difeso: titolo su una riga, descrizione su
   una riga. La spiegazione lunga va in un <details> "Come si legge",
   collocato dopo il primo blocco di dati. */
.page-intro {
  margin-bottom: var(--sp-5);
}

.page-intro__title {
  font-size: var(--fs-page);
  font-weight: var(--fw-bold);
  letter-spacing: var(--tr-tight);
  line-height: var(--lh-tight);
}

.page-intro__desc {
  max-width: var(--w-prose);
  margin-top: var(--sp-1);
  color: var(--ink-3);
  font-size: var(--fs-ui);
}

.app-footer {
  max-width: var(--w-tool);
  margin: 0 auto;
  padding: var(--sp-5) var(--sp-4) var(--sp-7);
  color: var(--ink-3);
  font-size: var(--fs-meta);
}

.toolbar {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  flex-wrap: wrap;
  margin-bottom: var(--sp-4);
}

.toolbar__spacer {
  margin-left: auto;
}

/* =====================================================================
   Card e pannelli
   ===================================================================== */

.card {
  background: var(--surface-1);
  border: 1px solid var(--line);
  border-radius: var(--r-3);
  padding: var(--sp-4);
}

.card + .card {
  margin-top: var(--sp-5);
}

/* Testata di pannello: titolo, aiuto, azioni a destra. Nasce in
   `tracking` come .card__head e diventa canonica. */
.card__head {
  display: flex;
  align-items: baseline;
  gap: var(--sp-3);
  flex-wrap: wrap;
  margin-bottom: var(--sp-3);
}

.card__title {
  font-size: var(--fs-title);
  font-weight: var(--fw-medium);
}

/* Tre nomi per la stessa cosa nei sette tool: .hint, .card__hint, .note.
   Vivono tutti, con lo stesso trattamento, invece di rinominare in
   settanta punti di markup. */
.hint,
.card__hint,
.note {
  color: var(--ink-3);
  font-size: var(--fs-ui);
  line-height: var(--lh-normal);
  /* Un cap di misura, non una larghezza: dentro un pannello da 1320px una nota
     di metodo arriverebbe a 160 caratteri per riga, e l'occhio perde il capo. */
  max-width: var(--w-prose);
}

/* Il gradino sotto il titolo di pannello: un blocco dentro un pannello di
   output. Nasce due volte in due tool con due nomi (`.out-h` in landing-kit,
   `.sub` in reconciliator), sempre a 14px fuori scala: quando una cosa serve a
   due tool smette di essere loro e diventa del sistema. */
.card__sub {
  margin: var(--sp-5) 0 var(--sp-2);
  color: var(--ink);
  font-size: var(--fs-body);
  font-weight: var(--fw-medium);
}

.card__sub:first-child {
  margin-top: 0;
}

/* Ritmo verticale dentro un pannello che impila titolo, aiuto, campi e
   messaggi. Opt in: applicarlo a ogni `.card` cambierebbe pagine già
   verificate, e non tutti i pannelli sono una pila. */
.stack {
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
}

.stack--stretto {
  gap: var(--sp-2);
}

.card__head .btn,
.card__head .hint,
.card__head .card__hint {
  margin-left: 0;
}

.card__head > *:last-child {
  margin-left: auto;
}

/* Gruppi di pannelli: lo spazio dentro un pannello non supera mai il
   gap fra pannelli (prossimità). */
.group {
  margin-top: var(--sp-7);
}

.group__title {
  margin-bottom: var(--sp-3);
  font-size: var(--fs-body);
  font-weight: var(--fw-medium);
}

/* Pannello richiudibile: <details> nativo. Il contenuto raro o
   pericoloso (pulizia dei dati) resta chiuso di default. */
/* Il triangolino nativo si toglie ovunque, non solo dentro una card: il
   chevron qui sotto è globale, quindi un <details> fuori da una card
   mostrava due frecce. Visto in tracking, dove "Come si legge" sta sotto la
   griglia dei KPI e non dentro un pannello. */
summary {
  cursor: pointer;
  list-style: none;
  display: flex;
  align-items: center;
  gap: var(--sp-2);
}

summary::-webkit-details-marker {
  display: none;
}

/* La taglia da titolo vale solo dove il <details> È un pannello: altrove è
   una riga di testo che si apre, e a 18px urlerebbe. */
details.card > summary,
.card > details > summary {
  font-size: var(--fs-title);
  font-weight: var(--fw-medium);
}

details > summary::before {
  content: "";
  width: 6px;
  height: 6px;
  border-right: 1.5px solid var(--ink-3);
  border-bottom: 1.5px solid var(--ink-3);
  transform: rotate(-45deg);
  transition: transform var(--dur-2) var(--ease-out);
}

details[open] > summary::before {
  transform: rotate(45deg);
}

details > summary:hover::before {
  border-color: var(--ink);
}

/* =====================================================================
   Pulsanti
   ===================================================================== */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  height: var(--h);
  padding: 0 14px;
  border: 1px solid transparent;
  border-radius: var(--r-2);
  background: transparent;
  color: var(--ink);
  font-family: var(--font-sans);
  font-size: var(--fs-ui);
  font-weight: var(--fw-medium);
  line-height: 1;
  letter-spacing: 0;
  text-transform: none; /* fuori il maiuscolo: era su ogni pulsante della suite */
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
  transition: background-color var(--dur-1), border-color var(--dur-1), color var(--dur-1);
}

/* Secondario: è il default. Il rango viene dal posto nella pagina, non
   dalla semantica. */
.btn {
  border-color: var(--border-field);
}

.btn:hover {
  background: var(--surface-2);
  border-color: var(--border-field-hover);
  color: var(--ink);
}

.btn:active {
  background: var(--surface-3);
}

/* Un solo pulsante pieno in accento per schermata. Se una pagina ne ha
   tre, due non erano primarie. */
.btn--primary {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--accent-ink);
}

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

.btn--primary:active {
  background: var(--accent-active);
  border-color: var(--accent-active);
}

/* Sul riempimento pieno l'anello semplice non avrebbe 3:1 contro il
   pulsante stesso: doppio anello, con il fondo pagina come stacco. */
.btn--primary:focus-visible,
.btn--danger:focus-visible {
  outline: none;
  box-shadow: 0 0 0 2px var(--bg), 0 0 0 4px var(--accent-text);
}

.btn--secondary {
  border-color: var(--border-field);
}

.btn--ghost,
.btn--tertiary {
  border-color: transparent;
  color: var(--ink-3);
}

.btn--ghost:hover,
.btn--tertiary:hover {
  background: var(--surface-2);
  border-color: transparent;
  color: var(--ink);
}

/* Distruttivo: contorno di default. Il pieno esiste solo nel passo di
   conferma, dove l'azione è già stata scelta. */
.btn--danger {
  border-color: var(--danger);
  color: var(--danger);
}

.btn--danger:hover {
  background: var(--danger-bg);
  border-color: var(--danger);
  color: var(--danger);
}

.btn--danger-solid {
  background: var(--danger);
  border-color: var(--danger);
  color: var(--danger-ink);
}

.btn--danger-solid:hover {
  background: color-mix(in srgb, var(--danger) 88%, #fff);
  color: var(--danger-ink);
}

.btn--small,
.btn--csv {
  height: var(--h-sm);
  padding: 0 10px;
  font-size: var(--fs-meta);
}

.btn--csv {
  border-color: transparent;
  color: var(--ink-3);
}

.btn--csv:hover {
  background: var(--surface-2);
  color: var(--ink);
}

.btn--lg,
.btn--run {
  height: var(--h-lg);
  padding: 0 18px;
}

.btn--full {
  width: 100%;
}

/* Da evitare: lascia bloccati senza dire perché, e il basso contrasto
   lo rende difficile da vedere. Dove è inevitabile resta focalizzabile
   con aria-disabled e il motivo scritto accanto, non in un tooltip. */
.btn:disabled,
.btn[aria-disabled="true"] {
  background: var(--surface-1);
  border-color: var(--line-strong);
  color: var(--ink-3);
  cursor: not-allowed;
}

/* Pulsante in attesa: stesso elemento, larghezza ferma, etichetta
   invariata. Mai "Attendere". */
.btn[aria-busy="true"] {
  position: relative;
  color: transparent;
}

.btn[aria-busy="true"]::after {
  content: "";
  position: absolute;
  width: 14px;
  height: 14px;
  border: 2px solid color-mix(in srgb, currentColor 30%, transparent);
  border-top-color: var(--ink);
  border-radius: 50%;
  animation: spin 700ms linear infinite;
}

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

.form-actions {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  flex-wrap: wrap;
}

/* =====================================================================
   Campi
   ===================================================================== */

.field {
  display: flex;
  flex-direction: column;
  gap: var(--sp-1);
  min-width: 0;
}

.field__label,
.field > label {
  color: var(--ink-2);
  font-size: var(--fs-ui);
  font-weight: var(--fw-medium);
}

/* L'aiuto sta sopra il campo, non sotto: sotto lo coprono la tastiera
   di sistema e i suggerimenti di autofill. */
.field__help {
  color: var(--ink-3);
  font-size: var(--fs-meta);
}

.field__req {
  color: var(--ink-3);
  font-size: var(--fs-meta);
  font-weight: var(--fw-normal);
}

.input,
.select,
textarea.input,
input[type="text"].input,
input[type="url"].input,
input[type="email"].input,
input[type="number"].input,
input[type="date"].input,
input[type="search"].input {
  width: 100%;
  height: var(--h);
  padding: 0 12px;
  background: var(--surface-2);
  border: 1px solid var(--border-field);
  border-radius: var(--r-2);
  color: var(--ink);
  font-family: var(--font-sans);
  font-size: var(--fs-ui);
  caret-color: var(--accent-text);
  transition: border-color var(--dur-1), background-color var(--dur-1);
}

textarea.input,
textarea {
  height: auto;
  min-height: 96px;
  padding: 10px 12px;
  line-height: var(--lh-normal);
  resize: vertical;
}

.select,
select.input {
  padding-right: 32px;
  background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%239096a0' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9.5 6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 8px center;
  background-size: 16px;
  appearance: none;
}

.input:hover,
.select:hover {
  border-color: var(--border-field-hover);
}

/* Il bordo da solo non basta, ed era il difetto: anello più bordo. */
.input:focus-visible,
.select:focus-visible,
textarea:focus-visible {
  border-color: var(--accent-text);
  outline: var(--focus-ring);
  outline-offset: 0;
}

.input::placeholder,
textarea::placeholder {
  color: var(--ink-4);
}

.input[aria-invalid="true"],
.input--error {
  border-color: var(--danger);
  background: var(--danger-bg);
}

.input[readonly] {
  background: var(--surface-1);
  border-color: var(--line-strong);
  color: var(--ink-2);
}

.input:disabled,
.select:disabled {
  background: var(--surface-1);
  border-color: var(--line-strong);
  color: var(--ink-4);
  cursor: not-allowed;
}

/* Su mobile i campi vanno a 16px, altrimenti iOS zooma la pagina al
   focus e l'utente si ritrova fuori inquadratura. */
@media (max-width: 640px) {
  .input,
  .select,
  textarea {
    font-size: 16px;
  }
}

/* Campo con prefisso o suffisso: il bordo è del contenitore, il campo
   dentro non ha bordo proprio e il focus va sul contenitore. */
.input-wrap {
  display: flex;
  align-items: stretch;
  height: var(--h);
  background: var(--surface-2);
  border: 1px solid var(--border-field);
  border-radius: var(--r-2);
  overflow: hidden;
}

.input-wrap:focus-within {
  border-color: var(--accent-text);
  outline: var(--focus-ring);
  outline-offset: 0;
}

.input-wrap .input {
  height: 100%;
  background: transparent;
  border: 0;
}

.input-wrap .input:focus-visible {
  outline: none;
}

.input-wrap__affix {
  display: inline-flex;
  align-items: center;
  padding: 0 10px;
  background: var(--surface-1);
  color: var(--ink-3);
  font-family: var(--font-mono);
  font-size: var(--fs-data);
}

.input-wrap__affix:first-child {
  border-right: 1px solid var(--line);
}

.input-wrap__affix:last-child {
  border-left: 1px solid var(--line);
}

/* 18 e non 16: sono cresciuti con la scala, e il quadratino di una spunta a
   16px accanto a un'etichetta da 16px sembrava un residuo. Il bersaglio vero
   resta l'etichetta, che li avvolge ed è alta almeno 32px. */
input[type="checkbox"],
input[type="radio"] {
  width: 18px;
  height: 18px;
  accent-color: var(--accent);
  cursor: pointer;
}

.check {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  min-height: 32px;
  cursor: pointer;
}

fieldset {
  margin: 0;
  padding: 0;
  border: 0;
}

legend {
  padding: 0;
  margin-bottom: var(--sp-2);
  font-size: var(--fs-ui);
  font-weight: var(--fw-medium);
}

.form-grid {
  display: grid;
  gap: var(--sp-4);
  grid-template-columns: 1fr;
}

@media (min-width: 720px) {
  .form-grid--2 {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

/* =====================================================================
   Tab
   ===================================================================== */

.tabs {
  display: flex;
  gap: var(--sp-1);
  border-bottom: 1px solid var(--line-strong);
  overflow-x: auto;
  scrollbar-width: none;
}

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

.tabs button,
.tabs [role="tab"] {
  height: var(--h);
  padding: 0 var(--sp-3);
  margin-bottom: -1px;
  border: 0;
  border-bottom: 2px solid transparent;
  background: none;
  color: var(--ink-3);
  font-family: var(--font-sans);
  font-size: var(--fs-ui);
  cursor: pointer;
  white-space: nowrap;
  transition: color var(--dur-1), border-color var(--dur-1);
}

.tabs button:hover {
  color: var(--ink);
}

/* Due segnali, non solo il colore: bordo e peso. */
.tabs [aria-selected="true"] {
  border-bottom-color: var(--accent-text);
  color: var(--ink);
  font-weight: var(--fw-medium);
}

.tabs button:focus-visible {
  outline: var(--focus-ring);
  outline-offset: -2px;
}

/* =====================================================================
   Tabelle dati
   ===================================================================== */

.table-wrap,
.scroller {
  overflow-x: auto;
  border: 1px solid var(--line);
  border-radius: var(--r-3);
  background: var(--surface-1);
}

.data-table,
.table,
.var-table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--fs-data);
  line-height: var(--lh-snug);
}

.data-table th,
.table th,
.var-table th {
  position: sticky;
  top: 0;
  z-index: 1;
  padding: var(--sp-2) var(--sp-3);
  background: var(--surface-2); /* pieno: le righe ci scorrono sotto */
  border-bottom: 1px solid var(--line-strong);
  color: var(--ink-3);
  font-size: var(--fs-meta);
  font-weight: var(--fw-medium);
  text-align: left;
  text-transform: none;
  letter-spacing: 0;
  white-space: nowrap;
}

.data-table td,
.table td,
.var-table td {
  padding: var(--sp-2) var(--sp-3);
  border-bottom: 1px solid var(--line);
  vertical-align: top;
}

.data-table tbody tr:last-child td,
.table tbody tr:last-child td,
.var-table tbody tr:last-child td {
  border-bottom: 0;
}

/* Nessuna zebra: la striatura è gradevolezza, non leggibilità
   misurata. Le righe si distinguono per filetto e in hover. */
.data-table tbody tr:hover,
.table tbody tr:hover {
  background: var(--surface-2);
}

.data-table th.num,
.table th.num,
.var-table th.num {
  text-align: right;
}

/* Riga aperta o selezionata: colore più barra interna, due canali. */
.data-table tbody tr.is-open,
.table tbody tr.is-open {
  background: var(--accent-quiet);
  box-shadow: inset 2px 0 0 var(--accent-text);
}

/* Intestazione ordinabile: il pulsante riempie la cella, lo spazio del
   glifo è sempre riservato così l'ordinamento non sposta le colonne. */
th button.sort {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: var(--sp-1);
  width: 100%;
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  cursor: pointer;
}

/* L'intera cella di intestazione è il bersaglio: il pulsante è alto quanto la
   sua riga di testo, il padding del `th` sta fuori da lui. */
th button.sort::before {
  content: "";
  position: absolute;
  inset: -8px -12px;
}

th button.sort::after {
  content: "";
  width: 8px;
  height: 8px;
  border-right: 1.5px solid var(--ink-4);
  border-bottom: 1.5px solid var(--ink-4);
  transform: rotate(45deg);
  opacity: 0;
}

th[aria-sort] button.sort::after {
  opacity: 1;
  border-color: var(--ink);
}

th[aria-sort="ascending"] button.sort::after {
  transform: rotate(-135deg);
}

/* I pulsanti di testo dentro una tabella sono alti quanto la loro riga di
   testo, cioè una ventina di pixel: sotto i 24 di WCAG 2.5.8. L'area
   sensibile si allarga con uno pseudo-elemento invece che con del padding,
   così il bersaglio cresce e l'altezza della riga no: in una tabella di
   trenta righe, sei pixel di padding per riga sono un altro schermo di
   scroll. */
.cell-filter,
.cell-open {
  position: relative;
}

.cell-filter::after,
.cell-open::after {
  content: "";
  position: absolute;
  /* Otto pixel per lato in orizzontale, non quattro: un valore corto come "3" o
     un nome di due lettere resterebbe sotto i 24 di larghezza. */
  inset: -6px -8px;
}

/* Cella che aggiunge un filtro alla vista. Un <button> vero, quindi
   raggiungibile da tastiera: il pattern nasce in `tracking`. */
.cell-filter {
  padding: 0;
  border: 0;
  border-bottom: 1px dashed var(--border-field);
  background: none;
  color: inherit;
  font: inherit;
  text-align: inherit;
  cursor: pointer;
}

.cell-filter:hover {
  color: var(--accent-text);
  border-bottom-color: var(--accent-text);
}

/* Riga cliccabile: l'azione vive in un pulsante dentro la cella che
   identifica la riga, non nel click sulla riga intera. */
.cell-open {
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  text-align: inherit;
  cursor: pointer;
  text-decoration: underline dotted var(--border-field);
  text-underline-offset: 3px;
}

.cell-open:hover {
  color: var(--accent-text);
}

/* Scorrendo in orizzontale non si perde l'identità della riga. */
@media (max-width: 720px) {
  .table-wrap .data-table tbody th:first-child,
  .table-wrap .data-table td:first-child,
  .table-wrap .table td:first-child {
    position: sticky;
    left: 0;
    background: var(--surface-1);
    box-shadow: 1px 0 0 var(--line);
  }
}

/* Tetto di righe con apertura esplicita: il pattern di `tracking`. */
.row-more {
  padding: var(--sp-2) var(--sp-3);
}

.more-wrap {
  padding: var(--sp-2) var(--sp-3);
  border-top: 1px solid var(--line);
}

/* Didascalia: cosa conta una riga. Obbligatoria su ogni tabella. */
.table-note {
  margin-top: var(--sp-2);
  color: var(--ink-3);
  font-size: var(--fs-meta);
}

/* =====================================================================
   Card metrica
   ===================================================================== */

.kpi-grid {
  display: grid;
  gap: var(--sp-3);
  grid-template-columns: repeat(2, minmax(0, 1fr));
}

@media (min-width: 560px) {
  .kpi-grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

@media (min-width: 900px) {
  .kpi-grid {
    grid-template-columns: repeat(5, minmax(0, 1fr));
  }
}

.kpi-card,
.kpi {
  display: flex;
  flex-direction: column;
  gap: var(--sp-1);
  padding: var(--sp-4);
  background: var(--surface-1);
  border: 1px solid var(--line);
  border-radius: var(--r-3);
  text-align: left;
  transition: border-color var(--dur-1), background-color var(--dur-1);
}

button.kpi-card {
  cursor: pointer;
  font-family: inherit;
}

button.kpi-card:hover {
  border-color: var(--border-field-hover);
  background: var(--surface-2);
}

/* Selezionata: bordo, fondo e un pallino prima dell'etichetta. Tre
   canali, di cui uno non cromatico. */
button.kpi-card[aria-pressed="true"] {
  border-color: var(--accent-text);
  background: var(--accent-quiet);
}

button.kpi-card[aria-pressed="true"] .kpi-card__label::before {
  content: "";
  display: inline-block;
  width: 6px;
  height: 6px;
  margin-right: var(--sp-1);
  border-radius: 50%;
  background: var(--accent-text);
  vertical-align: middle;
}

/* Uno dei due soli posti in cui il maiuscolo sopravvive: due o tre
   parole che si riconoscono per forma e non si leggono. */
.kpi-card__label,
.kpi__label {
  color: var(--ink-3);
  /* Maiuscolo: sopravvive qui e negli occhielli, ed è l'unico posto. Ma a 12px
     il maiuscolo si legge peggio del minuscolo, perché perde ascendenti e
     discendenti: sta un gradino sopra il pavimento, non sul pavimento. */
  font-size: var(--fs-meta);
  font-weight: var(--fw-medium);
  text-transform: uppercase;
  letter-spacing: var(--tr-caps);
}

.kpi-card__value,
.kpi__value {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: var(--fs-page);
  font-weight: var(--fw-medium);
  line-height: var(--lh-tight);
}

.kpi-card__delta,
.kpi__delta {
  font-size: var(--fs-meta);
  color: var(--ink-3);
}

/* Il glifo direzionale precede il numero: il colore non è il solo
   canale. */
.delta--up,
.delta--pos {
  color: var(--success);
}

.delta--down,
.delta--neg {
  color: var(--danger);
}

.delta--flat {
  color: var(--ink-4);
}

/* Metrica sotto osservazione che si accende. Il glifo non è decorazione: senza,
   l'allarme sarebbe solo un bordo e uno sfondo, cioè solo colore, e chi non lo
   distingue vedrebbe una card come le altre. */
.kpi--watch.is-alert {
  border-color: var(--warning);
  background: var(--warning-bg);
}

.kpi--watch.is-alert .kpi__label::before {
  content: "⚠ ";
  color: var(--warning);
}

/* =====================================================================
   Badge, pill, chip
   ===================================================================== */

.badge {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-1);
  padding: 2px 8px;
  border: 1px solid transparent;
  border-radius: var(--r-1);
  font-size: var(--fs-meta);
  font-weight: var(--fw-medium);
  white-space: nowrap;
}

.badge--ok,
.badge--completed {
  background: var(--success-bg);
  border-color: color-mix(in srgb, var(--success) 35%, transparent);
  color: var(--success);
}

.badge--warn,
.badge--paused {
  background: var(--warning-bg);
  border-color: color-mix(in srgb, var(--warning) 35%, transparent);
  color: var(--warning);
}

.badge--err {
  background: var(--danger-bg);
  border-color: color-mix(in srgb, var(--danger) 35%, transparent);
  color: var(--danger);
}

.badge--info,
.badge--running {
  background: var(--info-bg);
  border-color: color-mix(in srgb, var(--info) 35%, transparent);
  color: var(--info);
}

/* Esisteva nel JS di ab-test senza nessuna regola CSS: una bozza si
   riconosceva solo dal testo. */
.badge--muted,
.badge--draft {
  background: var(--surface-2);
  border-color: var(--line-strong);
  color: var(--ink-3);
}

/* Pallino di stato: sempre accompagnato da una frase, mai da solo. */
.dot {
  display: inline-block;
  width: 8px;
  height: 8px;
  border-radius: var(--r-full);
  background: var(--ink-4);
  flex-shrink: 0;
}

.dot--ok {
  background: var(--success);
}

.dot--warn {
  background: var(--warning);
}

.dot--err {
  background: var(--danger);
}

/* Chip di brand: quadratino più sigla in testo. Il colore da solo non
   dice niente a chi non lo distingue. */
.chip {
  display: inline-block;
  width: 10px;
  height: 10px;
  border-radius: 2px;
  background: var(--ink-4);
  flex-shrink: 0;
  vertical-align: middle;
}

.chip--ptdja {
  background: var(--brand-ptdja);
}

.chip--mat {
  background: var(--brand-mat);
}

/* Filtro attivo, rimovibile. Il pulsante di rimozione era 16px: sotto
   il minimo di 24. */
.chips {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  flex-wrap: wrap;
}

.chip-filter {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-1);
  height: 26px;
  padding: 0 4px 0 10px;
  background: var(--surface-2);
  border: 1px solid var(--border-field);
  border-radius: var(--r-full);
  font-size: var(--fs-meta);
}

.chip-filter button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  padding: 0;
  border: 0;
  border-radius: var(--r-full);
  background: none;
  color: var(--ink-3);
  font-size: var(--fs-ui);
  line-height: 1;
  cursor: pointer;
}

.chip-filter button:hover {
  color: var(--danger);
  background: var(--surface-3);
}

/* =====================================================================
   Barra filtri
   ===================================================================== */

.filter-bar,
.run-bar,
.run-row {
  display: flex;
  align-items: flex-end;
  gap: var(--sp-3);
  flex-wrap: wrap;
}

.filter-bar .field,
.run-bar .field,
.run-row .field {
  min-width: 150px;
}

.filter-bar .field__label,
.run-bar .field__label,
.run-row .field__label {
  color: var(--ink-3);
  font-size: var(--fs-meta);
}

/* =====================================================================
   Stati vuoti, caricamento, verdetti
   ===================================================================== */

/* Due varianti diverse, e non è un dettaglio: "non c'è ancora niente"
   spiega come farlo arrivare, "nessun risultato per questi filtri"
   offre di azzerarli. Nessun vicolo chiuso. */
.empty {
  padding: var(--sp-7) var(--sp-4);
  color: var(--ink-3);
  font-size: var(--fs-ui);
}

td.empty,
.data-table .empty,
.table .empty {
  padding: var(--sp-5) var(--sp-3);
  text-align: left;
}

.empty__title {
  display: block;
  margin-bottom: var(--sp-1);
  color: var(--ink);
  font-size: var(--fs-title);
  font-weight: var(--fw-medium);
}

.empty__help {
  display: block;
  max-width: 60ch;
  margin-top: var(--sp-2);
  color: var(--ink-3);
  font-size: var(--fs-meta);
}

/* Ricaricamento di contenuto già a schermo: il contenuto resta e si
   attenua. Sostituire una tabella leggibile con uno scheletro è una
   perdita di informazione. */
.is-refetching {
  opacity: 0.55;
  transition: opacity var(--dur-1);
}

/* Primo caricamento: la geometria di ciò che sta arrivando. */
.skeleton {
  background: var(--skeleton);
  border-radius: var(--r-1);
  background-image: linear-gradient(
    90deg,
    transparent 0%,
    color-mix(in srgb, var(--ink) 5%, transparent) 50%,
    transparent 100%
  );
  background-size: 200% 100%;
  animation: skeleton 1.4s linear infinite;
}

@keyframes skeleton {
  to {
    background-position: -200% 0;
  }
}

.skeleton--text {
  height: 1em;
  margin: 0.25em 0;
}

/* Verdetti: un colore, un glifo e una parola. `verdict--*` nasce in
   ab-test, `verdetto--*` in reconciliator-tracking, `sorgente--*` per
   lo stato di una fonte dati: tre vocabolari già nel JS, un solo
   trattamento. */
.verdict,
.verdetto {
  display: inline-flex;
  align-items: baseline;
  gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-3);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-2);
  background: var(--surface-2);
  font-size: var(--fs-ui);
}

.verdict--winner,
.verdetto--ok,
.sorgente--ok {
  background: var(--success-bg);
  border-color: color-mix(in srgb, var(--success) 35%, transparent);
  color: var(--success);
}

.verdict--keep_running,
.verdetto--spiegato {
  background: var(--info-bg);
  border-color: color-mix(in srgb, var(--info) 35%, transparent);
  color: var(--info);
}

/* `hold`: la soglia è raggiunta ma non ha ancora retto il numero di letture
   richiesto. Non è un vincitore e non è un dato insufficiente, quindi non prende
   né il verde né l'ambra: resta informativo, con il glifo a distinguerlo. */
.verdict--hold {
  background: var(--info-bg);
  border-color: color-mix(in srgb, var(--info) 55%, transparent);
  color: var(--info);
}

.verdict--insufficient,
.verdetto--indagare,
.sorgente--errore {
  background: var(--warning-bg);
  border-color: color-mix(in srgb, var(--warning) 35%, transparent);
  color: var(--warning);
}

.verdetto--nd,
.sorgente--spenta {
  background: var(--surface-2);
  border-color: var(--line-strong);
  color: var(--ink-3);
}

/* =====================================================================
   Messaggi
   ===================================================================== */

/* `.messages` porta due componenti diversi nel repo: un paragrafo di
   errore in quattro tool e una lista di messaggi con livelli in
   utm-generator. Si distinguono per elemento, invece di rinominare in
   quaranta punti fra markup e JS. */
p.messages,
.gate-msg,
.run-status {
  margin: 0;
  min-height: 1em;
  color: var(--ink-3);
  font-size: var(--fs-ui);
}

p.messages:not(:empty),
.gate-msg:not(:empty) {
  color: var(--danger);
}

.run-status--ok {
  color: var(--success);
}

.run-status--err {
  color: var(--danger);
}

ul.messages {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  margin: 0;
  padding: 0;
  list-style: none;
}

/* Messaggio in linea: sopra l'elemento a cui si riferisce, dentro il
   pannello interessato. */
/* Il livello colora il bordo, lo sfondo, il glifo e la frase in grassetto. Il
   corpo del messaggio resta --ink-2: una spiegazione di tre righe scritta in
   ambra o in rosso si legge peggio, e quando tutto è colorato il livello non si
   riconosce più a colpo d'occhio. */
.message,
.msg {
  --msg: var(--ink-3);
  display: grid;
  grid-template-columns: 16px 1fr;
  gap: var(--sp-2);
  padding: var(--sp-3);
  border: 1px solid color-mix(in srgb, var(--msg) 35%, transparent);
  border-radius: var(--r-2);
  background: color-mix(in srgb, var(--msg) 12%, var(--surface-1));
  color: var(--ink-2);
  font-size: var(--fs-ui);
  line-height: var(--lh-normal);
}

.message__icon,
.msg__icon,
.message strong,
.msg strong {
  color: var(--msg);
}

.message--ok,
.msg--ok {
  --msg: var(--success);
}

.message--warning,
.msg--warning {
  --msg: var(--warning);
}

.message--error,
.msg--error {
  --msg: var(--danger);
}

.message--info,
.msg--info {
  --msg: var(--info);
}

/* Toast: uno solo visibile. Il successo si chiude da sé, l'errore no,
   e non porta mai l'unica copia di un'informazione che serve dopo. */
.toast {
  position: fixed;
  right: var(--sp-5);
  bottom: var(--sp-5);
  z-index: 60;
  max-width: 42ch;
  padding: var(--sp-3) var(--sp-4);
  background: var(--surface-3);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-3);
  box-shadow: var(--shadow-pop);
  color: var(--ink);
  font-size: var(--fs-ui);
  opacity: 0;
  transform: translateY(8px);
  pointer-events: none;
  transition: opacity var(--dur-2) var(--ease-out), transform var(--dur-2) var(--ease-out);
}

.toast.is-visible {
  opacity: 1;
  transform: translateY(0);
  pointer-events: auto;
}

@media (max-width: 640px) {
  .toast {
    right: var(--sp-3);
    left: var(--sp-3);
    max-width: none;
  }
}

/* =====================================================================
   Paginazione
   ===================================================================== */

.pager {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  flex-wrap: wrap;
  margin-top: var(--sp-3);
  color: var(--ink-3);
  font-size: var(--fs-meta);
}

.pager__count {
  font-variant-numeric: tabular-nums;
}

/* Alla prima pagina il pulsante resta nel DOM e focalizzabile, con il
   contrasto mantenuto: spento e irraggiungibile lascia senza spiegazione. */
.pager .btn[aria-disabled="true"] {
  background: transparent;
  border-color: var(--line-strong);
  color: var(--ink-3);
  cursor: default;
}

/* =====================================================================
   Codice
   ===================================================================== */

pre {
  margin: 0;
  padding: var(--sp-3);
  max-height: 420px;
  overflow: auto;
  background: var(--surface-inset);
  border: 1px solid var(--line);
  border-radius: var(--r-2);
  color: var(--ink-2);
  font-family: var(--font-mono);
  font-size: var(--fs-data);
  line-height: var(--lh-normal);
  tab-size: 2;
}

code {
  padding: 1px 5px;
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: var(--r-1);
  color: var(--ink-2);
  font-family: var(--font-mono);
  font-size: 0.92em;
}

pre code {
  padding: 0;
  background: none;
  border: 0;
  font-size: inherit;
}

/* =====================================================================
   Grafici: parti condivise
   ===================================================================== */

.legend {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  flex-wrap: wrap;
  color: var(--ink-3);
  font-size: var(--fs-tick);
}

.legend__swatch {
  display: inline-block;
  width: 10px;
  height: 10px;
  margin-right: var(--sp-1);
  border-radius: var(--r-1);
  vertical-align: middle;
}

/* Il periodo precedente ha per swatch un segmento tratteggiato, non un
   quadrato: la forma dice già che è una linea di riferimento. */
.legend--prev .legend__swatch {
  height: 0;
  border-top: 2px dashed var(--viz-prev);
  border-radius: 0;
}

.chart__tip {
  position: absolute;
  z-index: 20;
  padding: var(--sp-2);
  background: var(--surface-3);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-2);
  box-shadow: var(--shadow-pop);
  color: var(--ink);
  font-size: var(--fs-meta);
  white-space: nowrap;
  pointer-events: none;
  opacity: 0;
  transition: opacity var(--dur-1);
}

.chart__tip-when {
  color: var(--ink-3);
}

.chart__tip-row {
  display: flex;
  align-items: center;
  gap: var(--sp-4);
  justify-content: space-between;
}

.chart__tip-row .num {
  font-family: var(--font-mono);
}

/* =====================================================================
   Stampa: le riconciliazioni e i report si stampano e si girano in PDF
   ===================================================================== */

@media print {
  :root {
    color-scheme: light;
  }
  body {
    background: #fff;
    color: #000;
  }
  .app-header,
  .toolbar,
  .filter-bar,
  .chips,
  .btn,
  .toast,
  .skip-link {
    display: none !important;
  }
  .card,
  .table-wrap {
    background: #fff;
    border-color: #ccc;
    box-shadow: none;
  }
  .data-table th,
  .table th {
    position: static;
    background: #f2f2f2;
    color: #000;
  }
  .data-table td,
  .table td {
    border-color: #ddd;
  }
  tr,
  .card {
    break-inside: avoid;
  }
  a[href]::after {
    content: " (" attr(href) ")";
    color: #555;
    font-size: 0.85em;
  }
}
