/* ==========================================================================
   Componenti — tutto cio' che si ripete e ha un nome proprio.
   Legge i token, non ne dichiara nessuno, non impagina la pagina.

   La grammatica dei nomi si conserva, perche' e' gia' difesa da un test che
   funziona: `c-` componente, `__` una parte, `--` un modificatore, `is-` uno
   stato messo da Ruby o dall'interazione. Due regole nuove, entrambe
   verificabili da un test statico:
     1. una classe costruita per interpolazione e' vietata. Il test cerca le
        classi con una espressione regolare e non vede `c-badge--<%= stato %>`:
        una variante che nessuna view scrive per intero puo' morire senza che
        nessuno se ne accorga. Le varianti si scelgono con un `case` che
        restituisce il nome INTERO;
     2. una utility non puo' avere un modificatore. Se serve, e' un componente.

   ## I nove difetti che questo foglio chiude

   1. L'intestazione appiccicata delle tabelle non si appiccicava, e non l'ha
      mai fatto: `overflow-y: clip` accanto a un valore di scorrimento CALCOLA
      `hidden`, quindi il porto verticale esisteva, non aveva altezza, e
      `top: 0` si misurava su un porto che non si muove. Vedi .c-table-port.
   2. Quattordici tabelle hanno piu' di sei colonne e due ne hanno dieci: dalla
      settima in su la prima colonna si appiccica.
   3. Dieci elenchi mostravano una colonna di importi e nessun totale.
   4. La barra dei filtri occupava 320px, sempre aperta: su /uscite restavano
      quattro righe di dati nel primo schermo.
   5. Due stati vuoti incompatibili per lo stesso problema (`c-empty` in 24
      file, `td.c-table__empty` in 10): ora e' uno, in due posizioni.
   6. Tre copie del markup di paginazione, e cinque famiglie di elenchi senza
      nessuna paginazione ne' limite.
   7. Il quadratino d'icona di una tessera non portava informazione — la stessa
      icona su tre grandezze diverse — e il suo fondo stava a 1,05:1.
   8. Il Riepilogo apriva con un indice di dieci pastiglie dentro una scheda,
      130px prima del primo numero.
   9. Cinque righe di intestazione prima del primo dato.
   ========================================================================== */

/* ══ CONTROLLI ═══════════════════════════════════════════════════════════ */

/* ── Il bottone ────────────────────────────────────────────────────────────
   Altezza 36 (era 32, sotto ogni raccomandazione di dimensione del bersaglio),
   raggio 8. La variante primaria e' il VERDE DEL SITO pieno con testo NERO:
   #8DF868 sta a 1,33:1 sul bianco, quindi non e' un inchiostro ma e' una
   superficie eccellente, e porta il nero a 15,76:1. Scrivere bianco qui sopra
   darebbe 1,33:1, ed e' uno dei dodici divieti del sistema. */
.c-btn {
  display: inline-grid;
  grid-auto-flow: column;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  min-height: var(--h-control);
  padding: 0 var(--sp-4);
  font-size: var(--fs-body);
  font-weight: var(--fw-medium);
  line-height: 1;
  color: var(--n-800);
  text-decoration: none;
  white-space: nowrap;
  background: var(--n-000);
  border: 1px solid var(--n-300);
  border-radius: var(--radius-control);
  cursor: pointer;
  transition: background var(--t-state) var(--ease),
              border-color var(--t-state) var(--ease);
}
.c-btn:hover { background: var(--n-100); border-color: var(--n-400); }
.c-btn:active { background: var(--n-200); }

.c-btn--primary {
  color: var(--n-900);
  background: var(--g-200);
  border-color: var(--g-400);
}
.c-btn--primary:hover { background: var(--g-100); border-color: var(--g-500); }
.c-btn--primary:active { background: var(--g-300); }

/* Un bottone quieto non ha bordo: e' un'azione secondaria, e un bordo la
   metterebbe alla pari di quella primaria. */
.c-btn--quiet {
  color: var(--n-600);
  background: transparent;
  border-color: transparent;
}
.c-btn--quiet:hover { color: var(--n-900); background: var(--n-100); border-color: transparent; }

/* Il rosso NON diventa una superficie: resta inchiostro e bordo. E' uno dei
   dodici divieti — il verde e' l'unico accento dell'interfaccia, e un bottone
   rosso pieno ne creerebbe un secondo. Il bersaglio resta riconoscibile:
   7,03:1 di inchiostro e un bordo a 3:1. */
.c-btn--danger { color: var(--neg-600); border-color: var(--neg-400); }
.c-btn--danger:hover { background: var(--neg-050); border-color: var(--neg-500); }

.c-btn--small {
  min-height: calc(var(--h-control) - var(--sp-2));
  padding: 0 var(--sp-3);
  font-size: var(--fs-small);
}

/* Il simmetrico di --small verso l'alto, costruito con gli stessi token: --small
   scende di --sp-2 e di un gradino di corpo, --large sale di --sp-3 e di un
   gradino. 36 + 12 = 48 px, che e' anche il bersaglio minimo che si tocca con
   sicurezza su un telefono. Esiste per le azioni di `/`: la dashboard e' la
   pagina che si apre per prima, e da la' si va ai movimenti o si registra. */
.c-btn--large {
  min-height: calc(var(--h-control) + var(--sp-3));
  padding: 0 var(--sp-5);
  font-size: var(--fs-title);
}

.c-btn[disabled], .c-btn[aria-disabled="true"] {
  color: var(--n-400);
  background: var(--n-100);
  border-color: var(--n-200);
  cursor: not-allowed;
}

.c-btnrow { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); }
/* Dentro una cella di tabella i bottoni non vanno a capo e stanno a destra:
   la colonna delle azioni e' l'ultima. */
.c-btnrow--cell { flex-wrap: nowrap; justify-content: flex-end; }

/* ── Il bottone-icona ─────────────────────────────────────────────────────
   Quadrato, nessun bordo, l'etichetta accessibile e' obbligatoria (lo verifica
   un test: un bottone che porta solo un disegno deve dire che cosa fa). */
.c-iconbtn {
  position: relative;
  display: inline-grid;
  place-items: center;
  width: var(--h-control);
  height: var(--h-control);
  padding: 0;
  color: var(--n-600);
  background: transparent;
  border: 0;
  border-radius: var(--radius-control);
  cursor: pointer;
}
.c-iconbtn:hover { color: var(--n-900); background: var(--n-100); }

/* Il pallino degli avvisi non letti. NON e' l'unico segnale: il numero sta
   nell'etichetta accessibile e la voce nel menu porta la stessa pastiglia. A
   zero non si stampa niente — un pallino che c'e' sempre non avvisa di niente.
   Il colore e' ambra e non rosso: un avviso non letto non e' un errore. */
.c-iconbtn__dot {
  position: absolute;
  inset-block-start: 6px;
  inset-inline-end: 6px;
  width: 7px;
  height: 7px;
  background: var(--warn-400);
  border: 1px solid var(--n-000);
  border-radius: var(--radius-pill);
}

.c-icon { width: 18px; height: 18px; flex: none; }

/* ── I campi ──────────────────────────────────────────────────────────────
   Stessa altezza e stesso raggio dei bottoni: in una riga di filtri un campo e
   un bottone devono stare sulla stessa linea di base senza aggiustamenti. */
.c-input, .c-select, .c-textarea {
  width: 100%;
  min-height: var(--h-control);
  padding: 0 var(--sp-3);
  font-size: var(--fs-body);
  color: var(--n-900);
  background: var(--n-000);
  border: 1px solid var(--n-400);
  border-radius: var(--radius-control);
}
.c-textarea { padding: var(--sp-2) var(--sp-3); min-height: calc(var(--h-control) * 2.5); resize: vertical; }

.c-input::placeholder, .c-textarea::placeholder { color: var(--n-400); }
.c-input:hover, .c-select:hover, .c-textarea:hover { border-color: var(--n-500); }

/* Il bordo di un campo sta a 3,02:1 (--n-400) e non a 1,40:1 come nel sistema
   precedente: WCAG 1.4.11 chiede 3:1 al confine di un controllo, perche' un
   campo di cui non si vede il confine non si sa dove cliccare. */

.c-input--num {
  text-align: end;
  font-variant-numeric: tabular-nums;
}
.c-input--compact, .c-select--compact {
  min-height: calc(var(--h-control) - var(--sp-2));
  font-size: var(--fs-small);
}

.c-input[disabled], .c-select[disabled], .c-textarea[disabled] {
  color: var(--n-500);
  background: var(--n-100);
  border-color: var(--n-200);
}

/* Lo stato non valido NON si affida al colore: il bordo cambia spessore, e il
   messaggio e' scritto in .c-field__error con `aria-describedby`. In
   deuteranopia il rosso e il verde sono lo stesso colore (1,43:1): un campo
   sbagliato riconoscibile solo dal bordo rosso non e' riconoscibile. */
.c-input.is-invalid, .c-select.is-invalid, .c-textarea.is-invalid {
  border-color: var(--neg-500);
  border-width: 2px;
  padding-inline: calc(var(--sp-3) - 1px);
}

