/* Stile delle pagine di test api.go.lagap (web/index.php e
   web/activate.php). Tema chiaro professionale da gestionale CALDO (giro
   caldo 24/10/2026, direzione «Gestionale caldo» scelta dal proprietario):
   superfici bianche su fondo grigio-pietra neutro, inchiostro petrol,
   accento teal profondo, ombre neutre leggere; font monospace riservato ai
   dati tecnici. La boldness è spesa in due soli punti — le porte (login e
   attivazione a tinta petrol piena col marchio su targa bianca) e i box
   tinta dei rinnovi — tutto il resto resta quieto e disciplinato.
   Transizioni brevi e discrete, disattivate con prefers-reduced-motion.

   Giro «Ibrido A — manifattura moderna sul caldo» (24/10/2026, brief del
   proprietario con la skill interface-design di Dammyjay93): la palette del
   giro caldo è confermata intatta, il moderno lo porta la manifattura —
   thead sticky sulle sei tabelle .fixed-cols (la fascia d'inchiostro diventa
   la barra persistente della vista), hover di riga uniforme su tutte le
   tabelle-elenco, cifre in tabular-nums, gradino titoli più netto (h2 a
   peso 700, la misura non si tocca), entrata del flash, e un solo momento
   animato: il reveal a cascata delle due porte (~290 ms, logo→titolo→riga→
   hint→form), mai sulle pagine operative. Il press dei bottoni era già in
   essere (translateY di .btn:active). Zero JS nuovo: tutto CSS, il vincolo
   «niente AJAX» della pagina resta; prefers-reduced-motion globale governa
   anche queste animazioni.

   La coppia è Fira self-hosted (volontà del proprietario, ottobre 2026,
   dopo le prove di Iosevka: Term sul mono giudicato pesante/stretto, Aile
   bocciata al secondo tentativo): Fira Code sul mono (la sorella con le
   legature da codice, che sui dati restano rare), Fira Sans sul sans —
   la coppia nativa Mozilla, stesse forme, stesso ritmo. SIL OFL 1.1:
   Fira Code v6.2 (github.com/tonsky/FiraCode, woff2 del pacchetto
   ufficiale), Fira Sans 4.203 (i TTF del repo googlefonts, convertiti in
   woff2 con fonttools+brotli); licenze in fonts/OFL-FiraCode.txt e
   fonts/OFL-FiraSans.txt, i woff2 in fonts/ (soli i quattro pesi usati
   qui: 400/500/600/700, ~600 kB in tutto). Nessun font di rete. */

/* Fira Code — i dati tecnici (id, badge, date, codici, chip, desk). */
@font-face {
    font-family: "Fira Code";
    src: url("fonts/FiraCode-Regular.woff2") format("woff2");
    font-weight: 400;
    font-style: normal;
    font-display: swap;
}

@font-face {
    font-family: "Fira Code";
    src: url("fonts/FiraCode-Medium.woff2") format("woff2");
    font-weight: 500;
    font-style: normal;
    font-display: swap;
}

@font-face {
    font-family: "Fira Code";
    src: url("fonts/FiraCode-SemiBold.woff2") format("woff2");
    font-weight: 600;
    font-style: normal;
    font-display: swap;
}

@font-face {
    font-family: "Fira Code";
    src: url("fonts/FiraCode-Bold.woff2") format("woff2");
    font-weight: 700;
    font-style: normal;
    font-display: swap;
}

/* Fira Sans — il corpo pagina (la sorella proporzionale, stesso gusto). */
@font-face {
    font-family: "Fira Sans";
    src: url("fonts/FiraSans-Regular.woff2") format("woff2");
    font-weight: 400;
    font-style: normal;
    font-display: swap;
}

@font-face {
    font-family: "Fira Sans";
    src: url("fonts/FiraSans-Medium.woff2") format("woff2");
    font-weight: 500;
    font-style: normal;
    font-display: swap;
}

@font-face {
    font-family: "Fira Sans";
    src: url("fonts/FiraSans-SemiBold.woff2") format("woff2");
    font-weight: 600;
    font-style: normal;
    font-display: swap;
}

@font-face {
    font-family: "Fira Sans";
    src: url("fonts/FiraSans-Bold.woff2") format("woff2");
    font-weight: 700;
    font-style: normal;
    font-display: swap;
}

:root {
    color-scheme: light;

    /* Palette del giro caldo 24/10/2026: la Minerale fredda del giro A è
       scaldata negli inchiostri e nelle tinte — fondo pietra neutro (NON
       crema: il crema alto è il
       tell delle pagine generate), inchiostro petrol, accento teal profondo.
       Gli stati semantici restano verde/ambra/rosso, ritinti verso il teal
       per armonia; il rosso --ko non si tocca (già caldo di suo, resta il
       più leggibile dei tre). */
    --bg: #e8e9e7; /* neutro, non beige: la prova del proprietario sul
        #e6e5df caldo ha reso l'idea di «beige della pagina» (24/10/2026);
        il calore del tema resta nell'inchiostro e nelle tinte d'accento,
        l'appoggio è pietra neutra */
    --panel: #ffffff;
    --panel-soft: #f1f1eb;
    --field-bg: #fdfdfa;
    --ink: #232e2c;
    --ink-dim: #62706a;
    --line: #d1d3ca;
    --line-soft: #e7e8e1;
    /* Una tacca più piena di --line: la frontiera che deve restare leggibile
       anche a riposo sui fondi morbidi (il box di ricerca, 22/10/2026). */
    --line-strong: #9ba49b;

    --accent: #17615e;
    --accent-strong: #104a47;
    --accent-ink: #ffffff;
    --accent-soft: rgba(23, 97, 94, 0.1);

    /* L'ambra bruciata dei momenti caldi (la POST, la banner .is-other,
       l'attesa dello stepper): una tinta sola, nominata; --post vi si
       aggancia e chi legge il chip POST legge la stessa tinta. */
    --accent-warm: #a86a24;

    --ok: #2e7352;
    --ok-bg: rgba(46, 115, 82, 0.08);
    --ko: #b3372f;
    --ko-bg: rgba(179, 55, 47, 0.07);

    /* I quattro colori di metodo restano distinti tra loro (la resa delle
       console API): dal giro caldo POST è l'ambra nominata del tema; il
       blu del GET NON è più anche l'accento (l'accento è teal), quindi
       resta tinta propria dei soli badge. */
    --post: var(--accent-warm);
    --get: #1c5e8a;
    --patch: #96527e;
    --put: #2e7459;

    /* Radius plurale: il valore unico su ogni elemento era un tell da
       SaaS-card kit. Pannello ≠ chip ≠ campo ≠ tabella. */
    --radius-panel: 8px;
    --radius-control: 4px;
    --radius-chip: 999px;
    --radius-table: 3px;

    /* Ombre: due soli livelli, tinta petrol sull'inchiostro del tema
       (ritinte col giro caldo, invariate di livello).
       shadow-1 = superficie appoggiata (quasi tutte), shadow-2 = solo
       elementi flottanti (banner, dropdown). Tutto il resto è bordi. */
    --shadow-1: 0 1px 2px rgba(35, 46, 44, 0.07);
    --shadow-2: 0 2px 8px rgba(35, 46, 44, 0.14);

    --sans: "Fira Sans", system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", sans-serif;
    --mono: "Fira Code", ui-monospace, "SF Mono", "Cascadia Mono", "JetBrains Mono", "DejaVu Sans Mono", monospace;
}

* {
    box-sizing: border-box;
}

body {
    margin: 0;
    min-height: 100vh;
    min-height: 100dvh;
    color: var(--ink);
    font-family: var(--sans);
    font-size: 0.9375rem;
    line-height: 1.5;
    background: var(--bg);
}

::selection {
    background: rgba(23, 97, 94, 0.2);
}

/* ── Layout a colonna unica: console sopra, area comandi sotto ── */

/* La console è stata spostata in alto, come barra orizzontale: la
   larghezza sotto è tutta dello stage, così la tabella dei soci
   respira. */
.layout {
    display: flex;
    flex-direction: column;
    gap: 1.75rem;
    max-width: 62rem;
    margin: 0 auto;
    padding: 1.75rem 1.75rem 4.5rem;
}

/* ── Console (barra in alto) ── */

/* La console è due righe indipendenti (scelta del proprietario, ottobre
   2026): sopra l'identità con l'area personale a destra, sotto la
   navigazione con attivazione e API a destra. Dal giro B del 22/10 è
   staccata dallo stage come card senza ombra (superficie appoggiata):
   la cornice le separa, non più la riga di fondo. I pannelli dello
   stage portano la shadow-1: console fissa e contenuto flottante si
   distinguono per profondità, non per tinta. Nessuna modifica alla
   struttura: la card veste il .desk esistente. */
.desk {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    padding: 1.05rem 1.4rem;
    background: var(--panel);
    border: 1px solid var(--line);
    border-radius: var(--radius-panel);
}

/* Una riga della console: flex item in wrap, allineati alla base (le
   pill possono andare a capo se la riga stringa). */
.desk-line {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 0.5rem 1.4rem;
}

/* Titolo di pagina: sans-serif normale, senza identità da terminale.
   Scala 22/10/2026 (giro anti-slop): +tacca e mezzo sul corpo pagina,
   tracking negativo — la gerarchia si legge a colpo d'occhio, il titolo
   non è più un paragrafo grasso. Mezza tacca ancora dal giro caldo
   24/10 (1,45 → 1,55rem): la gerarchia si allarga senza rompere la
   densità del gestionale. */
.desk h1 {
    margin: 0;
    font-size: 1.55rem;
    font-weight: 700;
    letter-spacing: -0.015em;
}

/* Area personale dell'utenza collegata (il nome preceduto dalla dicitura
   «AREA PERSONALE @»): più in risalto senza pill (la pill a tinta
   collide con i bottoni della navigazione), in accento petrol grasso e
   maiuscolo (l'anagrafica in DB è già maiuscola per normalizzazione: la
   trasformazione copre il fallback sulla username); niente cornice,
   nessun rischio di confonderlo con un bottone. Il margin-left auto lo
   spinge all'estremo bordo destro della riga, con tutto lo spazio vuoto
   della riga per sé; troncato con ellissi se lungo, con una max-width
   più generosa per la dicitura. Allineato in ALTO (align-self:flex-start): la
   dicitura siede sulla cima della riga accanto al marchio (la riga è
   align-items:baseline; l'h1 è visually-hidden, nessun testo di riferimento). */
.desk-user {
    margin-left: auto;
    align-self: flex-start;
    color: var(--accent-strong);
    font-weight: 700;
    font-size: 0.875rem;
    text-transform: uppercase;
    max-width: 24rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Navigazione tra le pagine della desk (la riga personale: Home, Utenza,
   Profilo, Rinnovo — o «Accesso» per l'anonimo; e la riga amministrativa
   sotto):
   pill come lo stato API, con la pagina corrente marcata a tinta. */
.page-nav {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    margin: 0;
}

.page-nav a,
.page-nav .is-current {
    padding: 0.25rem 0.7rem;
    border: 1px solid var(--line);
    border-radius: var(--radius-chip);
    font-family: var(--mono);
    font-size: 0.75rem;
    letter-spacing: 0.04em;
    text-transform: uppercase;
}

.page-nav a {
    color: var(--ink-dim);
    text-decoration: none;
    transition: color 0.15s ease, border-color 0.15s ease;
}

.page-nav a:hover {
    color: var(--accent-strong);
    border-color: var(--accent);
}

.page-nav .is-current {
    color: var(--accent-strong);
    background: var(--accent-soft);
    border-color: var(--accent);
}

/* La riga amministrativa della desk (renderDesk): le funzioni di gestione,
   sotto la riga personale, separate dal bordo superiore, senza dicitura.
   Si rende solo
   quando ha almeno una voce (la lista è filtrata per ruolo): il separatore
   non è mai orfano. Il padding-top apre lo spazio sopra la linea. */
.desk-backoffice {
    border-top: 1px solid var(--line);
    padding-top: 0.75rem;
}

/* La riga del bottone della scrittura («NUOVO CORSO»/«NUOVA EDIZIONE»)
   sopra la testata di ogni tabella di formazione/index.php (volontà del
   proprietario, ottobre 2026): il link contestuale alla pagina di
   scrittura formazione/admin.php, allineato a destra sotto il scritto e
   sopra la tabella. Il link veste la .btn condivisa dei form (l'accento
   petrol, testo bianco). La riga si rende solo con il ruolo in
   sessione (la guardia è nella pagina), mai un contenitore vuoto. */
.manage-btn-row {
    display: flex;
    justify-content: flex-end;
    margin: 0.75rem 0 0.5rem;
}

/* La .btn della scrittura è alla dimensione delle pill della
   navigazione (volontà del proprietario, ottobre 2026: la .btn piena
   dei form era troppo grande): la geometria è quella dei
   .page-nav a — il padding, il mono, il corpo 0.75rem e la pill a
   tutta altezza — mentre il vestito resta quello della .btn (l'accento
   petrol, testo bianco, e il grassetto del bottone). */
.manage-btn-row .btn {
    padding: 0.25rem 0.7rem;
    border-radius: var(--radius-chip);
    font-family: var(--mono);
    font-size: 0.75rem;
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
}

/* Blocco API della desk (base, stato, legenda degli endpoint): riservato
   agli admin in renderDesk. Il pill «API» (la stessa resa delle voci di
   navigazione) è l'etichetta della casella di spunta nuda che lo apre e lo
   chiude: CSS puro, nessun JavaScript. Sta all'estremo destro per il
   margin-left auto della sua regola (.desk-api-pill); il box si rende sotto
   le due righe della console, per conto suo: flex-basis 100% gli dà una riga
   tutta sua. */
.desk-api-toggle {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    margin: -1px;
}

/* La pill «API» della desk: il toggle che la apre è position:absolute (non
   occupa spazio nel flex), quindi la pill è il primo item in-flusso del gruppo
   admin. Il margin-left auto le assegna tutto lo spazio vuoto residuo della
   riga e la spinge all'estremo destro (l'economia del .desk-right pre-refactor,
   che ora è caduto con il pill «Attivazione»); il box API (flex-basis 100%) va
   comunque a capo sotto. Il selettore :checked ~ .desk-api-box e il
   :focus-visible + .desk-api-pill restano validi: toggle e pill sono ancora
   figli consecutivi di .desk-navline, nessun wrapper in mezzo. La classe è
   condivisa dalla pill «Esci» (il link logout): con la label API «Esci» le
   resta accanto col padding della pill (l'ancoraggio è della SOLA label,
   mai anche «Esci»: il doppio auto crea lo spazio tra le due che non si
   vuole); senza label (l'utente non admin) àncora il link, che è la sola
   pill della riga — vedi la regola sotto. */
.desk-api-pill {
    padding: 0.25rem 0.7rem;
    border: 1px solid var(--line);
    border-radius: var(--radius-chip);
    font-family: var(--mono);
    font-size: 0.75rem;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--ink-dim);
    cursor: pointer;
    transition: color 0.15s ease, border-color 0.15s ease;
}

/* L'ancoraggio a destra: la SOLA prima pill del gruppo (mai la classe nuda:
   con «Esci» in coda il margin-left auto sulla classe azzera lo spazio tra le
   due e lascia il vuoto a destra, e il destro non ce l'ha nessuna). Il
   selettore è sugli ELEMENTI (label = API, a = Esci): l'input della casella
   nuda è il primo figlio ma è position:absolute e mai una pill (mai prima
   element-wise). Il selettore non è :first-of-type: l'input nudo precede la
   label e sarebbe sempre il <label> primo-of-type, quindi la label API non
   passerebbe mai il selettore e il gruppo non ancorerebbe (né con la sola
   API né con API + Esci). Le due regole sono disgiunte sui rami:
   la label àncora quando è resa (il gruppo admin, con o senza «Esci» in
   coda); l'«Esci» del solo non-admin (label mai resa) àncora col selettore
   sotto. L'«Esci» admin NON àncora qui: si attacca a «API» (la label le è
   sorella adjacent: nessun gap HTML tra le due, l'unico margine è il
   padding della pill), e il gruppo è ancorato a destra dalla sola label. */
label.desk-api-pill {
    margin-left: auto;
}

/* L'«Esci» del non-admin: senza label API (la sessione non è admin, la desk
   non la rende), «Esci» è la SOLA pill del gruppo e àncora il suo destro.
   Il selettore esclude il ramo admin (label API sorella precedente): lì
   l'auto sulla label àncora il gruppo, «Esci» vi si attacca col padding
   della pill; il doppio auto sulle due crearebbe lo spazio tra le due che
   la nota sopra vieta. L'input nudo è position:absolute, non è un
   <label>, quindi il selettore adjacent non lo teme. */
.desk-navline > a.desk-api-pill:not(label.desk-api-pill + a) {
    margin-left: auto;
}

/* Il link «Esci» condivide la resa della pill API (la classe); il link non
   eredita l'underline globale dei link di stage (nessun rule globale sui
   link: .page-nav a dichiara text-decoration: none, la pill link lo dichiara
   qui). */
a.desk-api-pill {
    text-decoration: none;
}

.desk-api-pill:hover {
    color: var(--accent-strong);
    border-color: var(--accent);
}

/* Il marchio nella testata sostituisce l'h1 di testo: scala all'altezza della
   riga. Altezza fissa in rem (scala col font root), larghezza proporzionale
   (aspect ratio 796×318 ≈ 2.5:1, dato dagli attributi nativi dell'<img>: niente
   layout-shift). 3.5rem (richiesta del proprietario: ingrandito). align-self:center: la riga
   è align-items:baseline, che farebbe
   sedere il logo sull'asi del testo; qui si allinea al centro della riga. */
.desk-logo {
    height: 3.5rem;
    width: auto;
    display: block;
    align-self: center;
    padding-bottom: 0.5rem;    /* aria: lo spazio tra il logo e la nav sotto (il padding è dentro l'elemento: la cornice del logo, se c'è, non lo taglia) */
}

/* Il link-marchio «torna a casa» (solo con la sessione): eredità il ruolo del
   vecchio h1 desk-home. Nessun underline né colore proprio (il logo non è testo
   da marcare), ma l'anello di focus resta (tastiera). */
.desk-logo-link {
    color: inherit;
    text-decoration: none;
}
.desk-logo-link:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}

/* Heading presente solo per la tecnologia assistiva (l'h1 «Lagap» della testata,
   che il marchio sostituisce in vista): non display:none, che lo nasconderebbe
   anche agli screen reader. La tecnica clip/1px lo rende accessibile ma invisuale. */
.visually-hidden {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    border: 0;
    clip: rect(0 0 0 0);
    overflow: hidden;
    white-space: nowrap;
}

/* Anello di focus sul pill quando la casella (nuda) è in focus. */
.desk-api-toggle:focus-visible + .desk-api-pill {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}

.desk-api-box {
    display: none;
    flex-basis: 100%;
    flex-direction: column;
    margin-top: 0.75rem;
}

.desk-api-toggle:checked ~ .desk-api-box {
    display: flex;
}

.desk-api-box .endpoints-title {
    margin-top: 0.5rem;
}

/* Info API in fila (etichetta, valore, etichetta, pill): nella barra in
   alto non c'è una colonna che le impila. */
.api-info {
    display: flex;
    flex-wrap: wrap;
    gap: 0.3rem 0.9rem;
    align-items: baseline;
    margin: 0;
}

.api-info dt {
    color: var(--ink-dim);
    font-family: var(--mono);
    font-size: 0.6875rem;
    letter-spacing: 0.1em;
    text-transform: uppercase;
}

.api-info dd {
    margin: 0;
    font-size: 0.8125rem;
    min-width: 0;
    overflow-wrap: anywhere;
}

.api-info dd code {
    font-family: var(--mono);
    font-size: 0.8125rem;
    color: var(--accent-strong);
}

/* Stato come "pill" con led pulsante: il battito dice che è vivo. */
.api-status {
    display: inline-flex;
    align-items: center;
    gap: 0.45rem;
    padding: 0.2rem 0.7rem;
    border: 1px solid var(--line);
    border-radius: var(--radius-chip);
    font-family: var(--mono);
    font-size: 0.75rem;
    letter-spacing: 0.04em;
}

.api-status .dot {
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: var(--ink-dim);
    flex-shrink: 0;
}

.api-status.is-ok {
    color: var(--ok);
    background: var(--ok-bg);
    border-color: color-mix(in srgb, var(--ok) 35%, transparent);
}

.api-status.is-ok .dot {
    background: var(--ok);
    animation: dot-pulse 2.6s ease-out infinite;
}

.api-status.is-ko {
    color: var(--ko);
    background: var(--ko-bg);
    border-color: color-mix(in srgb, var(--ko) 35%, transparent);
}

.api-status.is-ko .dot {
    background: var(--ko);
    animation: dot-pulse 2.6s ease-out infinite;
}

/* Anello di pulsazione del pallino: la tinta è il currentColor dello
   stato (il color di .is-ok / .is-ko), così un solo keyframe copre
   entrambi. */
@keyframes dot-pulse {
    0%   { box-shadow: 0 0 0 0 currentColor; }
    70%  { box-shadow: 0 0 0 6px transparent; }
    100% { box-shadow: 0 0 0 0 transparent; }
}

/* Legenda endpoint: POST e GET sono le parole del soggetto, non decorazione.
   Colori di metodo distinti, come nelle console API. Le stesse pill colorate
   sono riusate nel pannello "Chiamata API" (.api-call). Nella barra in alto
   la lista è inline (flex in wrap), non più colonna. */
.endpoints-title {
    margin: 0;
    font-family: var(--mono);
    font-size: 0.75rem;
    font-weight: 700;
    letter-spacing: 0.2em;
    text-transform: uppercase;
    color: var(--ink-dim);
}

/* Elenco puntato: una riga per endpoint, con il marker nativo del ul. Il
   badge sotto il puntato non è più flex item, quindi vuole la resa
   inline-block. */
.endpoints {
    list-style: disc;
    margin: 0;
    padding-left: 1.3rem;
}

.endpoints li {
    margin: 0.3rem 0;
}

.endpoints .method {
    display: inline-block;
    vertical-align: middle;
}

.endpoints .method,
.api-call .method {
    font-family: var(--mono);
    font-size: 0.6875rem;
    font-weight: 700;
    letter-spacing: 0.06em;
    padding: 0.15rem 0.5rem;
    border-radius: var(--radius-control);
    flex-shrink: 0;
}

/* I quattro badge derivano fondo e bordo dalla propria tinta di metodo via
   color-mix (giro caldo 24/10/2026: prima ogni badge portava il tripletto
   rgba letterale della tinta, che ogni cambio di palette costringeva a
   ritintare a mano nei quattro punti; ora i quattro rgba meccanici (0.08/0.1
   fondo, 0.25/0.3 bordo) sono preservati come percentuali del color-mix e
   la tinta segue il token da una sola sede). */
.endpoints .method-post,
.api-call .method-post {
    color: var(--post);
    background: color-mix(in srgb, var(--post) 10%, transparent);
    border: 1px solid color-mix(in srgb, var(--post) 30%, transparent);
}

.endpoints .method-get,
.api-call .method-get {
    color: var(--get);
    background: color-mix(in srgb, var(--get) 8%, transparent);
    border: 1px solid color-mix(in srgb, var(--get) 25%, transparent);
}

/* Badge della PATCH: la terza tinta dei metodi (le pagine anagrafica/member.php e
   anagrafica/user.php la esibiscono), sulla stessa resa dei badge GET/POST. */
.endpoints .method-patch,
.api-call .method-patch {
    color: var(--patch);
    background: color-mix(in srgb, var(--patch) 8%, transparent);
    border: 1px solid color-mix(in srgb, var(--patch) 30%, transparent);
}

/* Badge della PUT: la quarta tinta (le due password di anagrafica/user.php), sulla
   stessa resa dei badge GET/POST/PATCH. */
.endpoints .method-put,
.api-call .method-put {
    color: var(--put);
    background: color-mix(in srgb, var(--put) 8%, transparent);
    border: 1px solid color-mix(in srgb, var(--put) 30%, transparent);
}

.endpoints .path {
    font-family: var(--mono);
    font-size: 0.8125rem;
    color: var(--ink);
    min-width: 0;
    overflow-wrap: anywhere;
}

.endpoints .scope {
    margin-left: 0.4rem;
    font-size: 0.75rem;
    color: var(--ink-dim);
}

/* ── Area comandi ── */

.stage {
    min-width: 0;
}

.flash {
    margin: 0 0 1.25rem;
    padding: 0.75rem 1rem;
    background: var(--panel);
    border: 1px solid var(--line);
    border-left-width: 3px;
    border-radius: var(--radius-panel);
    font-size: 0.9375rem;
    /* L'esito entra con un passo (giro Ibrido A 24/10/2026): il flash è un
       momento che merita il motion — segnala una conseguenza appena
       avvenuta. 150 ms, il tempo del tema; il kill globale di
       prefers-reduced-motion lo spegne e la resa resta ferma. */
    animation: flash-in 0.15s ease;
}

.flash::before {
    content: "✓";
    margin-right: 0.5rem;
    font-weight: 700;
}

.flash-ok {
    background: var(--ok-bg);
    border-color: color-mix(in srgb, var(--ok) 30%, transparent);
    border-left-color: var(--ok);
    color: var(--ok);
}

.flash-errore {
    background: var(--ko-bg);
    border-color: color-mix(in srgb, var(--ko) 30%, transparent);
    border-left-color: var(--ko);
    color: var(--ko);
}

.flash-errore::before {
    content: "✕";
}

@keyframes flash-in {
    from {
        opacity: 0;
        transform: translateY(-4px);
    }
}

.panel {
    background: var(--panel);
    border: 1px solid var(--line);
    border-radius: var(--radius-panel);
    padding: 1.4rem 1.5rem 1.5rem;
    margin-bottom: 1.25rem;
    box-shadow: var(--shadow-1);
}