.c-checkbox {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  font-size: var(--fs-small);
  /* Il bersaglio di una casella e' l'etichetta intera, non il quadratino. */
  min-height: var(--h-control);
  cursor: pointer;
}
.c-checkbox input { width: 16px; height: 16px; flex: none; cursor: pointer; }

/* ── Il campo con la sua etichetta ───────────────────────────────────────── */
/* `align-content: start` e non lo stiramento di partenza. Un `.c-field` e' una
   griglia DENTRO una griglia: quando il fratello accanto porta anche un
   paragrafo d'aiuto, la riga diventa piu' alta e un campo senza aiuto si
   lasciava stirare — le sue due righe automatiche si spartivano lo spazio in
   piu' e il campo cresceva con loro. Fotografato su /clienti/1/modifica:
   «Giorni di dilazione» alto 36 px e «Citta'» alto 67 px, nella stessa riga:
   trentun pixel di vuoto spartiti fra la scatola dell'etichetta e il controllo,
   che resta allineato con l'etichetta (lo scarto fra le due e' di 4 px).
   Con `start` ogni campo resta alto quanto deve e tutti partono dall'alto. */
.c-field { display: grid; gap: var(--sp-1); min-width: 0; align-content: start; }

.c-field__label {
  font-size: var(--fs-small);
  font-weight: var(--fw-medium);
  color: var(--n-800);
}

/* L'asterisco non e' l'unico segnale: il campo porta `required` e il browser
   lo annuncia. Serve a chi guarda il modulo per decidere quanto tempo ci vuole. */
.c-field__required { color: var(--neg-600); }

/* L'AIUTO STA SOTTO IL CAMPO, non sopra. Sopra, si legge prima di sapere a che
   cosa si riferisce, e si rilegge dopo aver letto l'etichetta: due letture per
   una riga. Sotto, si legge quando serve — dopo aver visto il campo. */
.c-field__help {
  font-size: var(--fs-small);
  color: var(--n-500);
  max-width: var(--measure-prose);
}

.c-field__error {
  font-size: var(--fs-small);
  font-weight: var(--fw-medium);
  color: var(--neg-600);
}

.c-form { display: grid; gap: var(--sp-4); }
.c-form--inline { grid-auto-flow: column; align-items: end; justify-content: start; }
.c-form__grid { display: grid; gap: var(--sp-4); grid-template-columns: repeat(auto-fit, minmax(min(100%, 240px), 1fr)); }
.c-form__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-2);
  padding-block-start: var(--sp-2);
}

/* ── Il riquadro degli errori di un modulo ──────────────────────────────── */
.c-errors {
  padding: var(--sp-3) var(--sp-4);
  background: var(--neg-050);
  border-inline-start: 3px solid var(--neg-600);
  border-radius: var(--radius-inner);
}
.c-errors__title {
  margin: 0 0 var(--sp-1);
  font-size: var(--fs-small);
  font-weight: var(--fw-semi);
  color: var(--neg-600);
}
.c-errors__list { margin: 0; padding-inline-start: var(--sp-4); font-size: var(--fs-small); }

/* ── La ricerca ───────────────────────────────────────────────────────────
   E' un FORM vero (POST verso l'assistente), non una tendina JavaScript:
   funziona senza script, e la risposta e' una pagina che si puo' mettere nei
   preferiti. */
.c-search { position: relative; display: flex; align-items: center; max-width: 520px; width: 100%; }
.c-search__icon {
  position: absolute;
  inset-inline-start: var(--sp-3);
  color: var(--n-500);
  pointer-events: none;
}
.c-search__input {
  width: 100%;
  min-height: var(--h-control);
  padding: 0 var(--sp-7) 0 calc(var(--sp-3) + 18px + var(--sp-2));
  font-size: var(--fs-small);
  background: var(--n-100);
  border: 1px solid transparent;
  border-radius: var(--radius-control);
}
.c-search__input:hover { background: var(--n-000); border-color: var(--n-300); }
.c-search__input:focus { background: var(--n-000); border-color: var(--n-400); }
/* La scorciatoia di tastiera e' scritta dentro il campo: una scorciatoia che
   non si vede non esiste. */
.c-search__key {
  position: absolute;
  inset-inline-end: var(--sp-2);
  padding: 2px var(--sp-1);
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  color: var(--n-500);
  background: var(--n-000);
  border: 1px solid var(--n-200);
  border-radius: var(--radius-inner);
  pointer-events: none;
}

/* ── I filtri: una riga, e le scelte fatte si vedono ─────────────────────── */
.c-filters { display: grid; gap: var(--sp-2); }

/* A filtri vuoti la barra e' alta UNA riga di controllo. Nessun testo d'aiuto
   visibile: gli aiuti stanno dentro «Altri filtri», accanto al controllo che
   spiegano. Il sistema precedente teneva otto controlli e quattro paragrafi
   sempre aperti: 320px, piu' di quanto occupassero i dati. */
.c-filters__row {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: var(--sp-2);
}
.c-filters__row .c-field { flex: 0 1 180px; }
.c-filters__row .c-search { flex: 1 1 240px; }

.c-filters__more > summary {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-1);
  font-size: var(--fs-small);
  font-weight: var(--fw-medium);
  color: var(--g-600);
  cursor: pointer;
  list-style: none;
}
.c-filters__more > summary::-webkit-details-marker { display: none; }
.c-filters__more[open] > summary { margin-block-end: var(--sp-3); }
.c-filters__more .c-form__grid { padding: var(--sp-3) 0; }

/* Un filtro attivo e' una pastiglia CON IL SUO VALORE SCRITTO («Anno: 2026»,
   «Solo senza data»), e si toglie da sola. Prima, per sapere che cosa si stava
   guardando, bisognava rileggere otto controlli. Il conteggio delle righe
   trovate sta qui accanto: e' la risposta al filtro, non un blocco a parte. */
.c-filters__active {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-2);
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: var(--fs-small);
}
.c-filters__count { color: var(--n-500); }

/* ── Pastiglie e scaglie ──────────────────────────────────────────────────
   `c-chip` e' una scelta che si puo' togliere; `c-pill` e' un'etichetta ferma. */
.c-chips { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin: 0; padding: 0; list-style: none; }

.c-chip {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-1);
  padding: var(--sp-1) var(--sp-3);
  font-size: var(--fs-small);
  color: var(--n-800);
  text-decoration: none;
  background: var(--n-100);
  border: 1px solid var(--n-200);
  border-radius: var(--radius-pill);
}
.c-chip:hover { background: var(--n-200); color: var(--n-900); }
.c-chip.is-active {
  color: var(--n-900);
  background: var(--g-100);
  border-color: var(--g-400);
}
/* La × che toglie il filtro. Un bersaglio di 20px dentro una pastiglia di 28:
   sotto, diventa impossibile da centrare. */
.c-chip__drop {
  display: inline-grid;
  place-items: center;
  width: 20px;
  height: 20px;
  margin-inline-end: calc(-1 * var(--sp-1));
  color: var(--n-500);
  border-radius: var(--radius-pill);
}
.c-chip__drop:hover { color: var(--neg-600); background: var(--n-000); }

.c-pill {
  display: inline-block;
  padding: 1px var(--sp-2);
  font-size: var(--fs-micro);
  font-weight: var(--fw-medium);
  color: var(--n-600);
  background: var(--n-100);
  border-radius: var(--radius-inner);
}

/* ── Le schede di navigazione interna ─────────────────────────────────────
   «Cio' che e' scelto SALE»: la pastiglia attiva e' bianca su una traccia
   grigia, cioe' piu' CHIARA del fondo su cui sta. E' una regola gia' verificata
   e si riscrive col conto nuovo: la traccia e' --n-100 (1,16:1 sul bianco),
   quindi la pastiglia bianca ci stacca sopra di 1,16:1 di luminanza e porta il
   suo bordo. */
.c-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-1);
  padding: var(--sp-1);
  margin: 0;
  list-style: none;
  background: var(--n-100);
  border-radius: var(--radius-control);
}
.c-tabs__link {
  display: inline-block;
  padding: var(--sp-2) var(--sp-3);
  font-size: var(--fs-small);
  font-weight: var(--fw-medium);
  color: var(--n-600);
  text-decoration: none;
  border-radius: var(--radius-inner);
}
.c-tabs__link:hover { color: var(--n-900); }
.c-tabs__link.is-active {
  color: var(--n-900);
  background: var(--n-000);
  box-shadow: inset 0 0 0 1px var(--n-200);
}

/* ── Il selettore d'anno e la barra degli strumenti ─────────────────────── */
.c-yearpick { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); }
.c-yearpick__label {
  font-size: var(--fs-micro);
  font-weight: var(--fw-medium);
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
  color: var(--n-500);
}

.c-toolbar { display: grid; gap: var(--sp-3); }
.c-toolbar__row {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--sp-3);
}
.c-toolbar__body { display: flex; flex-wrap: wrap; align-items: flex-end; gap: var(--sp-2); }
.c-toolbar__actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); }

/* ── La paginazione: UNA, su ogni elenco ──────────────────────────────────
   Il sistema precedente aveva tre copie di questo markup — expenses, il suo
   gemello incomes (diverso per UNA riga, la chiave del locale) e una scritta a
   mano nel registro attivita' — e cinque famiglie di elenchi senza nessuna
   paginazione ne' limite: fatture, controparti, ricorrenze, le liste di
   impostazioni e la coda di riconciliazione, che pagina a 25 nel modello, legge
   `params[:pagina]` nel controller e non rendeva nessun controllo: oltre il
   venticinquesimo movimento la coda si raggiungeva solo scrivendo la query
   string a mano.
   Gli estremi si rendono come `span[aria-disabled]` e NON si omettono: un
   controllo che scompare sposta gli altri, e al secondo clic si preme il
   bottone sbagliato. */
.c-pagination {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  padding-block-start: var(--sp-3);
  border-block-start: 1px solid var(--n-200);
}
.c-pagination__status {
  font-size: var(--fs-small);
  color: var(--n-500);
  font-variant-numeric: tabular-nums;
}
.c-pagination [aria-disabled="true"] {
  color: var(--n-400);
  background: var(--n-100);
  border-color: var(--n-200);
  cursor: not-allowed;
}

/* ══ SUPERFICI ═══════════════════════════════════════════════════════════ */

/* ── La scheda ────────────────────────────────────────────────────────────
   Nessuna ombra, un filo di --n-200, raggio 14. Le schede stanno su --bg-page,
   che e' 1,10:1 sotto il bianco: il distacco c'e' gia', ed e' la relazione
   copiata dal sito di riferimento. Una superficie ferma che ha bisogno di
   un'ombra per sembrare una superficie e' una superficie che non si distingue
   dal fondo — e un'ombra che si stampa diventa una banda grigia.
   IL TITOLO RESTA DENTRO LA SCHEDA: decisione del 03/10, confermata. */
.c-card {
  background: var(--n-000);
  border: 1px solid var(--n-200);
  border-radius: var(--radius-card);
}

/* UN <fieldset> NON SI LASCIA STRINGERE. La sua `min-inline-size` di partenza e'
   `min-content`, e nessun `width` la tocca: finche' resta, un `.c-table-port`
   dentro di lui non scorre mai — perche' il porto riceve sempre tutta la
   larghezza che chiede, e a scorrere e' il DOCUMENTO.

   Misurato su /fatture/nuova (il solo modulo che mette una tabella dentro un
   fieldset, `invoices/_form.html.erb:81`): a 900 px la pagina sforava di 101 px
   e la colonna «Categoria» finiva fuori dallo schermo, senza nessuna barra su
   cui tornare indietro — il porto, che avrebbe dovuto prendersi lo scorrimento,
   misurava zero. Con questa riga lo sforamento del documento torna a zero e i
   134 px passano dentro il porto, dove c'e' una barra. */
fieldset.c-card { min-inline-size: 0; }

.c-card__head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--sp-3);
  padding: var(--sp-4) var(--sp-4) 0;
}

.c-card__title { font-size: var(--fs-title); }

/* Il suggerimento di una scheda: una riga, sotto il titolo, e non un paragrafo
   fra il titolo e il primo numero. Nessuna riga di prosa sta li'. */
.c-card__hint {
  margin: 0;
  max-width: var(--measure-prose);
  font-size: var(--fs-small);
  color: var(--n-500);
}

.c-card__body { padding: var(--sp-4); display: grid; gap: var(--sp-3); }
.c-card__body > * { min-width: 0; }

.c-card__foot {
  padding: var(--sp-3) var(--sp-4);
  font-size: var(--fs-small);
  color: var(--n-500);
  border-block-start: 1px solid var(--n-200);
}

/* Una scheda che porta LA cifra di risposta respira di piu': e' l'unico posto
   in cui il padding sale a --sp-5. */
.c-card--answer .c-card__body { padding: var(--sp-5); }

/* ── L'avviso in cornice ──────────────────────────────────────────────────
   Fondo = VELO (1,08:1 sul bianco), filetto a sinistra 3px dell'inchiostro,
   titolo obbligatorio. Il velo non e' una superficie satura: rosso e ambra, in
   questo sistema, non diventano mai una campitura — il verde e' l'unico
   accento. Il filetto porta il 7:1, quindi il tipo di avviso si legge anche
   senza colore, dalla posizione e dal titolo. */
.c-callout {
  display: grid;
  gap: var(--sp-1);
  padding: var(--sp-3) var(--sp-4);
  font-size: var(--fs-small);
  background: var(--n-100);
  border-inline-start: 3px solid var(--n-600);
  border-radius: var(--radius-inner);
}
.c-callout__title { font-size: var(--fs-small); font-weight: var(--fw-semi); }
.c-callout p { max-width: var(--measure-prose); }

.c-callout--info   { background: var(--n-100);    border-inline-start-color: var(--n-600); }
.c-callout--ok     { background: var(--g-050);    border-inline-start-color: var(--g-600); }
.c-callout--warn   { background: var(--warn-050); border-inline-start-color: var(--warn-600); }
.c-callout--danger { background: var(--neg-050);  border-inline-start-color: var(--neg-600); }
.c-callout--ok .c-callout__title     { color: var(--g-600); }
.c-callout--warn .c-callout__title   { color: var(--warn-600); }
.c-callout--danger .c-callout__title { color: var(--neg-600); }

/* ── Il messaggio di sistema ──────────────────────────────────────────────
   Nessun bottone di chiusura: la chiave di locale esisteva e non si usava, e un
   bottone che sposta il contenuto quando si preme e' peggio di un messaggio che
   resta. Scompare alla navigazione successiva, che e' quando ha finito. */
.c-flash {
  margin: 0;
  padding: var(--sp-3) var(--sp-4);
  font-size: var(--fs-small);
  font-weight: var(--fw-medium);
  border-block-end: 1px solid var(--n-200);
}
.c-flash--notice { color: var(--g-600);   background: var(--g-050);   border-block-end-color: var(--g-200); }
.c-flash--alert  { color: var(--neg-600); background: var(--neg-050); border-block-end-color: var(--neg-400); }

/* ── Lo stato vuoto: UNO, in due posizioni ────────────────────────────────
   Il sistema precedente ne aveva due incompatibili per lo stesso problema:
   `c-empty` in 24 file e `td.c-table__empty` in 10, con due `colspan` scritti
   a mano (6 e 7) da tenere in sincrono con due `thead`.
   Qui e' un componente solo. Dentro una tabella sta nel `tbody`, in una cella
   con `colspan`, cosi' l'intestazione resta visibile e LA FORMA DEL DATO CHE
   MANCA SI VEDE; il `colspan` lo calcola l'helper che disegna la tabella.
   Fuori da una tabella sta al centro del contenuto.

   E una regola di CONTENUTO: lo stato vuoto e' il posto giusto per le
   spiegazioni lunghe. Le frasi che stavano in cima a ogni pagina — «Il grafico
   disegna i giorni in cui i soldi si sono mossi. Finche' nessun movimento ha
   una data di regolamento non c'e' niente da disegnare: non e' un grafico
   piatto, e' un grafico che non esiste» — sono scritte bene e sono ESATTAMENTE
   cio' che serve quando non c'e' niente. Sono rumore quando il dato c'e'. */
.c-empty {
  display: grid;
  gap: var(--sp-2);
  justify-items: center;
  padding: var(--sp-6) var(--sp-4);
  text-align: center;
  color: var(--n-600);
  background: var(--n-000);
  border: 1px dashed var(--n-300);
  border-radius: var(--radius-card);
}
.c-empty__title { font-size: var(--fs-title); }
.c-empty p { max-width: var(--measure-prose); font-size: var(--fs-small); color: var(--n-500); }

/* Dentro una tabella: la cella si spoglia del fondo e del bordo, che sono della
   tabella, e tiene il passo e il centramento. */
.c-table .c-empty {
  border: 0;
  border-radius: 0;
  padding-block: var(--sp-5);
}

/* ══ LA TABELLA ══════════════════════════════════════════════════════════
   Il componente piu' importante dell'applicazione: quattordici pagine su
   quaranta sono tabelle, e tre difetti su nove stavano qui.

   LA DECISIONE: UNA TABELLA E' UN PORTO, NON UN FOGLIO CHE CRESCE.

   `position: sticky` si misura SUL PRIMO ANTENATO CHE SCORRE in quell'asse. Il
   contenitore precedente (`.c-table-port`) dichiarava `overflow-x: auto` e
   sperava di non diventare un porto verticale con `overflow-y: clip` — ma
   `clip` accanto a un valore di scorrimento CALCOLA `hidden`: il porto
   verticale esisteva, non aveva altezza, e l'intestazione si appiccicava a un
   bordo che non si muove mai. Non si e' mai appiccicata, e il difetto era
   dichiarato aperto nel commento del foglio da mesi.

   Dando al porto un'ALTEZZA MASSIMA VERA la stessa riga di CSS comincia a
   funzionare, e in piu' si guadagnano la prima colonna ferma e la riga dei
   totali ferma in basso.

   Il costo e' un'area di scorrimento annidata, e si paga come si paga gia':
   `tabindex="0"`, `role="region"` e una `aria-label` DIVERSA per ogni tabella
   della pagina — regola che il test d'igiene impone. */