/* Il testo della bacheca (home/index.php): i blocchi markdown sono figli
   diretti del pannello, che non ha più nessun wrapper. I margini verticali
   collabiano col padding del pannello (non c'è border in mezzo: la regola
   generale del flow): l'h1 primo portava i suoi ~0.67em sopra il padding,
   l'ultimo blocco sotto. Si azzera la sola estremità d'attacco del flusso,
   non l'interblocco: i margini tra i blocchi markdown restano integrali,
   come nelle pagine che oggi non hanno h1/markdown diretti. L'override
   .panel p / .panel h2 (0,2,0) vince su questo (0,1,1): nessun ramo che
   usava le due regole cambia aspetto. */
.panel > :first-child {
    margin-top: 0;
}

.panel > :last-child {
    margin-bottom: 0;
}

/* Il testo giustificato vale per i soli blocchi di flusso (i paragrafi e le
   righe di lista); i titoli restano a sinistra, il codice (pre) no. */
.panel > p,
.panel > ul,
.panel > ol,
.panel > blockquote {
    text-align: justify;
}

/* Il respiro all'approdo di un àncora: i pannelli puntati da un hash (oggi
   solo #crediti-formativi, l'approdo del link 👤 di formazione/report.php)
   atterrerebbero col bordo incollato al vertice della viewport; lo
   scroll-margin lascia un rem d'aria sopra il titolo. Vale per qualunque
   .panel con id: la regola è del contenitore ancorabile, non del singolo
   pannello. */
.panel[id] {
    scroll-margin-top: 1rem;
}

.panel h2 {
    margin: 0 0 0.7rem;
    font-family: var(--sans);
    font-size: 1.125rem;
    /* Peso 700 dal giro Ibrido A 24/10/2026: il gradino titoli/corpo si
       guadagna in peso, non in misura (la scala 22/10 resta; la Fira Sans
       700 è tra i quattro pesi self-hosted). Vale a cascata anche sulle
       banner person-title/renew-title, che ereditano da qui. */
    font-weight: 700;
    letter-spacing: -0.01em;
    color: var(--ink);
}

/* Il sottotitolo di un blocco dentro il pannello (i rami della pagina del
   rinnovo: «Avvia il rinnovo», «Non autorizzato», «Esegui il bonifico»): la
   scala di .panel h2, un grado più leggera (la tinta ink-dim di
   .pay-cta-title, che da sottotitolo d'epoca resta coperta da questa regola:
   nessuna divergenza). */
.panel h3 {
    margin: 1.2rem 0 0.5rem;
    font-family: var(--sans);
    font-size: 0.9375rem;
    font-weight: 600;
    letter-spacing: 0;
    color: var(--ink-dim);
}

/* Il corpo dei titoli che portano un soggetto (il nome della persona,
   l'intestazione di un box di elenco, o il ciclo del rinnovo): un punto
   sopra .panel h2 (1,125rem → 1,25rem, scala 22/10/2026). Dichiarato una
   sola volta, condiviso da .person-title (anagrafica/user.php,
   anagrafica/member.php), .centered-title (anagrafica/index.php,
   formazione/index.php) e .renew-title (rinnovi/index.php): così il corpo
   resta uniforme tra le pagine e si cambia in un punto solo. */
.panel h2.person-title,
.panel h2.centered-title,
.panel h2.renew-title {
    font-size: 1.25rem;
}

/* Il titolo del pannello con il nome della persona (anagrafica/user.php e anagrafica/member.php):
   allineato a sinistra (il nome esce maiuscolo dai dati: l'anagrafica la
   dà maiuscola il trigger di normalize di auth, non la CSS). */
.panel h2.person-title {
    text-align: left;
}

/* La riga del titolo nelle due viste del dettaglio (anagrafica/user.php e
   anagrafica/member.php): una sola geometria di banner (flex: il nome a sinistra,
   l'incrociato spinto al bordo destro, lo spazio tra i due è il gap, le
   biancherie di testo tra due flex item sono ignorate; padding e angoli
   fanno la riga unica del box) e due tinte che dicono chi si sta
   guardando: ambra (la stessa tinta calda del chip POST, distinta
   dall'accento petrol dell'operatore) per il soggetto diverso, petrol
   d'accento forte (la tinta della voce «AREA PERSONALE» della desk) per il
   profilo autenticato. Il testo è bianco su entrambe. */
.panel h2.person-title.is-other,
.panel h2.person-title.is-self,
.panel h2.renew-title {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 1rem;
    padding: 0.6rem 1rem;
    border-radius: var(--radius-control);
}

.panel h2.person-title.is-other {
    background: var(--post);
    color: var(--accent-ink);
}

/* La banner della vista rinnovo (rinnovi/index.php, richiesta del
   proprietario 22/10/2026): la riga «RINNOVO <anno>» prende la stessa
   evidenza dell'accento (blu prima del giro caldo 24/10, petrol dopo) di
   Utenza/Profilo. Il soggetto non è una persona ma il
   ciclo, e la copy è maiuscola di scrittura (non di transform: come il
   nome in person-title, che maiuscolo lo esce dai dati). */
.panel h2.person-title.is-self,
.panel h2.renew-title {
    background: var(--accent-strong);
    color: var(--accent-ink);
}

/* L'incrociato tra le pagine gemelle (anagrafica/user.php «PROFILO», anagrafica/member.php
   «UTENZA», le due voci della navigazione): porta all'altra pagina sullo
   stesso socio, senza tornare in lista. Il link non fa rubrica al titolo:
   taglia minore, peso normale, maiuscolo e grassetto del .panel h2 tolti
   di mezzo (la voce la si scrive già maiuscola), niente sottolineatura
   (la convenzione delle `a` senza decorazione, come le voci di
   navigazione e le icone dei soci), pill sottile nel colore d'accento;
   dentro una banner (ambra o petrol che sia) resta leggibile come link su
   fondo translucido. */
.person-switch {
    font-family: var(--sans);
    font-size: 0.8125rem;
    font-weight: 400;
    letter-spacing: normal;
    text-transform: none;
    text-decoration: none;
    color: var(--accent-strong);
    border: 1px solid var(--line);
    border-radius: var(--radius-chip);
    padding: 0.15rem 0.6rem;
    white-space: nowrap;
}

.panel h2.person-title.is-other .person-switch,
.panel h2.person-title.is-self .person-switch {
    color: var(--accent-ink);
    border-color: rgba(255, 255, 255, 0.55);
    background: rgba(0, 0, 0, 0.14);
}

/* Il titolo centrato del box di elenco o di riepilogo (anagrafica/index.php
   «Anagrafica», formazione/index.php «Formazione», formazione/report.php
   «Piano Nazionale Formazione», rinnovi/report.php «Situazione Rinnovi»):
   stesso corpo di .person-title, centrato. */
.panel h2.centered-title {
    text-align: center;
}

.panel p {
    margin: 0 0 1rem;
}

.hint {
    color: var(--ink-dim);
    font-size: 0.875rem;
}

.hint code {
    font-family: var(--mono);
    font-size: 0.8125rem;
    color: var(--accent-strong);
    background: var(--panel-soft);
    border: 1px solid var(--line);
    padding: 0.1rem 0.4rem;
    border-radius: var(--radius-control);
}

/* Testo dello storico delle note (anagrafica/member.php): il testo libero di
   note_block rende con i suoi a capo (white-space: pre-line) e non
   sfonda la cella (overflow-wrap: anywhere), come i dd della detail-grid
   dei soci. */
.note-text {
    white-space: pre-line;
    overflow-wrap: anywhere;
}

/* Briciola sopra le tabelle CPD: sempre in maiuscolo (il titolo del corso
   viene dall'API con la sua resa, qui si mostra uniformato). */
.crumbs {
    text-transform: uppercase;
}

/* Le voci della briciola hanno tutte la stessa resa (volontà del
   proprietario, ottobre 2026): la voce corrente è il testo, le navigabili
   sono i link. Stile moderno senza pill né sottolineatura in hover (il
   proprietario, 15/10): il link si distingue a riposo in accent e
   dell'accent-soft, all'hover scurisce e si lega al fondo — la resa è
   tutta qui in CSS, il separatore → resta il carattere del testo reso
   dalla pagina. */
.crumbs a {
    color: var(--accent);
    text-decoration: none;
    background: var(--accent-soft);
    border-radius: var(--radius-control);
    padding: 0.15rem 0.4rem;
    margin: 0 -0.4rem;
    transition: color 0.15s ease, background-color 0.15s ease;
}

.crumbs a:hover {
    color: var(--accent-strong);
    background: var(--line-soft);
}

/* ── Form ── */

.field {
    margin-bottom: 1rem;
}

.field label {
    display: block;
    margin-bottom: 0.4rem;
    font-family: var(--mono);
    font-size: 0.6875rem;
    font-weight: 500;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--ink-dim);
}

/* Il textarea della PATCH (anagrafica/member.php) condivide la resa degli input: la
   stessa larghezza (100%) e la stessa tinta del campo telefono. Le select
   degli enum (Tipo/DLVR delle form CPD, ottobre 2026) condividono input e
   textarea: prima restavano fuori dal blocco e il browser le renderizzava
   alla sua dimensione minima (il contenuto «molto piccolo» notato dal
   proprietario); idem i bottoni .btn dei form: se un .btn vive in un .field,
   la sua resa è quella del selettore più specifico (le due regole .btn,
   che non sono in .field). */