.c-table-port {
  /* 70vh e NIENTE tetto in pixel. Il tetto c'era — `min(70vh, 720px)` — e su uno
     schermo alto faceva il contrario di quello che serve: la finestra ha 1.400
     pixel d'altezza, la tabella ne userebbe 980 e invece si ferma a 720,
     lasciando sette righe dentro un porto che scorre e trecento pixel di pagina
     vuota sotto. L'unico vincolo vero e' che il porto sia PIU' CORTO DELLA
     FINESTRA, altrimenti l'intestazione appiccicata non ha un bordo contro cui
     fermarsi: 70vh lo dice, e lo dice a ogni altezza. */
  max-height: 70vh;
  overflow: auto;
  overscroll-behavior: contain;
  background: var(--n-000);
  border: 1px solid var(--n-200);
  border-radius: var(--radius-card);
}
.c-table-port:focus-visible { outline-offset: -2px; }

.c-table {
  width: 100%;
  border-collapse: separate;
  border-spacing: 0;
  font-size: var(--fs-small);
}

/* La didascalia dice cosa c'e' nelle colonne PRIMA di leggerle, quindi e' testo
   che si legge: va allineata al bordo come ogni altro testo della pagina. Lo
   user-agent la centra — un residuo delle tabelle da quotidiano — e centrata
   sotto il titolo della scheda si legge come un sottotitolo decorativo invece
   che come la riga di servizio che e'. */
.c-table caption {
  padding: var(--sp-2) var(--sp-3);
  color: var(--n-500);
  font-size: var(--fs-small);
  text-align: start;
}

.c-table th, .c-table td {
  padding: var(--sp-2) var(--sp-3);
  min-height: var(--h-row);
  text-align: start;
  vertical-align: middle;
  border-block-end: 1px solid var(--n-200);
}
.c-table tbody tr:last-child td, .c-table tbody tr:last-child th { border-block-end: 0; }

/* L'INTESTAZIONE PORTA L'UNITA': «TOTALE (€)», «IVA (€)», «QUOTA (%)». Le celle
   portano il solo numero. In una colonna di cinquanta importi il simbolo
   ripetuto e' rumore con larghezza. */
.c-table thead th {
  position: sticky;
  inset-block-start: 0;
  z-index: 2;
  font-size: var(--fs-micro);
  font-weight: var(--fw-medium);
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
  color: var(--n-500);
  white-space: nowrap;
  background: var(--n-100);
  border-block-end: 1px solid var(--n-200);
}

.c-table tbody tr:hover td, .c-table tbody tr:hover th { background: var(--g-050); }

/* L'ALLINEAMENTO A DESTRA E LA LARGHEZZA FISSA sono la garanzia
   dell'incolonnamento, non `tabular-nums`: quella e' una richiesta che il font
   puo' ignorare, e lo si e' misurato. Questa no. */
.c-table__num {
  text-align: end;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

/* LA COLONNA CHE DICE QUAL E' LA RIGA. Un browser distribuisce la larghezza sul
   contenuto, e il contenuto piu' comprimibile e' il testo lungo: misurato su
   /uscite, la descrizione prendeva 110 px — «Viaggio Lamezia-Spoleto - ritorno:
   pranzo» su cinque righe — mentre la colonna dell'importo ne prendeva il doppio
   per via di una pastiglia, e fra le due restava spazio bianco. La colonna che
   identifica la riga non puo' essere la piu' stretta della tabella. */
.c-table__main { min-width: 16rem; }

/* UN MENU DENTRO UNA CELLA non puo' scendere sotto il proprio contenuto.
   `.c-select` dichiara `width: 100%`, che dentro una tabella vuol dire «la
   larghezza della COLONNA» — e la colonna la decide l'intestazione. Misurato su
   /fatture/nuova: «ALIQUOTA IVA» e' piu' stretta del suo stesso segnaposto e il
   menu si leggeva «Scegl»; sotto «CATEGORIA» si leggeva «Nessun» al posto di
   «Nessuna categoria», e scelta una categoria non se ne sarebbe letto il nome.

   Un minimo in rem e non `min-content`: con `min-content` la colonna prenderebbe
   la larghezza del nome di categoria piu' lungo dell'anagrafica, che non ha un
   tetto utile. 11rem tiene «Nessuna categoria» per intero. */
.c-table td > .c-select { min-width: 11rem; }

/* OGNI COLONNA DI IMPORTI HA IL SUO TOTALE, nel piede appiccicato in basso.
   Dieci elenchi mostravano soldi senza mai dirne la somma. Dove il totale non
   esiste come grandezza — una colonna di percentuali, di conteggi non
   sommabili — la cella dice «—» e NON resta vuota: una cella vuota si legge
   come un dato che manca, un trattino come un dato che non c'e'. */
.c-table tfoot td, .c-table tfoot th, .c-table__total {
  position: sticky;
  inset-block-end: 0;
  z-index: 2;
  font-weight: var(--fw-semi);
  color: var(--n-900);
  background: var(--n-100);
  border-block-start: 1px solid var(--n-300);
  border-block-end: 0;
}

/* DALLA SETTIMA COLONNA IN SU la prima colonna si appiccica: quattordici
   tabelle in tredici view la dichiarano, e a 1440px l'ultima colonna veniva
   tagliata dal bordo.
   La classe la scrive LA VIEW, a mano, quando la tabella passa le sei colonne:
   un helper che conti le colonne di una view non esiste e non puo' esistere
   senza renderla due volte. La larghezza della pagina e' un'altra cosa e la
   chiede la pagina, con `content_for :pagina_larga`; la verifica sta in
   ShellTest. */
.c-table--wide tbody th:first-child,
.c-table--wide tbody td:first-child {
  position: sticky;
  inset-inline-start: 0;
  z-index: 1;
  background: var(--n-000);
  border-inline-end: 1px solid var(--n-200);
}
.c-table--wide tbody tr:hover td:first-child,
.c-table--wide tbody tr:hover th:first-child { background: var(--g-050); }
/* L'angolo: l'intestazione della prima colonna deve stare sopra entrambi. */
.c-table--wide thead th:first-child { z-index: 3; inset-inline-start: 0; }
.c-table--wide tfoot td:first-child, .c-table--wide tfoot th:first-child { z-index: 3; inset-inline-start: 0; }

/* E LA COLONNA DELLE AZIONI SI APPICCICA DALL'ALTRA PARTE, per la stessa ragione
   e con la stessa simmetria: la prima colonna dice QUALE riga e', l'ultima dice
   che cosa ci si puo' fare. L'ultima e' sempre l'ultima, quindi in una tabella
   che scorre era sempre lei a finire oltre il bordo del porto.

   Misurato fotografando a 1440 px: su /uscite dei tre bottoni se ne vedeva uno
   solo, e tagliato a meta'; su /conti «Chiudi» era mozzato. Nove delle
   quattordici tabelle larghe hanno una colonna di azioni, e tutte e nove
   avevano lo stesso difetto — che non e' di una pagina ma di questa regola, che
   mancava. */
.c-table--wide tbody td.c-table__actions {
  position: sticky;
  inset-inline-end: 0;
  z-index: 1;
  background: var(--n-000);
  border-inline-start: 1px solid var(--n-200);
}
.c-table--wide tbody tr:hover td.c-table__actions { background: var(--g-050); }
.c-table--wide thead th.c-table__actions { z-index: 3; inset-inline-end: 0; }
.c-table--wide tfoot td.c-table__actions,
.c-table--wide tfoot th.c-table__actions { z-index: 3; inset-inline-end: 0; }

/* L'intestazione ordinabile resta un <button> dentro il <th> con `aria-sort`, e
   la sua freccia resta geometria SVG in attributi: la CSP vieta `style=`,
   quindi la larghezza non puo' passare da CSS in linea. */
.c-table__sort {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-1);
  padding: 0;
  font: inherit;
  letter-spacing: inherit;
  text-transform: inherit;
  color: inherit;
  background: none;
  border: 0;
  cursor: pointer;
}
.c-table__sort:hover { color: var(--n-900); }
.c-table th[aria-sort] .c-table__sort { color: var(--n-900); }

/* LA RIGA NON E' CLICCABILE TUTTA: l'azione sta in un bottone o in un link con
   un nome. Una riga-bersaglio nasconde che cosa fara' il clic, e con dieci
   colonne la zona «sicura» per selezionare del testo non esiste piu'. */
.c-table__actions { width: 1%; white-space: nowrap; text-align: end; }

/* UN MODULO NELLA COLONNA DELLE AZIONI. Su /impostazioni/utenti la
   disattivazione chiede di ridigitare la propria password, e quella cella porta
   etichetta, campo e bottone invece di due bottoni. `.c-field` e' una griglia
   con `min-width: 0` — si lascia stringere fino a zero — quindi la colonna
   riceveva 104,5 px e l'etichetta, che e' `nowrap`, veniva tagliata dal porto: si
   leggeva «La tua passwor» e il campo non c'era. 11rem e' la larghezza sotto la
   quale un campo di testo smette di essere un campo di testo. */
.c-table__actions .c-field { min-width: 11rem; }

.c-table .is-discarded { color: var(--n-500); }
.c-table .is-discarded .c-num { text-decoration: line-through; }

/* ── La riga di totali fuori tabella ────────────────────────────────────── */
.c-totals {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-5);
  padding: var(--sp-3) var(--sp-4);
  background: var(--n-100);
  border: 1px solid var(--n-200);
  border-radius: var(--radius-card);
}
.c-totals__item { display: grid; gap: 2px; }
.c-totals__key {
  font-size: var(--fs-micro);
  font-weight: var(--fw-medium);
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
  color: var(--n-500);
}
.c-totals__val { font-size: var(--fs-figure); font-weight: var(--fw-semi); color: var(--n-900); }

/* ── La coppia chiave/valore ────────────────────────────────────────────── */
.c-preview { display: grid; gap: 0; font-size: var(--fs-small); }
.c-preview__row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: var(--sp-3);
  padding: var(--sp-2) 0;
  border-block-end: 1px solid var(--n-200);
}
.c-preview__row:last-child { border-block-end: 0; }
.c-preview__key { color: var(--n-500); }
.c-preview__val { text-align: end; font-variant-numeric: tabular-nums; }

/* ══ I DATI ══════════════════════════════════════════════════════════════ */

/* ── Il numero ────────────────────────────────────────────────────────────
   LA CATEGORIA STA SUL VALORE, NON SULLA CELLA, e `kind:` e' obbligatorio
   senza predefinito: un predefinito renderebbe la scelta piu' comoda, e fra sei
   mesi sarebbe di nuovo la meta' dei numeri dell'applicazione.

   IL COLORE NON PORTA MAI IL SEGNO DA SOLO. Il conto che lo impone: --g-500 e
   --neg-500 stanno entrambi a 4,5:1 sul bianco, e nella simulazione di
   deuteranopia di Vienot 1999 diventano #757412 e #8F8F00 — 1,43:1 di
   separazione, cioe' lo stesso colore. Cercando su trentacinque combinazioni di
   tonalita' e luminanza, il massimo ottenibile e' 2,35:1, sotto il 3:1
   necessario. Quindi il segno si STAMPA sempre dove e' informazione, e il
   colore lo conferma. */
.c-num { font-variant-numeric: tabular-nums; white-space: nowrap; }

/* Il verso, e solo dove entrate e uscite convivono nella stessa colonna
   (Cassa, Scadenze, Riconciliazione). Sulla pagina Uscite ogni riga e' un'uscita:
   colorarle tutte spenderebbe l'unico colore d'allarme che c'e' per ripetere
   cio' che dice il titolo della pagina. */
.c-num--in  { color: var(--g-500); }
.c-num--out { color: var(--neg-500); }

/* Un saldo, un risultato, uno scarto: qui il SEGNO e' l'informazione, quindi si
   stampa sempre (lo fa l'helper) e il colore lo conferma. */
.c-num--balance.is-positive { color: var(--g-500); }
.c-num--balance.is-negative { color: var(--neg-500); }

/* Una partita aperta e un impegno previsto: non un allarme, ma qualcosa che non
   e' ancora successo. */
.c-num--open    { color: var(--warn-500); }
.c-num--planned { color: var(--n-500); }

/* Imponibile e IVA stanno ACCANTO al numero che conta e non devono competerci:
   su una riga d'uscita tre importi allo stesso peso chiedono la stessa
   attenzione, e quello che si cerca non si trova. */
.c-num--derived { color: var(--n-500); }

.c-num--zero  { color: var(--n-500); }
.c-num--blank { color: var(--n-400); }
.c-num--count { color: inherit; }
.c-num--pct   { color: var(--n-600); }
.c-num--date  { color: inherit; }
.c-num--ref   { font-family: var(--font-mono); font-size: 0.95em; color: var(--n-600); }

/* ── La pastiglia di stato ────────────────────────────────────────────────
   LA PAROLA DENTRO LA PASTIGLIA E' SEMPRE SCRITTA. Non e' una cortesia: in
   deuteranopia il colore non separa, quindi una pastiglia riconoscibile solo
   dalla tinta non e' riconoscibile. Il colore e' un rinforzo.
   Nessuna variante e' costruita per interpolazione: l'helper restituisce il
   nome INTERO della classe, cosi' il test statico la vede. */
.c-badge {
  display: inline-block;
  padding: 1px var(--sp-2);
  font-size: var(--fs-micro);
  font-weight: var(--fw-medium);
  letter-spacing: var(--ls-label);
  white-space: nowrap;
  border-radius: var(--radius-inner);
  border: 1px solid transparent;
}
.c-badge--neutral { color: var(--n-600);    background: var(--n-100);    border-color: var(--n-200); }
.c-badge--quiet   { color: var(--n-500);    background: transparent;     border-color: var(--n-200); }
.c-badge--paid    { color: var(--g-600);    background: var(--g-050);    border-color: var(--g-200); }
.c-badge--unpaid  { color: var(--warn-600); background: var(--warn-050); border-color: var(--warn-400); }
.c-badge--overdue { color: var(--neg-600);  background: var(--neg-050);  border-color: var(--neg-400); }
.c-badge--planned { color: var(--n-600);    background: var(--n-100);    border-color: var(--n-300); }
/* Le due specie delle entrate, che l'helper delle fatture produce per nome. */
.c-badge--collected   { color: var(--g-600);    background: var(--g-050);    border-color: var(--g-200); }
.c-badge--uncollected { color: var(--warn-600); background: var(--warn-050); border-color: var(--warn-400); }

/* ── La tessera ───────────────────────────────────────────────────────────
   IL QUADRATINO D'ICONA SPARISCE. Non perche' sia brutto: perche' non porta
   informazione. Sulle undici tessere della Dashboard la stessa icona di carta
   di credito compariva su «Soldi rimasti», «Messi dai soci» e «Cassa di fatto»,
   che sono tre grandezze diverse; e il suo fondo stava a 1,05:1, cioe' era
   invisibile. Al suo posto, quando c'e' qualcosa da dire, va un DATO: la
   sparkline o la variazione sul periodo precedente.
   Tre regole: una tessera senza nota e' legittima; una tessera non e' un posto
   per un numero che non si e' chiesto; la variazione ha SEMPRE il suo periodo
   scritto («+12 % sul mese scorso», non «+12 %»). */
.c-tile {
  display: grid;
  gap: var(--sp-1);
  padding: var(--sp-4);
  background: var(--n-000);
  border: 1px solid var(--n-200);
  border-radius: var(--radius-card);
}
.c-tile__label {
  font-size: var(--fs-micro);
  font-weight: var(--fw-medium);
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
  color: var(--n-500);
}
.c-tile__value {
  font-size: var(--fs-figure);
  font-weight: var(--fw-semi);
  line-height: var(--lh-tight);
  color: var(--n-900);
  font-variant-numeric: tabular-nums;
}
.c-tile__note { font-size: var(--fs-small); color: var(--n-500); }
.c-tile__spark { width: 100%; height: 28px; margin-block-start: var(--sp-1); }

/* ── LA cifra che risponde alla domanda della pagina ──────────────────────
   Al massimo UNA per pagina, e lo verifica un test sul markup. E' la regola che
   traduce «va dritta al punto» in qualcosa di controllabile, e nasce da un
   difetto misurato: la Dashboard mostrava undici tessere prima del primo
   grafico, dieci delle quali alla stessa misura. Una pagina con undici numeri
   grandi non ha un numero grande: ha uno sfondo di numeri. */
.c-answer {
  display: grid;
  gap: var(--sp-1);
}
.c-answer__value {
  font-size: var(--fs-answer);
  font-weight: var(--fw-semi);
  line-height: 1.1;
  color: var(--n-900);
  font-variant-numeric: tabular-nums;
}
.c-answer__label {
  font-size: var(--fs-micro);
  font-weight: var(--fw-medium);
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
  color: var(--n-500);
}
.c-answer__note { font-size: var(--fs-small); color: var(--n-500); max-width: var(--measure-prose); }
.c-answer__value.is-negative { color: var(--neg-500); }

/* ── Il pallino di categoria ──────────────────────────────────────────────
   Resta un QUADRATO SMUSSATO e non un cerchio: il cerchio e' la forma degli
   stati (il pallino degli avvisi), e due significati con la stessa forma si
   confondono. Regola verificata il 28/09.
   I sei gradini sono quelli delle categorie, assegnati per RANGO: il colore
   scelto a mano per categoria non esiste piu' (il patto fra pallino e striscia
   e' l'unica ragione per cui il pallino esiste, e un colore arbitrario lo
   rompe). Ogni forma piena porta il contorno di --g-400: --cat-1 sul bianco fa
   1,33:1, e senza contorno i suoi confini non si vedrebbero. */