.field input,
.field select,
.field textarea {
    width: 100%;
    padding: 0.6rem 0.8rem;
    background: var(--field-bg);
    border: 1px solid var(--line);
    border-radius: var(--radius-control);
    color: var(--ink);
    font-family: var(--sans);
    font-size: 0.9375rem;
    transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

.field input::placeholder {
    color: var(--ink-dim);
}

.field input:focus,
.field select:focus,
.field textarea:focus {
    outline: none;
    border-color: var(--accent);
    box-shadow: 0 0 0 3px var(--accent-soft);
}

/* Campo password con pulsante show/hide: il wrap serve solo al bottonino. */
.input-wrap {
    position: relative;
}

.input-wrap input {
    padding-right: 6rem;
}

.toggle-password {
    position: absolute;
    top: 50%;
    right: 0.45rem;
    transform: translateY(-50%);
    padding: 0.2rem 0.5rem;
    background: transparent;
    border: 1px solid transparent;
    border-radius: var(--radius-control);
    color: var(--ink-dim);
    font-family: var(--mono);
    font-size: 0.6875rem;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    cursor: pointer;
}

.toggle-password:hover:not(:disabled) {
    color: var(--accent-strong);
    background: var(--panel-soft);
    border-color: var(--line);
}

.toggle-password:disabled {
    opacity: 0.4;
    cursor: not-allowed;
}

.btn {
    display: inline-block;
    /* Il testo si centra nel box della .btn: per il <button> è già il
       default dell'UA, per il <a class="btn"> (Attiva nel login, i bottoni
       link altrove) è la resa che lo pareggia quando un flex lo allarga
       oltre il contenuto (giro B: .auth-gate distende la riga). */
    text-align: center;
    padding: 0.65rem 1.35rem;
    background: var(--accent);
    border: none;
    border-radius: var(--radius-control);
    color: var(--accent-ink);
    font-family: var(--sans);
    font-size: 0.9375rem;
    font-weight: 600;
    letter-spacing: 0.01em;
    /* Il maiuscolo è la resa di ogni bottone del progetto (la richiesta del
       proprietario, ottobre 2026): la copy dei sorgenti resta come è (le
       label minuscole delle pagine e i «oggi»/«svuota» comodi), la
       trasformazione è qui, l'economia dei chip e delle .st in tabella. */
    text-transform: uppercase;
    cursor: pointer;
    transition: background 0.15s ease, transform 0.1s ease;
}

.btn:hover:not(:disabled) {
    background: var(--accent-strong);
}

.btn:active:not(:disabled) {
    transform: translateY(1px);
}

.btn:disabled {
    opacity: 0.45;
    cursor: not-allowed;
}

/* Un link vestito da bottone (il «NUOVO CORSO»/«NUOVA EDIZIONE» di
   formazione/index.php): la cornice è della .btn, l'underline del link no. */
a.btn {
    text-decoration: none;
}

/* Bottone della rimozione (la DELETE d'iscrizione dal pannello «Modifica
   iscrizione», ottobre 2026): la distruzione si distingue a vista — il
   rosso del --ko della palette su fondo pieno, la stessa forma della
   .btn condivisa. */
.btn-danger {
    background: var(--ko);
}

.btn-danger:hover:not(:disabled) {
    background: #932d26;
}

.inline-form {
    display: inline-block;
    margin: 0.5rem 0.6rem 0 0;
}

/* La riga dei bottoni gemelli del pannello «Modifica partecipante»
   (volontà del proprietario, ottobre 2026): le due form — la PATCH e la
   DELETE della stessa riga, i due metodi non stanno in un form solo —
   stanno fianco a fianco sulla stessa riga a flex, lo spazio tra i due
   è il gap, e l'affioramento a capo è solo sul piccolo schermo
   (flex-wrap). */
.btn-row {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: 0.6rem;
    margin-top: 0.5rem;
}

/* La linea dei bottoni link (il gemello «ANNULLA» della home accanto al
   submit, e il «MODIFICA» che in una riga ci sta in futuro): il <a> non è
   replaced ed eredita il line-height 1.5 del body, quindi il suo box esce
   più alto del <button> gemello (l'UA ferma la linea del button al solo
   testo). La stessa riduzione del link «ATTIVA» del login (sopra), ma qui
   il selettore è la classe, non l'href: nessuna dipendenza dal path della
   destinazione. L'eccedenza resta nel padding interno, a vista i due sono
   identici. */
.btn-link {
    line-height: 1.15;
}

/* Il link «ATTIVA» accanto al submit «ACCEDI» nel login. Il button è
   replaced e la sua linea non sale oltre il testo (il default dell'UA,
   non l'1.5 del body); il link la eredita e il suo box cresce di ~0.5em.
   Si ferma la linea del solo link (la scelta del proprietario, ottobre
   2026): il box esce alto 4.725em contro i ~2em del button, l'eccedenza
   resta nel padding interno e a vista i due sono identici. Il selettore
   è la sola riga che ha un <button> gemello, nessun altro link-bottone
   del progetto è toccato. */
.btn-row a[href$="activate.php"] {
    line-height: 1.15;
}

.btn-row form {
    margin: 0;
}

/* ── Auth-gate — la porta di login e attivazione (giro B, 22/10/2026;
   tinta piena petrol dal giro caldo 24/10/2026) ── */

/* I pannelli di index.php e activate.php (classe .auth-gate nel markup,
   la sola aggiunta del giro): il login e l'attivazione diventano una
   porta e non un pannello gestionale a tutta colonna — più stretti,
   centrati nello stage, respiro interno maggiore. È resa, non flusso:
   gli action POST, i campi e gli hook di app.js (toggle-password) sono
   gli stessi delle sorelle.
   Dal giro caldo 24/10/2026 la porta è la boldness del tema: tinta
   d'accento forte (petrol) a tutto campo, testo bianco, submit e link
   «Attiva» rovesciati (targa bianca, testo petrol). Le pagine sorelle
   restano chiare: il contrasto è della sola porta, non del sito. */
.auth-gate {
    max-width: 34rem;
    margin-left: auto;
    margin-right: auto;
    padding: 1.75rem 2rem 2rem;
    background: var(--accent-strong);
    border-color: var(--accent-strong);
    color: var(--accent-ink);
    /* Flottante: la porta stacca dal fondo pietra con l'ombra sostenuta
       (il chiaro-scuro della tinta fa il resto). */
    box-shadow: var(--shadow-2);
}

/* Il titolo della porta (h2 «Accesso»/«Richiedi l'OTP»/«Imposta la
   password»): la resa comune di .panel h2 è ink sul bianco del pannello,
   qui il testo sale sul bianco d'inchiostro del tema. */
.auth-gate h2 {
    color: var(--accent-ink);
}

/* La riga mono sotto il titolo: cosa fa davvero la pagina, scritta nel
   linguaggio dei dati del tool (metodo, path, vincolo). Non è
   un'etichetta decorativa: è l'ancoraggio del pannello, e la sua
   presenza è il carattere della porta. Sul fondo petrol il dim di tema
   non avrebbe contrasto: bianca velata (78%, ~7:1 sulla tinta). */
.auth-gate .gate-line {
    margin: -0.3rem 0 1.1rem;
    font-family: var(--mono);
    font-size: 0.75rem;
    color: rgba(255, 255, 255, 0.78);
}

/* L'hint dentro la porta (le istruzioni del flusso): bianca velata come
   la gate-line; il <strong> (la parola «email» del passo 1) prende il
   bianco pieno per restare la voce più forte del paragrafo. */
.auth-gate .hint {
    color: rgba(255, 255, 255, 0.85);
}

.auth-gate .hint strong {
    color: var(--accent-ink);
}

/* Le label dei campi nella porta: il mono maiuscolo dim di tema non si
   legge sul petrol; bianca velata come la gate-line. Gli input restano
   targa bianca (il --field-bg del tema) con testo ink: la postazione di
   digitazione si stacca da sola dal fondo scuro, nessuna deroga. */
.auth-gate .field label {
    color: rgba(255, 255, 255, 0.75);
}

/* L'anello di focus dei campi nella porta: l'accent-soft velato non si
   vede sul petrol, l'anello monta bianco; il bordo segue (la tenuta
   dell'input a riposo resta la line di tema, già leggibile sul fondo). */
.auth-gate .field input:focus {
    border-color: var(--accent-ink);
    box-shadow: 0 0 0 3px rgba(255, 255, 255, 0.25);
}

/* I bottoni della porta rovesciati: targa bianca, testo petrol (il pieno
   d'accento sul pieno d'accento non esisterebbe); l'hover scurisce di un
   filo la bianca. */
.auth-gate .btn {
    background: var(--panel);
    color: var(--accent-strong);
}

.auth-gate .btn:hover:not(:disabled) {
    background: #eaf1ee;
}

/* L'anello di focus dei bottoni della porta: la tinta d'accento anello
   comune (var(--accent)) sul petrol del fondo non si legge; bianco. */
.auth-gate .btn:focus-visible {
    outline-color: var(--accent-ink);
}

/* Il marchio dentro la porta (giro 22/10/2026, richiesta del proprietario):
   il box solitario della desk sulla pagina di login (il logo da solo, senza
   sessione) è eliminato e la console non si rende affatto per l'anonimo su
   login e attivazione; il logo apre il pannello, centrato, all'altezza di
   sempre (3.5rem, aspect 796×318 dagli attributi: nessun layout-shift).
   Dal giro caldo 24/10/2026 il marchio (scuro, trasparenza inclusa:
   luminanza media 75 sulla prova dell'asset) siede su una TARGA BIANCA:
   sul petrol pieno si leggerebbe rovesciato; la targa è l'oggetto che
   àncora la porta, nessun ritocco all'asset. */
.auth-gate .gate-logo {
    display: block;
    height: 3.5rem;
    width: fit-content;
    margin: 0 auto 1.25rem;
    padding: 0.5rem 1rem;
    background: var(--panel);
    border-radius: var(--radius-panel);
}

/* Il rientro al login dai due passi dell'attivazione: sostituisce la pill
   «Accesso» della desk (la copia è la voce della navigazione, mai inventata
   qui); mono come la riga-soglia, bianco pieno (l'accento sul petrol non
   sarebbe leggibile), non sottolineato come
   le voci nav. */
.auth-gate .gate-back {
    margin: 1rem 0 0;
    font-family: var(--mono);
    font-size: 0.75rem;
}

.auth-gate .gate-back a {
    color: var(--accent-ink);
    text-decoration: none;
}

.auth-gate .gate-back a:hover {
    text-decoration: underline;
}

/* La riga dei bottoni del login (Accedi + Attiva): le due azioni
   riempiono la riga in parti uguali, la porta non lascia spazio vuoto
   sotto il form. */
.auth-gate .btn-row > .btn {
    flex: 1;
}

/* Il reveal a cascata della porta (giro Ibrido A 24/10/2026, la skill
   interface-design): l'arrivo alla porta è l'unico momento del sito che
   merita un'entrata — logo → titolo → riga mono → hint → form salgono
   sfalsati di 35 ms col tetto a 140 ms (la coda condivide l'ultimo scalo),
   ~290 ms in tutto (durata 150 ms + scalo max), opacity e 6 px di
   salita, il tempo del tema. Il figlio 1 è
   l'h1 visually-hidden del login: invisibile, il suo ritardo non si vede.
   Mai sulle pagine operative: chi lavora le riapre di continuo, lì la
   cerimonia d'ingresso è attrito. Il kill globale di
   prefers-reduced-motion spegne l'animation e i figli restano alla resa
   ferma (fill backwards rimosso insieme all'animation: nessuna finestra
   di invisibilità). */
.auth-gate > * {
    animation: gate-rise 0.15s ease backwards;
}

.auth-gate > :nth-child(2) {
    animation-delay: 0.035s;
}

.auth-gate > :nth-child(3) {
    animation-delay: 0.07s;
}

.auth-gate > :nth-child(4) {
    animation-delay: 0.105s;
}

.auth-gate > :nth-child(n+5) {
    animation-delay: 0.14s;
}

@keyframes gate-rise {
    from {
        opacity: 0;
        transform: translateY(6px);
    }
}

/* I submit nudi dei due passi dell'attivazione (fuori da .btn-row):
   tutta la larghezza della porta. */
.auth-gate form > .btn {
    width: 100%;
}

/* Il bottone della DELETE spinto al margine destro della riga (volontà
   del proprietario, ottobre 2026): il form AGGIORNA resta a sinistra,
   questo va a DX; sul piccolo schermo (flex-wrap) si porta giù, sempre
   allineato a destra. */
.btn-row .delete-form {
    margin-left: auto;
}

/* La riga di contesto sotto un campo del pannello «Modifica partecipante»
   (ottobre 2026, volontà del proprietario): rende il VALORE ATTUALE (il
   completamento efficace e la data dell'edizione, la competenza custodita)
   perché il bottone «svuota» abbia un oggetto leggibile. È un .hint già
   colorato e rimpicciolito: qui la riga precede i comodi (il contesto si
   legge, poi si agisce), quindi il margine è in BASSO (l'aria tra la riga
   e i bottoni) e zero sopra (attaccata al campo, la stessa vicinanza
   dell'ordine vecchio), e lo spazio tra la riga e i comodi lo fanno loro
   (il margin-top del «oggi», vedi la regola sotto). Il selettore è
   .field .field-note (e non la classe nuda): .panel p vale 0 0 1rem e
   vince la specificità del tag, la classe nuda a pari specificità perde
   contro il paragrafo e non ha mai parlato — il fix precedente del
   margine era inerte per questo. */
.field .field-note {
    margin: 0;
    line-height: 1.35;
}

/* Il comodo «oggi» accanto a un campo data (volontà del proprietario,
   ottobre 2026): NON è un submit, è un bottonino che compila il campo via
   l'handler btn-today in app.js. Il .field input è larghezza piena (100%),
   quindi il bottone va su una riga sua sotto il campo, allineato a
   sinistra, alla sua misura. Veste l'accento del tema (il proprietario,
   ottobre 2026: lo voleva in blu; la tinta segue l'accento, petrol dal
   giro caldo 24/10/2026) ma alla misura discreta del comodo: il
   mono e il corpo piccolo del toggle, non i 0.9375rem della .btn piena. */
.btn-today {
    margin-top: 0.4rem;
    padding: 0.25rem 0.7rem;
    background: var(--accent);
    border: none;
    border-radius: var(--radius-chip);
    color: var(--accent-ink);
    font-family: var(--mono);
    font-size: 0.6875rem;
    font-weight: 500;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    cursor: pointer;
    transition: background 0.15s ease, transform 0.1s ease;
}

.btn-today:hover:not(:disabled) {
    background: var(--accent-strong);
}

.btn-today:active:not(:disabled) {
    transform: translateY(1px);
}

/* Il bottone della DELETE non eredita la larghezza piena del selettore
   .field button (.field input/select/textarea, ottobre 2026): la row dei
   bottoni lo vuole alla sua misura, il bottone natural, accanto
   all'AGGIORNA. */
.btn-row .field button {
    width: auto;
}

/* ── TABELLE DI PAGINA (profilo, standing, finestre, soci) ── */

/* Colonne a larghezza fissa: il filtro a pill non le fa danzare (volontà
   del proprietario, ottobre 2026). Con table-layout: fixed la larghezza di
   ogni colonna è quella dichiarata nel <colgroup> (il contenuto eccedente
   va a capo, mai ellissi: scelta del proprietario), quindi nascondere righe
   col filtro non ridistribuisce nulla. La soppressione del white-space:
   nowrap delle celle .data/.center è voluta: se una data è più lunga della
   sua colonna, va a capo (le percentuali danno respiro alle colonne-data).
   Le due eccezioni, volute entrambe a ottobre 2026: le intestazioni non
   vanno a capo mai (i titoli sono brevi; la parola lunga deborda sul vuoto
   accanto); l'email dei soci non va a capo mai (i token non si troncano,
   l'eccedenza deborda). */
.fixed-cols {
    table-layout: fixed;
}

.fixed-cols td {
    white-space: normal;
    overflow-wrap: break-word;
}

.fixed-cols th {
    white-space: nowrap;
}

.fixed-cols td.email {
    white-space: nowrap;
}

/* thead sticky sulle sei tabelle .fixed-cols (giro Ibrido A 24/10/2026, la
   richiesta del brief: il moderno vero di un gestionale non è l'animazione,
   è leggere 566 righe di rinnovi senza perdere le intestazioni): la fascia
   d'inchiostro pieno diventa la barra persistente della vista. Sticky sul
   th e non sul thead (in border-collapse il thead non si attacca su
   Safari); z-index sopra le celle che scorrono, la tinta opaca di .members
   th/.credits th (fondo --ink) fa da tendina. Nessuna deriva di layout: le
   tabelle non stanno dentro contenitori con overflow, il scrollport è la
   finestra e sopra non c'è nessuna barra fissa da scavalcare. */
.fixed-cols thead th {
    position: sticky;
    top: 0;
    z-index: 2;
}

/* Forma comune delle quattro tabelle — profilo (.profile), timeline
   (.standings), finestre (.periods), elenco admin (.members): la resa
   condivisa vive sulla famiglia, non sui nomi. I nomi delle quattro
   tabelle restano la porta delle rese proprie (il dato accent, la pill
   .st, la colonna standing, la zebra), e «.members» marca gli elenchi
   con la riga di dettaglio. Il selettore di forma è la classe, non
   l'elemento: un wrapper che ospita una tabella non la tingerebbe mai. */
.profile,
.standings,
.periods,
.members,
.credits {
    width: 100%;
    border-collapse: collapse;
    margin-top: 0.5rem;
}

.profile th,
.standings th,
.periods th,
.members th,
.credits th,
.profile td,
.standings td,
.periods td,
.members td,
.credits td {
    text-align: left;
    padding: 0.5rem 0.25rem;
    border-bottom: 1px solid var(--line-soft);
    font-size: 0.9375rem;
}

.profile tr:last-child th,
.standings tr:last-child th,
.periods tr:last-child th,
.members tr:last-child th,
.credits tr:last-child th,
.profile tr:last-child td,
.standings tr:last-child td,
.periods tr:last-child td,
.members tr:last-child td,
.credits tr:last-child td {
    border-bottom: none;
}

/* Testata: la stessa resa su tutte le tabelle. Fasce 2026: nata a colore
   solido (il blu forte dell'accento) con scritta bianca mono maiuscola,
   per risaltare (volontà del proprietario, ottobre 2026); capovolta il
   22/10/2026 nel giro anti-slop su richiesta del proprietario, e alla
   prova delle pagine il capovolta chiaro non ha retto — la tinta tenue
   coincideva con quella della zebra (stessa luminanza percepita) e la
   testata risultava «una riga come le altre». Resa attuale: fascia
   d'inchiostro pieno con scritta bianca — il «risaltare» della prima
   decisione preservato senza la banda colorata, e la separazione dalle
   righe è strutturale (scuro/claro) non di sfumatura. Il mono maiuscolo
   con tracking resta (decisione documentata, e qui è struttura: il titolo
   di colonna occupa l'intera cella, non è un'etichetta decorativa sopra il
   contenuto). Il profilo non ha testata (è una tabella a due colonne
   etichetta/valore): la sua prima colonna è dim mono, la resa propria è
   la regola sotto, che batte questa per specificità (.profile th, 0-1-1 >
   .profile th 0-1-0). */
.profile th,
.standings th,
.periods th,
.members th,
.credits th {
    color: var(--panel);
    font-family: var(--mono);
    font-size: 0.6875rem;
    font-weight: 500;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    white-space: nowrap;
    background: var(--ink);
    border-bottom: none;
}

/* Profilo: l'etichetta della riga (la prima colonna) resta dim mono su
   fondo nudo, il bordo segna la fine della riga. */
.profile th {
    color: var(--ink-dim);
    background: none;
    border-bottom: 1px solid var(--line-soft);
}

/* Valori tecnici (ID, username, CF, scadenze, tessera, finestre): dati,
   quindi monospace con tinta accent. L'accento (petrol dal giro caldo
   24/10/2026) è la tinta del
   dato nudo (cella a fondo bianco); sulla testata è la regola «Testata»
   a vincere per specificità, e dopo il capovolgimento del 22/10/2026
   la sua tinta inchiostro su fondo tenue non compete più coll'accento. */
.profile td.data,
.standings td.data,
.periods td.data,
.members td.data,
.credits td.data {
    font-family: var(--mono);
    font-size: 0.8125rem;
    color: var(--accent-strong);
}

/* Classe .vtop (nelle tabelle della pagina formazione CPD): il contenuto
   delle celle sta sempre in alto, mai centrato; le righe dei docenti su
   più righe non spostano le altre colonne della riga. */
.vtop th,
.vtop td {
    vertical-align: top;
}

/* Classe .upper (la colonna «Corso» della pagina formazione CPD): il nome
   del corso esce sempre in maiuscolo, la stessa economia della briciola
   .crumbs: la resa è della CSS, il wire resta come custodito. */
.upper {
    text-transform: uppercase;
}

/* Classe .keep (la colonna «Cognome e nome» della tabella soci): la parte
   anagrafica è un'isola non spezzabile, le sue parole restano sulla
   stessa riga; l'interruzione di riga di un'anagrafica lunga cade solo
   tra le due isole della cella: prima il nome per intero, poi il
   cognome. */
.keep {
    white-space: nowrap;
}

/* Classe .zebra (le tre tabelle della pagina formazione CPD): le righe
   si alternano una nuda e una tinta (il pari riceve una tinta scura
   d'inchiostro sul pannello bianco), per facilitare la lettura in
   orizzontale sulle righe lunghe; la bordatura di riga resta. */
.zebra tbody tr:nth-child(even) {
    background: rgba(35, 46, 44, 0.16);
}

/* Rinnovi — la directory `web/rinnovi/` (rinominata da `web/renewals/` il
   20/10/2026, la richiesta del proprietario: la DOM italiana come le sorelle).
   I riferimenti storici ai vecchi path restano dove sono registro (REPORT.md,
   HISTORY.md). */
/* Riga aperta del report rinnovi (web/rinnovi/report.php): la riga
   payment cui corrisponde il pannello «Verifica bonifico» sotto (il ✏️ di
   riga, l'economia del ?payment= che apre il pannello di modifica della
   formazione CPD). Tinta d'inchiostro più piena della zebratura, per
   riconoscere la riga a colpo d'occhio. */
.members tbody tr.is-current {
    background: rgba(35, 46, 44, 0.24);
}

/* Classe .center (le colonne che si leggono come colonne di segni: «Tipo»
   dei corsi e delle edizioni, «DLVR», «Ore» e «Crediti» delle edizioni,
   «Completamento» e «Competenza» dei partecipanti; in anagrafica/user.php la timeline:
   «Anno» e «Riportato» e le due colonne di «Finestre formative»): testo
   centrato sulla colonna, in deroga all'allineamento a sinistra delle celle;
   con i «—» dei valori ignoti la colonna si legge come una colonna di segni. */
.standings td.center,
.standings th.center,
.periods td.center,
.periods th.center,
.members td.center,
.members th.center,
.credits td.center,
.credits th.center {
    text-align: center;
}

/* Tabella profilo: la colonna delle etichette è larga. */
.profile th {
    width: 40%;
}

/* ── Pannello "Standing negli anni": la tabella ── */

/* Standing colorato nella tabella: la classe .st-<standing> (in basso)
   fornisce la tinta via --st-ink; standing non riconosciute ricadono sulla
   tinta dim di default. */
.person-title .st,
.profile .st,
.standings .st,
.members .st {
    color: var(--st-ink, var(--ink-dim));
}

/* Colonna standing (della timeline e della tabella dei soci): il valore e
   il titolo della colonna centrati (la testata comune centra già il
   titolo, l'elenco lo deriva). Il respiro della colonna nella tabella dei
   soci lo dà il colgroup a larghezza fissa (ottobre 2026); il min-width
   resta per la timeline del socio, che non è fixed. */
.standings td.standing,
.standings th.standing,
.members td.standing,
.members th.standing {
    text-align: center;
    min-width: 6.5rem;
}

/* I 7 valori dell'enum membership.standing (lo stato del socio sulla
   tessera), uno colore ciascuno (tinte tutte leggibili sul tema chiaro;
   ritinte dal giro caldo 24/10/2026: l'inactive coincide col nuovo
   ink-dim, l'expired è l'ambra nominata del tema, il verde active si
   scalda di un filo verso il teal; il resigned resta il blu, distinto
   dal petrol d'accento: la stessa tinta non può dire due concetti);
   la riga della non socia (.st-none) e le standing non riconosciute
   ricadono sulla tinta dim di default (la prima materializzata qui, le
   seconde sul fallback di .st sopra). La classe comanda la tinta della
   pill nelle due tabelle (la timeline del socio e l'elenco dei soci). */
.st-active   { --st-ink: #3f8a64; }
.st-inactive { --st-ink: #62706a; }
.st-emeritus { --st-ink: #6d4f96; }
.st-expired  { --st-ink: #a86a24; }
.st-resigned { --st-ink: #164a6e; }
.st-expelled { --st-ink: #b3372f; }
.st-deceased { --st-ink: #6f6a64; }
.st-none     { --st-ink: var(--ink-dim); }

/* ── Pannello «Piano Nazionale Formazione» (anagrafica/member.php): la vista di cpdcheck ── */

/* Il check (globale in testa al pannello e per finestra): la pill keyed
   sul valore dell'enum CreditCheck della spec, a sfondo pieno nei tre
   colori del semaforo (verde = IN REGOLA, sia SUCCESS sia STARTED — la
   copia è la stessa, il wire distingue i due stati —, giallo = IN
   SCADENZA, rosso = NON IN REGOLA). Il rosso e il verde sono le variabili
   di tema (--ko, --ok): dal giro caldo 24/10/2026 la distinzione
   «bosco del banner / verde keyed del semaforo» è caduta, un solo verde
   del tema (--ok, ritinto verso il teal) copre entrambe le sedi. Il
   giallo IN SCADENZA è il fondo ambra chiaro
   (#f7f4e3, la stessa famiglia di verdi e rossi) con l'inchiostro ambra
   scuro che la lettura già aveva, 16/10: il pieno amber-400 non rendeva
   bene (richiesta del proprietario, stesso giro). ck-future è
   la copia della finestra futura (la chiave check è omessa sul wire: la
   pagina lo rende come stato, non come giudizio). Il marker .ckpill è la
   stessa pill per le sedi che non sono una tabella .credits né la sua
   testata: la colonna STATO del report formazione/report.php, dove la
   cella sta in una td di una tabella .members e il selettore discendente
   d'origine non la raggiunge. */
.credits .ck,
.credits-head .ck,
.ckpill {
    display: inline-block;
    padding: 0.05rem 0.5rem;
    border-radius: var(--radius-chip);
    color: var(--ck-bg, var(--panel));
    background: var(--ck-ink, var(--ink-dim));
    font-size: 0.8rem;
    font-weight: 600;
    white-space: nowrap;
    /* Il passo fisso (richiesta del proprietario, ottobre 2026): nella
       tabella del report rinnovi la PNF (.ckpill) e lo STATO (.rstpill)
       stanno sulla stessa riga e devono uscire alla stessa altezza; senza
       il valore fisso l'altezza veniva dal line-height ereditato (1.5)
       moltiplicato dai font diversi dei due rami (il marker .ck della
       famiglia mono, la .rstpill dall'eredità sans), e le pill rendevano
       alte diverse — il passo è qui, gemello a .rstpill. */
    line-height: 1.4;
}
.ck-SUCCESS { --ck-ink: var(--ok); --ck-bg: #edf4ef; }
.ck-FAILURE { --ck-ink: var(--ko); --ck-bg: #f8eeed; }
.ck-STARTED { --ck-ink: var(--ok); --ck-bg: #edf4ef; }
.ck-PENDING { --ck-ink: #a17c1e; --ck-bg: #f7f4e3; }
.ck-future  { --ck-ink: var(--ink-dim); --ck-bg: var(--line-soft, #e7e8e1); }

/* La testa del pannello: il check globale e l'anno di riferimento in riga
   (l'asof dim, mono: è un dato tecnico della risposta). */
.credits-head {
    display: flex;
    align-items: baseline;
    gap: 0.75rem;
    margin: 0.5rem 0 0;
}
.credits-head .credits-asof {
    color: var(--ink-dim);
    font-family: var(--mono);
    font-size: 0.75rem;
}

/* Testata del pannello «Piano Nazionale Formazione» (anagrafica/member.php): la prima colonna stacca il
   titolo «Finestra» dal bordo sinistro dell'intestazione colorata (il
   padding orizzontale di 0.25rem lo tiene attaccato all'angolo). Scopo solo
   .credits: le altre tabelle non hanno la testata su fondo colorato, o
   portano un layout a larghezze dichiarate (la .members.fixed-cols) che
   l'aumento di padding sposterebbe. */
.credits thead th:first-child {
    padding-left: 0.75rem;
}

/* Le sub righe dei corsi (il dettaglio, non il bilancio): la cella unica
   impilata, più stretta e dim della
   riga-finestra. Le tre righe di resa
   del corso (capolettera dei chip, titolo, dato): il titolo è grassetto
   (il peso che la cella dim non porta); il dato va a capo e si allinea a
   sinistra sotto il nome del corso — l'indentazione è il capolettera a
   larghezza fissa (la classe .cr-head), non un margine a lettere: i chip
   della riga 1 variano (CP·IRL, AF·FDA, …) e il bordo è sempre quello, la
   resa voluta dal proprietario, 16/10. Le sub righe si rendono sempre: il
   pulsante di espansione (e le sue regole .btn-toggle-rows) è caduto a
   ottobre 2026 per scelta del proprietario. */
.credits tr.cr-sub td {
    padding: 0.25rem 0.25rem 0.25rem 1.25rem;
    font-size: 0.8125rem;
    color: var(--ink-dim);
}
.credits .cr-course .cr-line {
    display: block;
}
.credits .cr-course .cr-head {
    display: inline-block;
    /* 13ch: la label più lunga dell'enum cpd_type (CORSO PATROCINATO),
       il capolettera non muove mai (il dlvr non si rende qui, la sola
       label del tipo governa la larghezza). */
    min-width: 13ch;
    margin: 0 0.35rem 0.05rem 0;
}
/* Il dato del corso (data · COMPETENZA · CREDITI): sempre a capo sotto il
   titolo, il block che segue l'inline-block lo porta già giù. */
.credits .cr-course .cr-meta {
    display: block;
}
.credits tr.cr-sub .cr-course .upper {
    color: var(--ink);
    font-weight: 600;
}

/* Le etichette della seconda riga (COMPETENZA, CREDITI): la sola forma
   maiuscola della riga-corso (inchiostro e corpo ereditati dalla sub
   riga, il corsivo del bucket non c'entra). */
.credits tr.cr-sub .lbl {
    letter-spacing: 0.04em;
}

/* La riga del bucket «Non assegnati» (i corsi fuori finestra: la divergenza
   dichiarata dal PHP): dim in cerniera. */
.credits tr.unassigned td {
    color: var(--ink-dim);
    font-style: italic;
}

/* ── Pannello "Anagrafica": tabella dell'elenco riservato all'admin ── */

/* Override della tabella soci sulla forma comune (sezione TABELLE DI
   PAGINA sopra): una riga per utenza, più stretta perché le colonne sono
   molte: respiro a sinistra su ogni colonna, bordo più marcato e corpo
   più piccolo; la testata è quella comune («Testata» sopra: già bianca
   su fascia d'inchiostro, nowrap, senza bordo). */
.members th,
.members td {
    padding: 0.5rem 0.5rem 0.5rem 0.75rem;
    border-bottom: 1px solid var(--line);
    font-size: 0.8125rem;
}

/* Dati tecnici (username, CF, scadenze, tessera): più piccoli del corpo
   comune. */
.members td.data {
    font-size: 0.75rem;
}

/* Colonna N. (il numero di tessera): in grassetto, da leggere come il
   segno d'identificazione della riga. Il numero non va a capo mai: con
   table-layout: fixed la colonna al 5% conteneva tre cifre (1384 spezzato
   in due righe, ottobre 2026); il nowrap lo tiene su una riga sola e
   l'eventuale eccedenza deborda sul vuoto accanto, l'economia del nowrap
   dell'email. */
.members td.badge {
    font-weight: 700;
    white-space: nowrap;
}

/* Colonna email (la username-credenziale linkata a anagrafica/user.php): via la
   resa classica da link anni 2000 (azzurro UA e sottolineatura sempre
   attiva): tinta del dato, nessuna sottolineatura né effetto hover, e
   il font normale della tabella in bold, non il mono tecnico della
   cella; corpo di due punti sopra il dato tecnico (0.75rem), così
   l'email si legge per prima. */
.members td.data a {
    color: inherit;
    text-decoration: none;
    font-family: var(--sans);
    font-weight: 700;
    font-size: 0.875rem;
}

/* Colonna delle due icone di pagina (👤 anagrafica/user.php e 💳 anagrafica/member.php):
   centrata e senza ritorno a capo, le ancore nude (le emoji non
   prendono tinta né sottolineatura: testo delle icone, con il title
   come etichetta); un po' di spazio tra le due, voluto dal proprietario
   ottobre 2026 (💳 scelta al posto di 🪪: stessa idea). */
.members td.links,
.members th.links {
    text-align: center;
    white-space: nowrap;
}

.members td.links a {
    text-decoration: none;
}

.members td.links a + a {
    margin-left: 0.6rem;
}

/* Pill dello standing (la timeline del socio e l'elenco soci): la stessa
   economia dei chip-filtro (tinta --st-ink in color-mix su fondo e bordo,
   pill 999px), in versione compatta per la cella di tabella, testo in
   maiuscolo. */
.person-title .st,
.profile .st,
.standings .st,
.members .st {
    display: inline-block;
    padding: 0.0625rem 0.625rem;
    border: 1px solid color-mix(in srgb, var(--st-ink, var(--ink-dim)) 45%, transparent);
    border-radius: var(--radius-chip);
    background: color-mix(in srgb, var(--st-ink, var(--ink-dim)) 8%, transparent);
    font-size: 0.75rem;
    font-weight: 600;
    text-transform: uppercase;
    white-space: nowrap;
}

/* Pannelli delle viste affiancati: era la griglia del duo «Standing negli
   anni» + «Finestre formative» di anagrafica/member.php. L'assorbimento di ottobre 2026
   lascia la sola timeline, che si rende come pannello diretto: nessuna
   griglia, nessuna regola (la classe .views-duo non è più usata). */

/* Righe nascoste dal filtro client-side degli standing (app.js):
   l'attributo hidden da solo non basta, la resa di tabella vince sulle
   regole UA, quindi regola esplicita. La stessa regola è ripetuta su
   .credits (le sub riga dei corsi del pannello crediti, nascoste dal
   toggle d'espansione: la resa di tabella è la medesima). */
.members tr[hidden] {
    display: none;
}

.credits tr[hidden] {
    display: none;
}

/* Zebra dell'elenco soci: la stessa tinta di .zebra della formazione CPD
   (riga sì e riga no, per facilitare la lettura in orizzontale), ma qui
   ogni socio occupa due righe (principale + dettaglio), quindi la riga
   principale va tinta una su due: nth-child(4n+1) conta le righe delle
   coppie. Lo scope :not(.zebra) tiene fuori tutte le tabelle che zebrano
   al passo naturale di due (formazione/index.php, formazione/report.php,
   formazione/admin.php, rinnovi/report.php): sono a riga singola per
   record e dichiarano .zebra esplicita; senza questo filtro una tabella
   members+zebra batterebbe su entrambe le regole con pattern sovrapposti.
   (Storicamente lo scope era :not(.vtop), che nel report formazione —
   members senza vtop né zebra — lasciava passare il 4n+1 su righe singole:
   «una tinta e tre nude», corretto il 22/10/2026 portando .zebra sulla
   tabella e restringendo qui.) */
.members:not(.zebra) tbody tr:nth-child(4n+1) {
    background: rgba(35, 46, 44, 0.16);
}

/* Dettaglio al hover sulle prime due celle (N. e nome): il resto dei
   dati dell'utenza si apre nella riga successiva (markup in anagrafica/index.php),
   allineata alla colonna Nome (cella vuota sotto la N. e colspan 4 fino
   a fondo tabella): email, standing e icone non hanno grilletto e il
   loro hover non apre nulla, i link restano raggiunti dal mouse. Il
   grilletto è :has sulla cella (già usato dal filtro degli standing), la
   riga-di-dettaglio condivide il data-standing con la sua riga, così il
   filtro degli standing le nasconde in coppia. Il dettaglio resta
   visibile anche mentre ci si passa sopra il mouse (seconda regola). */
.members tbody tr[data-standing]:has(td:nth-child(-n+2):hover) {
    background: var(--panel-soft);
}

.members tr.row-detail {
    display: none;
}

.members tbody tr[data-standing]:has(td:nth-child(-n+2):hover) + tr.row-detail,
.members tr.row-detail:hover {
    display: table-row;
}

/* Tinta da riga-di-dettaglio: dati secondari, monospace dim su fondo
   leggermente più scuro della riga in hover. La padding-left coincide con
   quella delle celle (0.75rem): il blocco esce allineato al testo della
   colonna Nome (la prima cella è il vuoto sotto la colonna N.). */
.members tr.row-detail td {
    background: var(--panel-soft);
    border-bottom: 1px solid var(--line);
    padding: 0.3rem 0.5rem 0.5rem 0.75rem;
    font-family: var(--mono);
    font-size: 0.75rem;
    color: var(--ink-dim);
}

/* Hover di riga uniforme su tutte le tabelle-elenco (giro Ibrido A
   24/10/2026): prima il hover esisteva solo come grilletto dell'isola
   anagrafica; ora ogni riga accesa conferma la posizione di lettura sulla
   riga lunga. Stessa tinta dell'isola (--panel-soft), nessun colore nuovo.
   Il posizionamento in coda al blocco members è ciò che risolve i pari di
   specificità con .zebra e .is-current: la fonte è unica per tutti e tre i
   pattern (zebra, riga corrente, hover) e qui l'hover vince a vista.
   .profile è fuori di seta: non è un elenco da scorrere ma un dossier
   chiave/valore, l'evidenziazione non avrebbe bersaglio. */
.members tbody tr:hover,
.credits tbody tr:hover,
.standings tbody tr:hover,
.periods tbody tr:hover {
    background: var(--panel-soft);
}

/* Cifre a larghezza costante nelle tabelle-elenco (giro Ibrido A
   24/10/2026): dove il dato passa dal mono al sans (date, importi, conti)
   le colonne si leggono come colonne; sulla cella-mono è un no-op esatto
   (il glifo è già a passo fisso). */
.members td,
.credits td {
    font-variant-numeric: tabular-nums;
}

/* Prima cella della riga-di-dettaglio: il vuoto sotto la tessera, senza
   tinta né bordo: fondo, bordo e griglia iniziano dalla colonna Nome. */
.members tr.row-detail td:first-child {
    background: none;
    border-bottom: none;
}

.members tr.row-detail:last-child td {
    border-bottom: none;
}

/* Contenuto del dettaglio: tabella a due colonne etichetta/valore. Il dl
   è ridotto a grid, con dt e dd diretti che diventano le celle, così
   ogni etichetta e ogni valore finisce nella sua colonna: etichette
   maiuscole dim tutte allineate a sinistra, valori in tinta nella
   colonna accanto. */
.members .detail-grid {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    gap: 0.2rem 1.1rem;
    margin: 0;
}

.members .detail-grid dt {
    color: var(--ink-dim);
    font-size: 0.6875rem;
    letter-spacing: 0.08em;
    text-transform: uppercase;
}

.members .detail-grid dd {
    margin: 0;
    color: var(--accent-strong);
    overflow-wrap: anywhere;
    /* Gli a capo di profileCell con `",\n"` (ogni ruolo su una riga) rendono. */
    white-space: pre-line;
}

/* ── Filtro client-side a chip (meccanismo condiviso) ──
   La classe .chip-filter è la resa comune dei filtro a chip: oggi gli
   standing della pagina soci e i cpd_type della pagina formazione (il
   fieldset porta data-filter con il nome dell'attributo di riga che
   governa, standing o cpd; il comportamento è in app.js). */

/* Chip dei checkbox come pill nella tinta propria (il --st-ink della
   classe di tinta, portato sull'etichetta così bordo, fondo e casella lo
   leggono): bordo e fondo velati, casella personalizzata a sinistra;
   nessuna selezione: tutti i valori (il comportamento è in app.js).
   Nessun legend: i sottotitoli del box sono caduti per scelta del
   proprietario, ottobre 2026. */
.chip-filter {
    border: none;
    padding: 0;
    margin: 0.5rem 0 0.9rem;
}

/* La barra di ricerca delle due tabelle dei soci (anagrafica/index.php e
   formazione/report.php; app.js, la riga data-search): il blocco sta subito
   sopra l'intestazione della tabella che governa, dopo i chip e gli
   hint (la richiesta del proprietario, ottobre 2026). La misura del testo non
   è più quella dei chip: il font è +2pt sull'originale 0.85rem (stessa
   richiesta), lo stesso modulo di calc(... + 2pt) di .ro-desc; la --mono non
   c'entra mai, è testo libero. Nessun'etichetta a lato: la parola «Cerca» non
   aggiunge nulla alla lente e al placeholder (sempre ottobre 2026). La tenuta
   è width: 100% come la tabella; la riga resta per conto suo: il campo lo
   governa app.js con il selettore sull'intero pannello, non con l'adiacenza
   nel DOM. */
.search-row {
    margin: 0.5rem 0 0;
}

/* La tenuta del campo: larga quanto la tabella (il .members è width: 100%
   del contenuto del pannello, e questa sta nello stesso contenuto), il bordo
   e il fondo del campo, la lente a sinistra. L'anello del focus è della
   tenuta, non dell'input, che nudo non ha bordo: :focus-within.
   Maggior evidenza (richiesta del proprietario, 22/10/2026): il fondo a
   riposo è il grigio morbido di --panel-soft — sul bianco del pannello il
   box si vede come postazione di digitazione, non come campo mimetico —
   e al focus schiarisce a bianco mentre monta l'anello d'accento. Il bordo
   a riposo è la tacca --line-strong (seconda mano della richiesta, 22/10:
   il bordo sempre leggibile anche a box non selezionato). I fondi,
   l'accento e la scala delle linee sono quelli del tema. */
.member-search {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    width: 100%;
    padding: 0 0.85rem;
    border: 1px solid var(--line-strong);
    border-radius: var(--radius-control);
    background: var(--panel-soft);
    color: var(--ink);
}

.member-search:focus-within {
    background: var(--panel);
    outline: 2px solid var(--accent);
    outline-offset: 1px;
}

/* La lente d'ingrandimento (svg inline nell'input): in em così cresce col
   +2pt del campo, mai colorata a olio: la tinta è --ink-dim come il testo
   dim della pagina. */
.search-icon {
    width: 1em;
    height: 1em;
    flex-shrink: 0;
    fill: none;
    stroke: var(--ink-dim);
    stroke-width: 1.6;
}

/* Lente d'accento a ricerca attiva (giro evidenza 22/10/2026): la tinta
   piena resta vietata a riposo (sopra), ma quando il focus è nella tenuta
   la lente diventa il segnalibro del box. */
.member-search:focus-within .search-icon {
    stroke: var(--accent);
}

/* Il campo di ricerca delle due tabelle dei soci: prende tutto il resto della
   tenuta; il bordo non lo porta (è della tenuta), l'outline pure: l'input nudo
   non deve raddoppiare l'anello. */
.search-input {
    flex: 1;
    min-width: 0;
    padding: 0.5rem 0;
    border: 0;
    background: transparent;
    color: var(--ink);
    font-size: calc(0.85rem + 2pt);
    outline: none;
}

/* Barra dei chip-filter affiancati (rinnovi/report.php: lo standing a
   sinistra, gli stati del rinnovo a destra, la richiesta del proprietario
   ottobre 2026). Una riga: il primo fieldset a sinistra, l'ultimo a destra
   (space-between); sugli schermi stretti va in wrap e si centra (l'economia
   dei .filter-row interni). I fieldset restano indipendenti per conto loro: la
   combinazione AND è di app.js, non di qui. Il margin-bottom dei fieldset
   interni è azzerato: la barra dà lo spazio, non il doppio. */
.chip-filter-bar {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    align-items: flex-start;
    gap: 0.5rem 1rem;
    margin: 0.5rem 0 0.9rem;
}
.chip-filter-bar > .chip-filter {
    margin: 0;
}

/* Ogni .filter-row è una riga di chip centrata; su schermi stretti una
   riga può andare in wrap, sempre centrata (anagrafica/index.php ne rende due: tre
   standing vivi sopra, quattro cessati sotto). */
.chip-filter .filter-row {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 0.45rem;
    margin-top: 0.5rem;
}

/* Font a 0.75rem, la stessa dimensione delle pill .st in tabella: è la
   misura che fa stare i quattro chip cpd di formazione/index.php su un'unica
   riga centrata, e il proprietario, ottobre 2026, ha voluto la stessa
   misura anche per gli standing di anagrafica/index.php. */
.chip-filter .filter-chip {
    display: inline-flex;
    align-items: center;
    gap: 0.45rem;
    flex-shrink: 0;
    margin: 0;
    padding: 0.3rem 0.8rem 0.3rem 0.6rem;
    border: 1px solid color-mix(in srgb, var(--st-ink, var(--ink-dim)) 45%, transparent);
    border-radius: var(--radius-chip);
    background: color-mix(in srgb, var(--st-ink, var(--ink-dim)) 8%, transparent);
    font-family: var(--mono);
    font-size: 0.75rem;
    cursor: pointer;
    transition: background 0.15s ease, border-color 0.15s ease;
    user-select: none;
}

.chip-filter .filter-chip:hover {
    border-color: var(--st-ink, var(--ink-dim));
    background: color-mix(in srgb, var(--st-ink, var(--ink-dim)) 16%, transparent);
}

/* Conteggio tra parentesi sul chip: dato, non nome dello standing, quindi
   tinta dim (il nome resta la parte colorata). */
.chip-filter .filter-count {
    color: var(--ink-dim);
}

/* Pill selezionata (casella spuntata): la tinta dello standing sale
   sul fondo. */
.chip-filter .filter-chip:has(input:checked) {
    background: color-mix(in srgb, var(--st-ink, var(--ink-dim)) 26%, transparent);
    border-color: var(--st-ink, var(--ink-dim));
}

/* Casella personalizzata: quadrino col bordo nella tinta dello
   standing, spunta chiara su fondo pieno da selezionata (appearance:
   none toglie la resa nativa del control). */
.chip-filter input[type='checkbox'] {
    appearance: none;
    margin: 0;
    display: grid;
    place-content: center;
    width: 1.05rem;
    height: 1.05rem;
    border: 1px solid var(--st-ink, var(--ink-dim));
    border-radius: var(--radius-control);
    background: transparent;
    cursor: pointer;
    transition: background 0.15s ease;
}

.chip-filter input[type='checkbox']::after {
    content: "✓";
    font-size: 0.75rem;
    line-height: 1;
    color: var(--bg);
    visibility: hidden;
}

.chip-filter input[type='checkbox']:checked {
    background: var(--st-ink, var(--accent-strong));
    border-color: var(--st-ink, var(--accent-strong));
}

.chip-filter input[type='checkbox']:checked::after {
    visibility: visible;
}

.chip-filter input[type='checkbox']:focus-visible {
    outline: 1px solid var(--accent-strong);
    outline-offset: 2px;
}

/* Label della pill in maiuscolo (scelta del proprietario, ottobre 2026):
   la copy resta minuscola in STANDING_LABELS e si trasforma qui, come nelle
   pill .st in tabella (.members .st); le label cpd di CPD_TYPE_LABELS sono
   già maiuscole e non cambiano resa. */
.chip-filter .st {
    color: var(--st-ink, var(--ink-dim));
    text-transform: uppercase;
}

/* Tinte dei quattro codici cpd_type per i chip-filtro di formazione/index.php
   (la stessa economia dei .st-<standing> di sopra): il codice è quello
   sul wire, la classe porta solo il colore. */
.cpd-SP { --st-ink: #164a6e; }
.cpd-AF { --st-ink: #6d4f96; }
.cpd-CP { --st-ink: #a86a24; }
.cpd-LM { --st-ink: #3f8a64; }

/* Tinte dei tre chip del semaforo per il filtro del report formazione
   (report.php): la stessa economia delle .cpd-<codice> sopra, letta sul
   --st-ink del .chip-filter, e keyed sulle tre lettere del raggruppato
   (ok|pending|fail, CREDIT_CHECK_GROUPS in domain.php). Il colore è quello
   del check che il chip rappresenta, ripreso dalla stessa famiglia delle
   tinte semaforo già materializzate qui (il verde di --st-active, il giallo
   d'inchiostro del PENDING, il rosso di --st-expelled): il chip è la casella
   della riga, quindi ripete il colore della pill senza importarne la
   meccanica (--ck-ink/--ck-bg sono della pill a fondo pieno). */
.ckchip-ok      { --st-ink: #3f8a64; }
.ckchip-pending { --st-ink: #a17c1e; }
.ckchip-fail    { --st-ink: #b3372f; }

/* ── Rinnovi — il riepilogo del ciclo (rinnovi/report.php): i tre box ── */

/* Il box di selezione dell'anno è NASCOSTO a resa, non eliminato (scelta
   del proprietario, 22/10/2026): il form GET, la sua action vuota e la
   sua hint restano nel DOM e la meccanica funziona ancora per chi porta
   ?year= in query (i link del pannello di verifica e delle prove). Si
   riapre togliendo questa regola o la classe .cycle-select nel markup
   di rinnovi/report.php. */
section.panel.cycle-select {
    display: none;
}

/* I tre box di riepilogo sopra gli elenchi: il numero in risalto, la
   dicitura sotto. griglia a tre colonne, che su schermi stretti va a una
   (flex-wrap: la colonna unica del layout è già troppo stretta per tre
   box). Le tre tinte dicono la classe del rinnovo, non un giudizio:
   sono un componente proprio, non le variabili del semaforo (.ck-*) né
   quelle degli standing (.st-*), e il numero riprende il fondo pieno
   della classe (l'inchiostro chiaro su fondo colorato: la lettura a
   colpo d'occhio che il proprietario vuole). */
.renewal-stats {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 0.75rem;
    margin: 0.2rem 0 0.6rem;
}

.rstat {
    border-radius: var(--radius-panel);
    padding: 0.8rem 1rem 0.7rem;
    text-align: center;
    color: var(--panel);
}

.rstat-num {
    display: block;
    font-family: var(--mono);
    /* Il mono protagonista del dato (giro caldo 24/10/2026): +tacca e
       tracking chiuso — il numero è la cosa da leggere a colpo d'occhio,
       la richiesta che il box esiste a soddisfare. */
    font-size: 1.75rem;
    font-weight: 700;
    letter-spacing: -0.02em;
    line-height: 1.15;
}

.rstat-label {
    display: block;
    margin-top: 0.25rem;
    font-size: 0.75rem;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
}

/* Non avviati (tessera active senza riga): l'ardesia scaldata (slate
   vira petrol dal giro caldo 24/10/2026), la classe d'attesa. */
.rstat-notstarted {
    background: #4e5d5b;
}

/* In corso (dichiarata o ricevuta): l'ambra del «in lavorazione», la
   famiglia calda del chip POST (l'ambra nominata del tema). */
.rstat-inprogress {
    background: var(--accent-warm);
}

/* Completati (confermata): il verde bosco del banner ok (--ok), il fatto
   compiuto. */
.rstat-completed {
    background: var(--ok);
}

/* Semaforo del rinnovo nella tabella del report (rinnovi/report.php): la
   pill a fondo pieno keyed sul bucket del report (not_started|in_progress|
   completed), le TRE STESSE tinte dei box di riepilogo sopra (la richiesta
   del proprietario, ottobre 2026): il colore dice la stessa identica cosa
   del numero nel box. La meccanica è la gemella del semaforo CPD (.ck/.
   ckpill): --rst-ink è il fondo pieno della tinta, --rst-bg l'inchiostro
   chiaro sopra il fondo (il bianco pannello, come il box); il maiuscolo è
   la resa di ogni stato in pill del progetto — la copy resta minuscola
   nell'etichetta (la stessa economia dei chip-filtro qui sopra e delle .st
   in tabella, richiesta del proprietario ottobre 2026: NON AVVIATO / IN
   CORSO / COMPLETATO). */
.rstpill {
    display: inline-block;
    padding: 0.05rem 0.5rem;
    border-radius: var(--radius-chip);
    color: var(--rst-bg, var(--panel));
    background: var(--rst-ink, var(--ink-dim));
    font-size: 0.8rem;
    font-weight: 600;
    white-space: nowrap;
    text-transform: uppercase;
    /* Il passo fisso gemello di .ckpill (richiesta del proprietario,
       ottobre 2026): PNF e STATO nella stessa riga del report rinnovi
        escono alla stessa altezza. */
    line-height: 1.4;
}
.rst-not_started { --rst-ink: #4e5d5b; --rst-bg: var(--panel); }
.rst-in_progress { --rst-ink: var(--accent-warm); --rst-bg: var(--panel); }
.rst-completed   { --rst-ink: var(--ok); --rst-bg: var(--panel); }

/* Tinte dei chip del filtro del rinnovo (report.php): l'economia dei
   .ckchip-* del report formazione — la casella ripete il colore della pill
   senza importarne la meccanica. Le quattro chiavi di ottobre 2026 (la
   separazione dell'in corso): l'IN ATTESA (declared) è l'ambra del bucket
   madre; il RICEVUTO (received, il riscontro della segreteria) è il
   petrol del tema (--accent-strong, dal giro caldo 24/10/2026: prima era
   il blu, della stessa famiglia di .st-resigned; ora è la sola tinta del
   tema, la famiglia va letta lì): la riga è in
   lavorazione alla segreteria, non è né un'attesa del socio né un esito. Il
   chip IN CORSO non è più reso (i due lo sostituiscono), la classe resta:
   è il fallback della chiave fuori enum (difesa). */
.rstchip-notstarted { --st-ink: #4e5d5b; }
.rstchip-inprogress { --st-ink: var(--accent-warm); }
.rstchip-attesa     { --st-ink: var(--accent-warm); }
.rstchip-ricevuto   { --st-ink: var(--accent-strong); }
.rstchip-completed  { --st-ink: var(--ok); }

/* Su schermi stretti i tre box si impilano (la griglia a una colonna);
   la soglia è quella del layout. */
@media (max-width: 760px) {
    .renewal-stats {
        grid-template-columns: minmax(0, 1fr);
    }
}

/* ── Rinnovo — la pagina del socio (rinnovi/index.php): stepper, radio, ──
   ── coordinate del bonifico (ottobre 2026)                               ── */

/* Lo stepper del percorso (Avvio → Ricevuto → Completato), montato DENTRO il
   pannello unico del socio (rinnovi/index.php, ottobre 2026: non è più un
   section a sé): i tre passi in riga, l'elenco marcato a mano (i numeri sono
   il marker: nessun counter CSS, il glifo del fatto è nel markup). La tinta
   del numero è gemella dei box .rstat del report (ardesia scaldata/
   ambra/verde: la
   stessa classe del percorso, non un giudizio). Il pallino è la conferma
   contabile (la revisione del 18/10): il passo VERDE col ✓ è contabilizzato,
   il corrente non ancora contabilizzato ha bordo, fondo e pallino ambra, i
   futuri restano chiari con la cornice. */
.renew-steps {
    margin-bottom: 0.8rem;
}

.rsteps {
    display: flex;
    gap: 0.75rem;
    list-style: none;
    margin: 0.2rem 0 0.4rem;
    padding: 0;
}

.rstep {
    flex: 1;
    display: flex;
    align-items: center;
    gap: 0.5rem;
    border: 1px solid var(--line);
    border-radius: var(--radius-control);
    padding: 0.55rem 0.75rem;
    font-size: 0.875rem;
}

.rstep-num {
    display: inline-grid;
    place-items: center;
    width: 1.6rem;
    height: 1.6rem;
    border-radius: var(--radius-chip);
    background: var(--rst-ink, var(--line-soft));
    color: var(--panel);
    font-family: var(--mono);
    font-weight: 700;
    font-size: 0.8125rem;
    flex: none;
}

/* Il passo contabilizzato (verde col ✓): la conferma contabile — l'Avvio
   quando la riga payment esiste, il Ricevuto e il Completato quando la
   segreteria li ha registrati. Il bordo resta neutro: la tinta piena è solo
   sul corrente. */
.rstep-done {
    --rst-ink: var(--ok);
}

/* Il passo corrente non ancora contabilizzato: ambra (l'attesa che la
   segreteria chiuda il passo — la ricezione del bonifico, la conferma del
   rinnovo). Bordo, fondo e pallino ambra: «dove sei, in lavorazione» si vede
   dalla cornice. L'ambra è l'ambra nominata del tema (--accent-warm,
   la stessa dei chip .rst-* del report). */
.rstep-now {
    --rst-ink: var(--accent-warm);
    border-color: var(--accent-warm);
    background: color-mix(in srgb, var(--accent-warm) 8%, transparent);
}

/* Il futuro (nessuna tinta): su fondo chiaro, dim. */
.rstep-todo .rstep-num {
    --rst-ink: var(--line-soft);
    color: var(--ink-dim);
}

.rstep-label {
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    font-size: 0.75rem;
    min-width: 0;
    overflow-wrap: anywhere;
}

/* Le card-radio dell'opzione (la scelta del socio, ottobre 2026): una card
   per riga, la label è la card intera (click anywhere), la radio nativa
    resta focusabile. Il selezionato è la tinta del progetto (il bosco di
   --ok, la famiglia del «fatto»: la scelta è presa), l'hover la cornice
   accentata. Gli importi in mono: è l'unico dato tecnico della card. */
.renew-options {
    border: none;
    padding: 0;
    margin: 0 0 1rem;
}

.renew-options legend {
    display: block;
    margin-bottom: 0.4rem;
    padding: 0;
    font-family: var(--mono);
    font-size: 0.6875rem;
    font-weight: 500;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--ink-dim);
}

.renew-option {
    display: flex;
    gap: 0.75rem;
    border: 1px solid var(--line);
    border-radius: var(--radius-panel);
    background: var(--field-bg);
    padding: 0.7rem 0.9rem;
    margin-bottom: 0.5rem;
    cursor: pointer;
    transition: border-color 0.15s ease, box-shadow 0.15s ease, background-color 0.15s ease;
}

/* L'isola etichetta + descrizione (la quarta chiave del blocco, ottobre
   2026): la colonna che occupa lo spazio fra la radio e l'importo. La card
   non allinea più il blocco: l'importo sta in alto (la richiesta del
   proprietario, ottobre 2026). */
.ro-main {
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
    min-width: 0;
    flex: 1;
}

.renew-option:hover {
    border-color: var(--accent);
}

/* La radio ha la sua resa nativa (focusabile): nessuna dimensione piena
   (.field input è 100%), le card non sono .field. Il margine superiore la
   porta sulla linea di testo dell'etichetta (la card non allinea più il
   blocco: l'importo sta in alto, ottobre 2026): 0.9375rem/1.5 della key =
   riga 1.406rem, la radio ~1rem centrata sulla riga → (1.406 − 1) / 2. */
.renew-option input[type='radio'] {
    width: auto;
    margin: 0.2rem 0 0;
    accent-color: var(--ok);
    flex: none;
}

.ro-key {
    font-weight: 600;
    min-width: 0;
    overflow-wrap: anywhere;
}

/* La descrizione del prodotto sotto l'etichetta (ottobre 2026): testo dim
   (2pt sopra il piccolo originale, la richiesta del proprietario), la
   lettura lunga spezzata a capo (non è un dato tecnico: mai mono). Il
   pre-line rende i \n del testo — i capi decisi dalla gestione nel jsonb
   (la scelta del proprietario, ottobre 2026: nessun wrap automatico in
   pagina, l'escape JSON \n è il contratto dichiarato in openapi.yaml);
   gli spazi multipli collassano, le frasi più lunghe della card vanno
   a capo da sole con l'overflow-wrap. */
.ro-desc {
    font-size: calc(0.8125rem + 2pt);
    white-space: pre-line;
    color: var(--ink-dim);
    min-width: 0;
    overflow-wrap: anywhere;
}

.ro-amount {
    margin-left: auto;
    font-family: var(--mono);
    font-weight: 600;
    white-space: nowrap;
}

.renew-option:has(input[type='radio']:checked) {
    border-color: var(--ok);
    background: #edf4ef;
    box-shadow: 0 0 0 2px color-mix(in srgb, var(--ok) 18%, transparent);
}

.renew-option:has(input[type='radio']:focus-visible) {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}

/* Il blocco operativo «Esegui il bonifico»: l'importo in risalto (il numero
   è uno span proprio: il JS pre-avvio riscrive la sola text, mai il
   blocco), le righe chiave/valore. La cornice verde chiara (la famiglia del
   «pagare»: il semaforo PENDING/ok) lo stacca dal resto del pannello: è il
   dato da usare, non da leggere. Il titolo del blocco è l'h3 del pannello
   (.panel h3, ottobre 2026: la classe .pay-cta-title è retiring, nessun
   chiamante). */
.pay-cta {
    border: 1px solid var(--line);
    border-left: 4px solid var(--ok);
    border-radius: var(--radius-panel);
    background: #edf4ef;
    padding: 0.8rem 1rem;
}

.pay-amount {
    font-family: var(--mono);
    font-size: 1.35rem;
    font-weight: 700;
    line-height: 1.2;
    color: var(--ink);
    margin-bottom: 0.6rem;
}

/* Il numero è uno span proprio (il JS pre-avvio riscrive la sua text, mai
   il blocco): la resa è in linea, l'etichetta sotto. */
.pay-amount > span:first-child {
    display: block;
}

.pay-amount .pay-amount-lbl {
    display: block;
    font-family: var(--mono);
    font-size: 0.6875rem;
    font-weight: 500;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--ink-dim);
    margin-top: 0.15rem;
}

.pay-lines {
    display: grid;
    gap: 0.3rem;
}

.pay-line {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 0.25rem 0.75rem;
}

.pay-lbl {
    font-family: var(--mono);
    font-size: 0.6875rem;
    font-weight: 500;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--ink-dim);
    flex: none;
    min-width: 6.5rem;
}

.pay-val {
    min-width: 0;
    overflow-wrap: anywhere;
}

/* L'IBAN: monospace e selezionabile con un clic (user-select: all: la
   stringa intera è la selezione, zero mouse-drag), il palloncino lo dice. */
.pay-iban {
    font-family: var(--mono);
    font-weight: 600;
    user-select: all;
}

/* La causale: il testo da riportare, marcata e selezionabile come l'IBAN. */
.pay-causale {
    font-weight: 600;
    user-select: all;
}

/* Su schermi stretti i tre passi si impilano (la soglia del layout,
   l'economia dei box .renewal-stats). */
@media (max-width: 760px) {
    .rsteps {
        flex-direction: column;
    }
}

/* ── Pannello "Chiamata API": JSON di richiesta e risposta ── */

/* Il pannello è un <details> chiuso di default: il summary è il titolo
   toggle (stessa resa delle intestazioni .panel h2) e il triangolo di
   default suggerisce che si apre. */
.api-call > summary {
    cursor: pointer;
    margin: 0;
    font-family: var(--mono);
    font-size: 0.875rem;
    font-weight: 700;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: var(--accent-strong);
}

/* Il respiro sotto il titolo solo a pannello aperto: da chiuso il summary
   è l'unica riga e il margin-bottom sarebbe spazio vuoto in fondo. */
.api-call[open] > summary {
    margin-bottom: 0.7rem;
}

/* Riga di testata: pill di metodo, URL e status code della chiamata. */
.api-call .io-line {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.6rem;
}

.api-call .io-url {
    font-family: var(--mono);
    font-size: 0.8125rem;
    color: var(--ink);
    min-width: 0;
    overflow-wrap: anywhere;
}

/* Status code: lo stesso lessico cromatici ok/ko del resto della pagina. */
.api-call .io-status {
    font-family: var(--mono);
    font-size: 0.8125rem;
    font-weight: 700;
}

.api-call .io-status.is-ok {
    color: var(--ok);
}

.api-call .io-status.is-ko {
    color: var(--ko);
}

/* Etichette Richiesta/Risposta: come le intestazioni della tabella profilo. */
.api-call h3 {
    margin: 1rem 0 0.4rem;
    font-family: var(--mono);
    font-size: 0.6875rem;
    font-weight: 500;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--ink-dim);
}

.api-call h3:first-of-type {
    margin-top: 0.4rem;
}

/* Header di richiesta mostrati in chiaro (es. Authorization: Bearer ...). */
.api-call .io-header {
    margin: 0 0 0.5rem;
    font-family: var(--mono);
    font-size: 0.75rem;
    color: var(--ink-dim);
    overflow-wrap: anywhere;
}

/* Corpo JSON pretty-print: blocco dati su fondo campo, con token e UTF-8. */
.api-call pre.io-json {
    margin: 0 0 1rem;
    padding: 0.7rem 0.9rem;
    background: var(--field-bg);
    border: 1px solid var(--line);
    border-radius: var(--radius-control);
    font-family: var(--mono);
    font-size: 0.8125rem;
    line-height: 1.45;
    color: var(--accent-strong);
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}

.api-call .io-json:last-child {
    margin-bottom: 0;
}

/* ── «Chiamata API» come tab sul bordo sinistro (ogni pagina) ── */

/* In ogni pagina i pannelli "Chiamata API" stanno in una zona dedicata
   (div.api-tab-zone), sollevata sopra la pagina: una colonna di linguette
   fissa sul bordo sinistro, verticalmente centrata, che non occupa spazio
   nel flusso (una pagina con più chiamate, come anagrafica/index.php, ha più
   linguette). Il bordo sinistro perché a destra la tab interferirebbe con
   la scrollbar della pagina. */
.api-tab-zone {
    position: fixed;
    left: 0;
    top: 50%;
    transform: translateY(-50%);
    z-index: 30;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 0.6rem;
    max-width: min(30rem, 92vw);
}

/* Da chiusa ogni pannello è solo la sua testata, stretta come una
   linguetta; da aperta cresce verso il basso come pannello sollevato
   sopra la pagina (se alto, scrolla dentro). */
.api-tab-zone .api-call {
    margin: 0;
    border-left: none;
    border-radius: 0 var(--radius-panel) var(--radius-panel) 0;
    max-height: 90vh;
    overflow: auto;
}

.api-tab-zone .api-call:not([open]) {
    padding: 0.5rem 0.25rem;
}

/* Testata: da chiusa è una linguetta verticale, da aperta torna
   orizzontale (intestazione del pannello). */
.api-tab-zone .api-call > summary {
    writing-mode: vertical-rl;
}

.api-tab-zone .api-call[open] > summary {
    writing-mode: horizontal-tb;
}

/* ── «Torna in cima» (renderBackToTop: solo le pagine con elenchi lunghi) ── */

/* Cerotto circolare fisso in basso a destra, sollevato sopra la pagina. Lo
   z-index è quello della zona tab API (fissa ma sul bordo sinistro): gli due
   elementi non si toccano mai. Da spento è invisibile e non intercetta click
   (pointer-events: none): la classe .visible (messa da app.js a pagina
   scollata) lo rivela con una dissolvenza, che il blocco reduced-motion
   globale spegne da sola lasciando la comparsa secca. */
.back-to-top {
    position: fixed;
    right: 1.25rem;
    bottom: 1.25rem;
    z-index: 30;
    display: grid;
    place-items: center;
    width: 44px;
    height: 44px;
    border-radius: var(--radius-chip);
    background: var(--accent);
    color: var(--accent-ink);
    font-size: 1.25rem;
    font-weight: 600;
    line-height: 1;
    text-decoration: none;
    box-shadow: 0 2px 8px rgba(35, 46, 44, 0.28); /* fondo pieno: ombra più sostenuta del token flottante */
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    transition: opacity 0.2s ease, background 0.15s ease;
}

.back-to-top.visible {
    opacity: 1;
    visibility: visible;
    pointer-events: auto;
}

.back-to-top:hover {
    background: var(--accent-strong);
}

/* ── Accessibilità ── */

.btn:focus-visible,
.toggle-password:focus-visible,
.page-nav a:focus-visible,
.api-call summary:focus-visible,
.back-to-top:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}

/* Movimento ridotto: niente battiti né transizioni. */
@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        animation: none !important;
        transition: none !important;
    }
}

/* ── Schermi stretti: solo spazi più stretti (la colonna è già unica) ── */

@media (max-width: 760px) {
    .layout {
        gap: 1.25rem;
        padding: 1.25rem 1.25rem 3rem;
    }
}