.c-dot {
  display: inline-block;
  width: 10px;
  height: 10px;
  flex: none;
  background: var(--n-300);
  border: 1px solid var(--g-400);
  border-radius: 3px;
}
.c-dot--1 { background: var(--cat-1); }
.c-dot--2 { background: var(--cat-2); }
.c-dot--3 { background: var(--cat-3); }
.c-dot--4 { background: var(--cat-4); }
.c-dot--5 { background: var(--cat-5); }
.c-dot--6 { background: var(--cat-6); }
/* Il residuo — «Non ancora indicato» — prende l'ultimo gradino E lo dice a
   parole nella tabella: sui dati veri e' il segmento piu' grande (64,9 %), e un
   residuo che sembra una categoria e' un dato inventato. */
.c-dot--residual { background: var(--cat-6); border-color: var(--n-400); }

.c-dotname { display: inline-flex; align-items: center; gap: var(--sp-2); min-width: 0; }

/* ── Il misuratore ────────────────────────────────────────────────────────
   Un solo componente per il punteggio di riconciliazione E per la barra di
   budget. I tre gradini si separano per LUMINANZA e non per tinta, perche' un
   misuratore letto in deuteranopia deve dire la stessa cosa. */
.c-meter { display: flex; align-items: center; gap: var(--sp-2); }
.c-meter__svg { width: 72px; height: 8px; flex: none; }
/* Il misuratore di un AVVISO, non di una cella: li' confronta due numeri dentro
   una riga di tabella, qui e' la figura di un paragrafo e sta su una riga sua.
   `max-width` e non una larghezza fissa: una barra lunga quanto lo schermo
   renderebbe illeggibile la distanza fra il riempimento e la tacca. */
.c-meter__svg--wide { width: 100%; max-width: 320px; height: 10px; }
/* IL MISURATORE DI UNA CELLA, quando la cella ha la tacca. 72 px bastano a un
   riempimento solo; con due segni dentro no — misurato sul budget: una riga al
   20 % contro un ritmo del 25,81 % metteva il bordo del riempimento e la tacca a
   QUATTRO pixel di distanza, cioe' la domanda «l'ho superato?» non si poteva
   rispondere guardando. A 160 px gli stessi due numeri distano nove pixel. */
.c-meter__svg--cell { width: 160px; height: 8px; }
.c-meter__track { fill: var(--n-200); }
.c-meter__bar { fill: var(--g-500); }
.c-meter__bar--weak   { fill: var(--g-200); }
.c-meter__bar--medium { fill: var(--g-400); }
.c-meter__bar--strong { fill: var(--g-600); }
.c-meter__value {
  margin: 0;
  font-size: var(--fs-small);
  color: var(--n-600);
  font-variant-numeric: tabular-nums;
}
/* LA TACCA DEL RITMO: dove e' arrivato il mese, non quanto si e' speso. E' cio'
   che rende «a rischio» una cosa che si VEDE invece di una parola da credere —
   il riempimento che ha superato la tacca. La parola resta comunque, nel
   `title` e nell'etichetta accessibile: una relazione geometrica non e' una
   parola, e togliere l'unico portatore testuale di uno stato e' una perdita.

   --n-900 E NON --n-600, ed e' un conto: la tacca va letta SOPRA IL
   RIEMPIMENTO, perche' il caso che conta e' proprio quello in cui il
   riempimento l'ha superata. --n-600 su --g-500 fa 1,57:1 — misurato, la tacca
   spariva dentro il verde esattamente nelle righe a rischio. --n-900 fa 3,80:1,
   cioe' la soglia 1.4.11 per un oggetto grafico, e sulla traccia (--n-200) resta
   oltre 10:1. */
.c-meter__pace { fill: var(--n-900); }

/* ── La striscia impilata ─────────────────────────────────────────────────
   Una partizione: niente testo dentro, fili bianchi fra i segmenti, e il
   contorno di --g-400 su ogni area. `preserveAspectRatio="none"` perche' una
   partizione non ha proporzioni da conservare — solo rapporti. */
.c-stack { display: grid; gap: var(--sp-2); }
.c-stack__svg { width: 100%; height: 14px; border-radius: var(--radius-inner); }
.c-stack__track { fill: var(--n-100); }

/* ── Gli elenchi di stato ─────────────────────────────────────────────────
   Il punteggio di un abbinamento e i controlli di «Da fare». Lo stato e' una
   PAROLA, e il colore un rinforzo: tre segnali che si distinguono solo per
   tinta sarebbero tre segnali uguali per chi non vede la tinta. */
.c-signals, .c-checks { display: grid; gap: var(--sp-1); margin: 0; padding: 0; list-style: none; font-size: var(--fs-small); }
.c-signal, .c-check {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  padding: var(--sp-1) 0;
}
.c-signal--hit  { color: var(--g-600); }
.c-signal--miss { color: var(--neg-600); }
.c-signal--unavailable { color: var(--n-500); }
.c-check--ok    { color: var(--n-500); }
.c-check--warn  { color: var(--warn-600); }
.c-check--error { color: var(--neg-600); }
.c-check__count { margin-inline-start: auto; font-weight: var(--fw-semi); font-variant-numeric: tabular-nums; }

/* ── I passi di una procedura ─────────────────────────────────────────────── */
.c-steps { margin: 0; }
.c-steps__list { display: flex; flex-wrap: wrap; gap: var(--sp-4); margin: 0; padding: 0; list-style: none; }
.c-steps__step { display: flex; align-items: center; gap: var(--sp-2); font-size: var(--fs-small); color: var(--n-500); }
.c-steps__number {
  display: inline-grid;
  place-items: center;
  width: 22px;
  height: 22px;
  font-size: var(--fs-micro);
  font-weight: var(--fw-semi);
  color: var(--n-600);
  background: var(--n-100);
  border: 1px solid var(--n-300);
  border-radius: var(--radius-pill);
}
.c-steps__step.is-current { color: var(--n-900); font-weight: var(--fw-medium); }
.c-steps__step.is-current .c-steps__number { color: var(--n-900); background: var(--g-200); border-color: var(--g-400); }
.c-steps__step.is-done .c-steps__number { color: var(--on-dark-1); background: var(--g-600); border-color: var(--g-600); }

/* ── Il candidato di un abbinamento ───────────────────────────────────────── */
.c-candidates { display: grid; gap: var(--sp-2); margin: 0; padding: 0; list-style: none; }
.c-candidate {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: var(--sp-3);
  align-items: center;
  padding: var(--sp-3);
  background: var(--n-000);
  border: 1px solid var(--n-200);
  border-radius: var(--radius-control);
}
.c-candidate:hover { border-color: var(--g-400); background: var(--g-050); }
.c-candidate__main { display: grid; gap: 2px; min-width: 0; }
.c-candidate__title { font-size: var(--fs-small); font-weight: var(--fw-medium); }
.c-candidate__meta { font-size: var(--fs-micro); color: var(--n-500); }
.c-candidate__amount { font-size: var(--fs-small); font-weight: var(--fw-semi); font-variant-numeric: tabular-nums; }

/* ── L'elenco delle modifiche del registro attivita' ─────────────────────── */
/* L'elenco dei campi cambiati, dentro una cella del registro attivita'.

   Il tetto e' un'assicurazione, non una potatura: la potatura la fa l'helper, che
   di una creazione elenca le sole colonne valorizzate. Misurato sul registro vero:
   la riga mediana e' di 5 campi, la piu' lunga di 19. A 1440 px quella riga
   occupa 351,5 px; sotto i 1024 px i valori vanno a capo e arriva a 385. Il tetto
   stava a 22rem = 352 px, cioe' mezzo pixel sopra il caso largo e TRENTATRE SOTTO
   il caso stretto: tre celle su settanta nascondevano del testo su uno schermo
   piccolo, e il commento che stai leggendo diceva il contrario. 25rem = 400 px
   le tiene tutte, e una riga patologica (un'importazione con trenta colonne) non
   si porta comunque via la pagina. Prima della potatura la peggiore era di 34
   campi, cioe' 562 px di cella.

   Non si perde niente comunque: dentro si scorre, e il contenitore e'
   `tabindex="0"` perche' con la sola tastiera lo si possa scorrere. A SCHERMO.
   Su carta non si scorre, quindi il tetto va tolto: lo fa `print.css`, e
   dimenticarlo significa stampare un registro a cui mancano dei campi senza che
   si veda — che e' il difetto n.3 dichiarato in testa a quel foglio. */
.c-changelist {
  max-height: 25rem;
  overflow-y: auto;
  font-size: var(--fs-micro);
  color: var(--n-600);
}
.c-changelist > div { padding: 1px 0; }

/* ── L'avatar ─────────────────────────────────────────────────────────────── */
.c-avatar {
  display: inline-grid;
  place-items: center;
  width: 30px;
  height: 30px;
  flex: none;
  font-size: var(--fs-micro);
  font-weight: var(--fw-semi);
  letter-spacing: var(--ls-label);
  color: var(--n-900);
  background: var(--g-200);
  border-radius: var(--radius-pill);
}
/* Sulla barra verde il verde del sito non stacca abbastanza da se stesso:
   l'avatar li' diventa bianco con inchiostro verde profondo (11,14:1). */
.c-avatar--nav { color: var(--g-700); background: var(--on-dark-1); }

/* ══ LA NAVIGAZIONE ══════════════════════════════════════════════════════ */

/* La barra laterale e' VERDE PROFONDA, e la voce attiva e' una pastiglia col
   verde del sito e testo NERO sopra: 8,36:1 di stacco dal fondo della barra,
   15,76:1 fra il testo e la pastiglia. */
.c-sidenav { display: flex; flex-direction: column; min-height: 100vh; }
.c-sidenav__body { flex: 1; padding: var(--sp-3) var(--sp-2); overflow-y: auto; }

/* L'INTESTAZIONE DI UN GRUPPO. E' un <h2> vero — la barra e' una navigazione
   con quattro sezioni, e `aria-labelledby` lega ogni elenco al suo titolo —
   quindi eredita il colore dei titoli, che e' --n-900: quasi nero su verde
   profondo, cioe' invisibile. Qui si corregge, e non e' un dettaglio: il
   sistema precedente metteva questo testo a 2,76:1 sul proprio fondo e lo
   dichiarava come debito nel proprio commento. --on-dark-2 porta 6,16:1. */
.c-sidenav__group {
  margin: var(--sp-4) 0 var(--sp-1);
  padding-inline: var(--sp-3);
  font-size: var(--fs-micro);
  font-weight: var(--fw-medium);
  letter-spacing: var(--ls-eyebrow);
  text-transform: uppercase;
  color: var(--on-dark-2);
}
.c-sidenav__group:first-of-type { margin-block-start: var(--sp-2); }
.is-collapsed .c-sidenav__group {
  /* A barra ristretta il nome del gruppo non sta su 72px. Non si nasconde con
     `display: none`, che lo toglierebbe anche all'albero di accessibilita' e
     lascerebbe quattro elenchi senza titolo: si toglie dalla VISTA e resta per
     chi legge con la voce. E' lo stesso criterio della pastiglia di conteggio,
     che invece sparisce davvero perche' il suo numero vive gia' nel `title`
     del link. */
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.c-navlist { margin: 0; padding: 0; list-style: none; display: grid; gap: 2px; }
.c-navlist li { display: flex; align-items: center; }

.c-navlist__link {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  flex: 1;
  min-width: 0;
  min-height: var(--h-control);
  padding: 0 var(--sp-3);
  font-size: var(--fs-small);
  color: var(--on-dark-1);
  text-decoration: none;
  border-radius: var(--radius-control);
  white-space: nowrap;
}
.c-navlist__link:hover { color: var(--on-dark-1); background: var(--g-800); }

/* La voce attiva e' una pastiglia col VERDE DEL SITO e testo NERO sopra:
   8,36:1 di stacco dal fondo della barra, 15,76:1 fra il testo e la pastiglia.
   Scrivere bianco qui sarebbe 1,33:1 — ed e' uno dei dodici divieti. */
.c-navlist__link.is-active {
  color: var(--n-900);
  background: var(--on-dark-pill);
  font-weight: var(--fw-medium);
}
.c-navlist__link.is-active:hover { color: var(--n-900); background: var(--g-100); }

/* Il TESTO di una voce, dentro il link: eredita il colore del link, cosi' sulla
   pastiglia attiva diventa nero da solo. */
.c-sidenav__label { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.is-collapsed .c-sidenav__label { display: none; }
.is-collapsed .c-navlist__link { justify-content: center; padding-inline: 0; }

/* La pastiglia di conteggio. UNA PASTIGLIA A ZERO NON ESISTE — un contatore che
   dice sempre qualcosa non conta niente — e il suo numero vive anche nel
   `title` del link, che e' il motivo per cui qui puo' sparire del tutto a barra
   ristretta senza portarsi via un'informazione. */
.c-sidenav .c-pill {
  flex: none;
  margin-inline: calc(-1 * var(--sp-2)) var(--sp-2);
  color: var(--g-700);
  background: var(--on-dark-pill);
  border-radius: var(--radius-pill);
  font-variant-numeric: tabular-nums;
}
.is-collapsed .c-sidenav .c-pill { display: none; }

/* Il marchio e l'interruttore del cassetto. Il `<details>` e' la forma che
   funziona senza JavaScript: l'interruttore e' il `<summary>`, e il browser lo
   apre da se'. */
.c-sidenav__brand { border-block-end: 1px solid var(--on-dark-3); }
.c-sidenav__toggle {
  /* NASCOSTO di norma: sopra la soglia stretta non c'e' nessuna tendina da
     comandare — la barra e' una colonna, e il comando che la restringe sta nella
     barra in alto. Torna visibile sotto gli 860 px, dove questo <summary> E' il
     menu. */
  display: none;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-2);
  min-height: var(--h-topbar);
  padding-inline: var(--sp-4);
  font-size: var(--fs-small);
  font-weight: var(--fw-medium);
  color: var(--on-dark-1);
  cursor: pointer;
  list-style: none;
}
.c-sidenav__toggle::-webkit-details-marker { display: none; }

/* ── Sotto la soglia stretta la barra E' la tendina ───────────────────────
   860 px: lo stesso numero della soglia di base.css e del token --bp-narrow.
   Scritto qui e non li' perche' questo foglio viene DOPO: una media query non
   aggiunge specificita', e la regola senza soglia vincerebbe comunque. */
@media (max-width: 860px) {
  .c-sidenav { min-height: 0; }
  .c-sidenav__toggle { display: flex; }

  /* Il corpo del menu GALLEGGIA sopra il contenuto invece di spingerlo in giu':
     venti voci spinte sotto il titolo lascerebbero la pagina a schermo vuoto
     proprio mentre si cerca dove andare. Parte sotto la fascia del comando, che
     resta in testa e si tocca una seconda volta per chiudere.

     L'UNICA ombra del sistema, e questo e' il suo unico lettore: il menu aperto
     e' la sola superficie dell'applicazione che galleggia sopra un'altra. Le
     schede non ce l'hanno — stanno su --bg-page, 1,10:1 sotto il bianco, e il
     distacco c'e' gia'. */
  .c-sidenav[open] .c-sidenav__body {
    position: fixed;
    inset-block: var(--h-topbar) 0;
    inset-inline-start: 0;
    width: var(--w-sidebar);
    z-index: 40;
    background: var(--g-700);
    border-inline-end: 1px solid var(--on-dark-3);
    box-shadow: var(--shadow-pop);
  }
}

/* Le icone della barra: ereditano il colore del link, quindi diventano nere
   sulla pastiglia attiva senza una regola in piu'. */
.c-sidenav .c-icon { flex: none; }

/* ══ I GRAFICI ═══════════════════════════════════════════════════════════
   Le regole di disegno stanno nel capitolo 4 del piano. Qui solo i colori e i
   tratti, perche' la geometria vive negli attributi dell'SVG: un <text> dentro
   un SVG ha il corpo in unita' di viewBox, quindi scala col disegno, e la
   larghezza minima e massima di una colonna che contiene un grafico sono token.

   NESSUNA LEGENDA. Le serie si etichettano dove finiscono, e due serie si
   distinguono per TRATTO prima che per colore: il conto della deuteranopia dice
   che una legenda costringe a tenere a mente un accoppiamento colore→nome, che
   e' esattamente la cosa che il daltonismo rompe. */
.c-chart { display: grid; gap: var(--sp-3); }

/* IL DISEGNO SCORRE, LA SCHEDA NO.
   Un <text> dentro un SVG ha il corpo in unita' di viewBox, quindi SCALA col
   disegno: sotto una certa larghezza le etichette degli assi diventano
   illeggibili, e non c'e' nessuna media query che possa salvarle — il testo non
   e' testo CSS, e' geometria. Quindi sotto il minimo il disegno non
   rimpicciolisce: SCORRE dentro il suo porto.
   I due limiti sono frazioni della larghezza del viewBox (0,875x e 1,2x di 640)
   e stanno in tokens.css perche' il Ruby che le calcola le deve ritrovare
   uguali: un test lega i due numeri a `ChartsHelper::BARS_WIDTH`. */
.c-chart__plot {
  overflow-x: auto;
  overscroll-behavior-x: contain;
}
.c-chart__svg {
  width: 100%;
  min-width: var(--chart-w-min);
  max-width: var(--chart-w-max);
  height: auto;
  overflow: visible;
}

/* Il reticolo deve guidare l'occhio senza competere col dato, e l'asse deve
   essere un confine vero: il sistema precedente dichiarava nel proprio commento
   che il reticolo era «piu' chiaro del bordo di una scheda» e NON lo era —
   1,21:1 contro 1,18:1, cioe' lo stesso peso. */
.c-chart__grid  { stroke: var(--n-200); stroke-width: 1; }
.c-chart__base  { stroke: var(--n-400); stroke-width: 1; }
.c-chart__zero  { stroke: var(--n-600); stroke-width: 1; }
.c-chart__track { fill: var(--n-100); }

.c-chart__tick, .c-chart__label {
  fill: var(--n-500);
  font-size: 11px;
  font-variant-numeric: tabular-nums;
}
.c-chart__value {
  fill: var(--n-900);
  font-size: 11px;
  font-weight: var(--fw-medium);
  font-variant-numeric: tabular-nums;
}
.c-chart__caption { font-size: var(--fs-small); color: var(--n-500); }

/* IL NOME DI UN PANNELLO dentro una figura a piu' disegni. Non e' la didascalia
   della figura (`--n-500`, il grigio di cio' che qualifica): e' l'etichetta della
   cosa che sta sotto, quindi sta un gradino piu' scuro e ha il peso medio. Sopra
   il secondo pannello e' l'unica riga che dice che quella curva e' il
   progressivo. */
.c-chart__panel {
  font-size: var(--fs-small);
  font-weight: var(--fw-medium);
  color: var(--n-600);
  margin-block-end: var(--sp-1);
}
.c-chart__plot + .c-chart__panel { margin-block-start: var(--sp-4); }

/* OGNI FORMA PIENA HA UN CONTORNO DI 1px IN --g-400. --cat-1 sul bianco di una
   scheda fa 1,33:1: il suo bordo non si vedrebbe, e una barra impilata il cui
   segmento piu' chiaro non ha confini non si misura a occhio. Il contorno a 3:1
   glielo ridà. */
.c-chart__bar { fill: var(--g-200); stroke: var(--g-400); stroke-width: 1; }
.c-chart__bar--1 { fill: var(--cat-1); }
.c-chart__bar--2 { fill: var(--cat-2); }
.c-chart__bar--3 { fill: var(--cat-3); }
.c-chart__bar--4 { fill: var(--cat-4); }
.c-chart__bar--5 { fill: var(--cat-5); }
.c-chart__bar--6 { fill: var(--cat-6); }
.c-chart__bar--residual { fill: var(--cat-6); stroke: var(--n-400); }

/* Le due serie di un grafico nel tempo: la prima piena, la seconda TRATTEGGIATA.
   Il tratto porta l'informazione, il colore la conferma. */
.c-chart__bar--revenue { fill: var(--g-300); stroke: var(--g-500); }
.c-chart__bar--expense { fill: var(--n-200); stroke: var(--n-500); stroke-dasharray: 2 2; }

.c-chart__line {
  fill: none;
  stroke: var(--g-500);
  stroke-width: 2;
  stroke-linejoin: round;
  stroke-linecap: round;
}
.c-chart__line--forecast { stroke-dasharray: 5 4; }
.c-chart__area { fill: var(--g-050); }

/* La soglia: TRATTEGGIATA, con l'importo scritto in capo alla linea. Il
   tratteggio e' il portatore, non il rosso. */
.c-chart__threshold { stroke: var(--neg-600); stroke-width: 1; stroke-dasharray: 4 3; fill: none; }

.c-chart__point { fill: var(--g-500); stroke: var(--n-000); stroke-width: 1.5; }
/* Il giorno di sforamento: un cerchio pieno con la sua DATA scritta accanto. */
.c-chart__point--breach { fill: var(--neg-500); }

/* La tabella equivalente di un grafico: non e' un ripiego per chi non vede il
   disegno, e' il posto dove stanno i numeri esatti. Dove la tabella accanto al
   grafico c'e' gia' per conto suo, questa NON si rende: stampare due volte la
   stessa tabella era un difetto del sistema precedente. */
.c-chart__data > summary {
  font-size: var(--fs-small);
  color: var(--g-600);
  cursor: pointer;
}
.c-chart__data[open] > summary { margin-block-end: var(--sp-2); }

/* ══ CODA: le parti che vivono su una sola pagina ════════════════════════
   Entrano qui perche' il foglio e' il posto dove un nome di classe esiste, non
   perche' siano componenti: un componente, in questo sistema, compare in almeno
   tre pagine o chiude un difetto misurato. */

/* Una SEZIONE che e' essa stessa una scheda. Esiste perche' in ventisei punti
   il contenuto di una sezione e' tutto dentro un solo riquadro, e annidare
   `.l-section > .c-card` aggiungerebbe un livello di markup che non porta
   niente. Dove la scheda non e' la sezione ma la TABELLA, questa classe non si
   usa: chiuderebbe il porto dentro un secondo bordo. */
.l-section--card {
  padding: var(--sp-4);
  background: var(--n-000);
  border: 1px solid var(--n-200);
  border-radius: var(--radius-card);
}

/* L'INDICE DEL RIEPILOGO: una barra sottile che si appiccica mentre si scorre.
   Era una scheda alta quanto una sezione, con undici pastiglie dentro, e costava
   180 px prima del primo dato — mentre la prima cosa sotto il titolo di un
   documento contabile dev'essere un numero.

   `top: var(--h-topbar)`: la barra in alto e' appiccicata a 0 e sta a z-index 20,
   quindi questa si ferma sotto di lei e le passa dietro. Il fondo e' quello della
   PAGINA e non il bianco di una scheda: e' sul fondo della pagina che galleggia, e
   le schede le passano sotto.

   VA A CAPO sul largo, SCORRE sullo stretto. Misurato: le undici voci del Riepilogo
   occupano circa 1450 px in una colonna di 1080 (`--w-read`), quindi le ultime tre
   finivano tagliate dal bordo — senza sfumatura, senza freccia, senza niente che
   dicesse che continuavano. Un indice che nasconde un terzo di se' e' peggio di
   nessun indice. A capo diventa due righe e si vede tutto.
   Sotto gli 860 px invece le righe sarebbero quattro o cinque, cioe' mezzo schermo
   di telefono prima del primo dato: li' torna una riga sola che scorre, che e' la
   forma che su un telefono si riconosce. Il porto non prende `tabindex` — la regola
   di `.c-table-port` vale per cio' che non e' focalizzabile, e qui dentro ci sono
   solo link, che il tabulatore raggiunge da soli portandosi dietro lo scorrimento. */
.c-index {
  position: sticky;
  top: var(--h-topbar);
  z-index: 10;
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2) var(--sp-3);
  padding-block: var(--sp-2);
  background: var(--bg-page);
  border-block-end: 1px solid var(--n-200);
}

@media (max-width: 860px) {
  .c-index {
    flex-wrap: nowrap;
    overflow-x: auto;
    overscroll-behavior-x: contain;
    scrollbar-width: thin;
  }
}

/* Una voce dell'indice e' un LINK e si veste da link del sistema (`--g-600`), non
   da bottone: undici bottoni in fila sono undici comandi, e questi non comandano
   niente — portano. La sottolineatura compare al passaggio, perche' undici
   sottolineature in fila si leggono come un paragrafo spezzato. */
.c-index__link {
  flex: none;
  font-size: var(--fs-small);
  white-space: nowrap;
  text-decoration: none;
}
.c-index__link:hover { text-decoration: underline; }

.c-steps__name { min-width: 0; }

/* Il filetto iniziale di una riga con una partita aperta. NON e' l'unico
   segnale — la riga porta anche la sua pastiglia con la parola scritta — ma
   permette di contare a occhio quante righe aperte ci sono in una colonna di
   cinquanta, che una pastiglia per riga non permette. */
.c-table tbody tr.is-unpaid    > *:first-child { box-shadow: inset 3px 0 0 var(--warn-400); }
.c-table tbody tr.is-uncollected > *:first-child { box-shadow: inset 3px 0 0 var(--warn-400); }
.c-table tbody tr.is-planned   > *:first-child { box-shadow: inset 3px 0 0 var(--n-300); }

/* La variazione: testo appoggiato alla linea di base del numero, non una
   pastiglia. Il colore NON e' l'unico portatore — la freccia e il segno lo
   dicono per primi, ed e' obbligatorio che accanto ci sia il periodo di
   confronto: «+12 % sul mese scorso». Una percentuale senza il suo termine di
   confronto non e' un dato, e' un'impressione. */
.c-tile__delta {
  font-size: var(--fs-small);
  font-weight: var(--fw-medium);
  white-space: nowrap;
}
.c-tile__delta.is-positive { color: var(--g-500); }
.c-tile__delta.is-negative { color: var(--neg-500); }
/* Variazione nulla: il grigio del testo secondario e nessuna freccia. Non e' un
   dato mancante (quello e' `nil` e non si stampa): e' «uguale al periodo
   precedente», che e' una risposta. */
.c-tile__delta.is-flat { color: var(--n-500); }
.c-tile__delta-period { font-weight: var(--fw-normal); color: var(--n-500); }

/* La tessera che porta LA cifra: respira di piu' ed e' l'unica della pagina. */
.c-tile--answer { padding: var(--sp-5); }

/* Le barrette della sparkline. L'ULTIMA e' piu' scura, perche' «adesso» e' il
   punto che si cerca: senza, undici barrette uguali non dicono da che parte si
   legge la forma. */
.c-tile__spark-bar { fill: var(--g-200); stroke: var(--g-400); stroke-width: 0.5; }
.c-tile__spark-bar--last { fill: var(--g-500); stroke: var(--g-600); }

/* Uno zero non e' un numero come gli altri: in contabilita' significa «non e'
   successo niente», e lo dice scendendo di inchiostro invece di competere con
   i numeri che qualcosa dicono. */
.c-num.is-zero { color: var(--n-500); }
