/* ===========================================================================
 * 5.0 M3 — CONSOLIDAMENTO: tokens.css e theme.css sono ORA UN FILE SOLO.
 *
 * Il contenuto qui sotto e' la CONCATENAZIONE ESATTA dei due, nello stesso
 * ordine in cui `inc/header.inc.php` li caricava (prima i token, poi il tema).
 * Non e' una riscrittura: nessuna regola e' stata tolta, spostata o riordinata,
 * quindi la cascata e' identica per costruzione e non puo' cambiare un pixel.
 * ⭐ E' il primo passo, non l'ultimo: unire i file e' cio' che RENDE POSSIBILE
 * togliere piu' avanti gli `!important` e le guerre di specificita' fra i due,
 * una regola per volta e con il gate a controllare.
 *
 * 🔴 `main.css` resta FUORI, di proposito. Fondere anche quello porterebbe via
 * il rollback di sola veste della 4.8 - commentare un <link> e il pannello
 * torna al look 4.7 senza toccare il markup - che e' una rete che si tiene.
 *
 * ⚠️ Il gate: peregoarredamenti.it/_DEVELOP/impronta-tema.js sul banco
 * theme-harness-5.0.html. Prima del merge (2026-08-22, 1440px, 1552 elementi):
 * chiaro `lb2nrf`, scuro `shqc99`. Dopo deve dare gli stessi.
 * Copie pre-merge in _ARCHIVE/{tokens,theme}.css.pre-merge-M3.
 * =========================================================================== */

/* ============================================================
   lcRaptor 4.8 "Veste Grafica" — DESIGN TOKENS
   ------------------------------------------------------------
   Sorgente: `_DEVELOP/ui-refresh/mockups/tokens.css` (export Claude Design,
   agosto 2026). Questo file è la COPIA DI LAVORO nel core: contiene solo
   variabili, nessuna regola sui componenti (quelle stanno in `theme.css`).

   ⚠️ NON scrivere qui hex o px "sparsi": se serve un valore nuovo, si aggiunge
   una variabile e la si porta anche nel file sorgente in `_DEVELOP/`, così una
   ri-esportazione da Claude Design non la perde.

   DELTA rispetto al file sorgente (documentati, sono gli unici):
   1. Il selettore del tema scuro era `[data-theme="dark"]`. Qui è
      `:root[data-theme=dark], :root[data-bs-theme=dark]`:
      - il prefisso `:root` è OBBLIGATORIO — la sidebar del pannello è un
        `<aside ... data-bs-theme="dark">` e senza `:root` le superfici scure
        piomberebbero dentro la sidebar anche a tema chiaro;
      - il doppio selettore serve perché il toggle (M2) marca `<html>` con
        ENTRAMBI gli attributi: `data-theme` pilota i nostri token,
        `data-bs-theme` fa scattare anche il ramo scuro nativo di Tabler.
   2. Aggiunti i tripletti `*-rgb`: Tabler compone diversi colori con
      `rgba(var(--tblr-primary-rgb), .x)` e le variabili CSS non sanno
      scomporre un hex.
   3. `--text-muted` scurito da #66767a a #637377. Il valore dei mockup è
      calcolato su fondo BIANCO (4.73:1), ma nel pannello vero il testo muted
      capita anche sullo sfondo applicazione `--surface-3` #f2f5f5, dove
      scendeva a 4.32:1 — sotto AA. #637377 tiene 4.94:1 su bianco e 4.51:1
      sul grigio, restando ben distinto da `--text-secondary`.
   4. Aggiunta la coppia `--danger-fill` / `--danger-fill-fg` per il bottone
      distruttivo PIENO. I mockup prevedono solo la variante testuale, ma il
      pannello usa `.btn-danger` pieno in 12 punti e il rosso "solid" (pensato
      per pallini e barre) con testo bianco dà 4.37:1. La coppia inverte
      polarità nel tema scuro, come già fa `--text-on-primary`.
   ============================================================ */

:root {
  /* ---------- Tipografia ---------- */
  --font-sans: "Inter Var", Inter, -apple-system, "Segoe UI", sans-serif;
  --font-mono: ui-monospace, SFMono-Regular, Menlo, monospace;
  --font-features: "cv05", "ss01";

  --text-2xs: 11px;    /* badge minimi, note */
  --text-xs: 11.5px;   /* intestazioni tabella, caption */
  --text-sm: 12.5px;   /* meta, label form, chip */
  --text-base: 13.5px; /* testo interfaccia, bottoni */
  --text-md: 14px;     /* titoli record in lista */
  --text-lg: 16px;     /* titolo editor, titoli card grandi */
  --text-xl: 19px;     /* h2 nel contenuto */
  --text-2xl: 23px;    /* numeri KPI piccoli */
  --text-3xl: 25px;    /* titolo pagina (h1) */
  --text-4xl: 30px;    /* numeri KPI dashboard */

  --weight-regular: 400;
  --weight-medium: 500;
  --weight-semibold: 600;

  --leading-tight: 1.3;
  --leading-normal: 1.5;
  --leading-relaxed: 1.65;

  --tracking-title: -0.5px;  /* h1 */
  --tracking-heading: -0.2px;
  --tracking-tight: -0.1px;  /* titoli record */
  --tracking-caps: 0.05em;   /* intestazioni tabella maiuscole */
  --tracking-caps-wide: 0.1em; /* label sezione sidebar */

  /* ---------- Superfici ---------- */
  --surface-1: #ffffff;   /* card, pannelli, topbar */
  --surface-2: #fafcfc;   /* header tabella, hover riga */
  --surface-3: #f2f5f5;   /* sfondo applicazione, hover icone */
  --surface-4: #eef2f2;   /* riempimento neutro, track barre */
  --surface-5: #e4ecec;   /* riempimento neutro forte */
  --surface-6: #d8e2e3;   /* placeholder, bordi pieni */
  --surface-7: #c6d0d1;   /* placeholder immagine */
  --surface-overlay: rgba(255,255,255,.93); /* header sticky con blur */
  /* ⚠️ `--surface-tabs` (pannello dietro le linguette del form) è stato RIMOSSO nella 4.9:
     l'area delle tab non è più una superficie, vedi la nota in theme.css. Il token non va
     reintrodotto senza ridiscutere quella scelta. */
  /* CodeMirror: nel tema CHIARO resta il oneDark della libreria (scelta storica, vedi la
     nota in theme.css), quindi questi due valori sono i suoi. */
  --cm-bg: #282c34;
  --cm-gutter-bg: #282c34;

  --accent-soft: #eef4f5;      /* chip e riquadri accento */
  --accent-soft-strong: #cfe4e7; /* selezione: dove il velo tenue non si distingue dal fondo */
  --success-soft: #e8f5ec;
  --warning-soft: #fdf3e4;
  --warning-soft-alt: #fdf1dc;
  --danger-soft: #fdeceb;

  /* ---------- Pastiglia SEO (5.0) ----------
     Fondo PIENO al posto del fondo tenue con inchiostro colorato che aveva fino alla 4.9:
     a corpo piccolo e su una riga fitta il fondo tenue si perdeva.
     ⚠️ Rosso e verde NON sono scelti a occhio: sono la piu' CHIARA di ciascuna tonalita'
     che regge il bianco sopra AA, calcolata, con un margine voluto sopra la soglia -
     4.5 e' un limite, non un obiettivo. Misurate: 5.01 e 5.04 su bianco.
     ⭐ Il giallo fa eccezione e porta INCHIOSTRO SCURO. Col bianco sopra, l'unico giallo
     ammesso era un #ad580d che di giallo non aveva piu' niente: era marrone. Girato il
     verso, la tinta torna un giallo vero (#f5c211) e il contrasto invece di essere il
     vincolo diventa abbondante: 10,31:1. ℹ️ L'inchiostro e' un nero CALDO, non #000, per
     restare nella famiglia della palette - a questo corpo la differenza non si vede.
     ⚠️ Il prezzo, dichiarato: nel tema CHIARO il giallo contro il bianco della riga sta a
     1,67:1, cioe' il PROFILO della pastiglia stacca poco (il TESTO no, quello sta a 10,31).
     Rosso e verde non hanno il problema, sono scuri di loro. E' lo stesso scambio che il
     tema scuro faceva al contrario (vedi il blocco scuro), e si accetta per la stessa
     ragione: la pastiglia non e' un comando e l'informazione sta nel testo.
     🚫 Provato e SCARTATO un filo di bordo interno in oro sulla sola gialla (`inset 0 0 0
     1px #a8790a`, che stava sopra 3:1 su entrambi i fondi): risolveva il profilo ma faceva
     della gialla l'unica pastiglia disegnata diversamente dalle altre due - una toppa piu'
     evidente del difetto. Se un giorno il profilo dovesse servire davvero, la strada e'
     quella, ma allora va data a tutte e tre.
     ℹ️ Il colore resta un RINFORZO: la pastiglia dice «SEO 74%» a parole, quindi chi non
     distingue rosso e verde legge comunque il numero. */
  --seo-bad-bg:    #cf352a;   /* 5.01:1 col bianco */
  --seo-warn-bg:   #f5c211;   /* 10.31:1 con --seo-warn-ink */
  --seo-ok-bg:     #187f47;   /* 5.04:1 col bianco */
  --seo-ink:       #ffffff;
  --seo-warn-ink:  #241a00;

  /* ---------- Bordi ---------- */
  --border: #dfe6e7;          /* controlli: bottoni, campi */
  --border-soft: #e2e8e9;     /* card, divisori topbar */
  --border-faint: #eef2f2;    /* separatori interni */
  --border-hairline: #f2f5f5; /* righe di lista */
  --border-hover: #b9c7c9;    /* hover bottone secondario, dashed */

  /* ---------- Testo ---------- */
  --text-heading: #0f1c1f;    /* h1, titoli card — 17.4:1 */
  --text-body: #16272b;       /* corpo editor — 15.5:1 */
  --text-strong: #28393d;     /* label form, voci menu — 12.1:1 */
  --text-default: #41565a;    /* icone topbar, testo forte — 7.8:1 */
  --text-secondary: #5c6c70;  /* descrizioni, sottotitoli — 5.5:1 */
  --text-muted: #637377;      /* meta, timestamp — 4.94:1 su bianco, 4.51:1 su --surface-3 (delta 3) */
  --text-faint: #8b9c9f;      /* solo icone e placeholder decorativi */
  --text-disabled: #9fb0b3;   /* placeholder campi, empty state */
  --text-decor: #b9c7c9;      /* maniglie drag, elementi non informativi */
  --text-on-accent: #ffffff;  /* testo su sidebar attiva / brand */
  --text-on-primary: #ffffff; /* testo dentro i bottoni primari */

  /* ---------- Accento (petrolio/teal) ---------- */
  --accent: #0c7d8a;           /* bottone primario, switch on, titoli record */
  --accent-hover: #0a6b77;
  --accent-brand: #0f8c9b;     /* logo */
  --accent-link: #0a6b77;      /* link testuali — 6.2:1 */
  --accent-link-hover: #084f58;
  --accent-text-soft: #2a5f68; /* testo dentro chip accento */
  --accent-bright: #3fc4d4;    /* icone su fondo sidebar */
  --focus-ring: #0a6b7722;     /* alone focus, usato a 3px */

  /* tripletti rgb (delta 2: servono a Tabler per gli alpha) */
  --accent-rgb: 12,125,138;
  --success-rgb: 15,122,69;
  --warning-rgb: 154,91,19;
  --danger-rgb: 185,58,43;
  --text-body-rgb: 22,39,43;
  --surface-1-rgb: 255,255,255;

  /* ---------- Semantici ---------- */
  --success: #0f7a45;        /* testo/badge ok */
  --success-solid: #12a150;  /* pallini, barre di stato */
  /* 5.0 (2026-08-24) — inchiostro da usare SOPRA `--success-solid`, gemello di
     `--warning-solid-ink` e per la stessa ragione: il verde pieno regge il bianco solo a
     3,37:1 nel chiaro e 2,86:1 nello scuro. Questo verde molto scuro dà 5,11:1 nel chiaro e
     6,03:1 nello scuro, quindi non si ridefinisce nel blocco dark. */
  --success-solid-ink: #06200e;
  --warning: #9a5b13;
  --warning-alt: #8a5a00;
  --warning-solid: #e2a53a;
  /* 5.0 M1 T3 — inchiostro da usare SOPRA `--warning-solid`. Serve perché l'ambra piena è
     chiara in ENTRAMBI i temi (#e2a53a e #d9a13c): il bianco ci sta sopra a 2,17:1, cioè
     illeggibile, mentre questo scuro dà 5,55:1 nel chiaro e 5,23:1 nello scuro. È quindi
     l'unico token che NON si ridefinisce nel blocco dark: il fondo non si inverte, e nemmeno
     il testo deve farlo. */
  --warning-solid-ink: #28393d;
  --danger: #b93a2b;         /* testo distruttivo, asterischi */
  --danger-alt: #c8492f;
  --danger-solid: #d24b3b;   /* pallino notifiche, barre */
  --danger-fill: #b93a2b;    /* fondo del bottone distruttivo pieno (delta 4) */
  --danger-fill-fg: #ffffff; /* testo dentro il bottone distruttivo — 5.67:1 */
  --info: #1a4fa0;
  --serp-url: #3d6b3d;       /* anteprima Google */

  /* ---------- Grafici ---------- */
  --chart-1: #7fb9c1;
  --chart-2: #dceef0;
  --chart-3: #bde2e7;
  --chart-4: #8fe1ec;

  /* ---------- Sidebar (superficie sempre scura) ---------- */
  --sidebar-bg: #063239;
  --sidebar-item: #aebdbf;          /* voce a riposo — 7.2:1 */
  --sidebar-item-strong: #c6d3d4;
  /* ⚠️ 4.9 (2026-08-07): il «4.9:1» vale sul FONDO della sidebar (`--sidebar-bg`). Dentro il
     riquadro `--sidebar-card` la misura è un'altra, e per la misura dello spazio disco stava a
     3,83:1 - sotto AA. Regola imparata: un token di testo va misurato su TUTTE le superfici su
     cui quel testo può finire, non solo su quella per cui è stato scelto. */
  --sidebar-label: #7fa0a3;         /* label di sezione — 4.9:1 sul fondo, 4.6:1 sulla card */
  --sidebar-muted: #7f9497;         /* footer, versione */
  --sidebar-hover: #0f4048;
  --sidebar-active: #1b494f;
  --sidebar-border: #315c62;
  --sidebar-border-hover: #41757c;
  /* ⚠️ Scurito il 2026-08-07 (era #0a444d) per portare la misura dello spazio disco da 3,83 a
     **4,63:1**. Il tetto è dato: sopra L≈0,0325 il testo non arriva ad AA, quindi qui non si
     può risalire. Effetto collaterale accettato: il riempimento stacca dal fondo sidebar 1,058
     invece di 1,278, cioè il riquadro si regge ora sul suo BORDO (1,76:1 su questo fondo) più
     che sulla campitura.
     🚫 NON copiare qui il valore del tema scuro (#073037): quel fondo è più scuro del fondo
     sidebar CHIARO (stacco 1,024), e il riquadro sparirebbe. Le due varianti hanno lo stesso
     rapporto card/fondo (~1,28 prima), ma partono da altezze diverse: è il fondo chiaro a
     stare più in alto, non la card a essere sbagliata. */
  --sidebar-card: #073640;          /* box spazio disco */
  --sidebar-track: #1b5b64;         /* track barra disco */
  --sidebar-avatar: #14383d;

  /* ---------- Campi form ---------- */
  --field-bg-filled: #f0f5f5;       /* variante adottata: fondo pieno */
  --field-border-filled: #d8e2e3;
  --field-border-outlined: #9db1b4; /* variante alternativa bordata */
  --switch-knob: #ffffff;

  /* ---------- Raggi ---------- */
  --radius-xs: 4px;    /* micro-badge, barre */
  --radius-sm: 6px;    /* badge, chip */
  --radius-md: 8px;    /* bottoni piccoli, voci menu */
  --radius-lg: 9px;    /* bottoni, campi, voci sidebar */
  --radius-xl: 11px;   /* dropdown, box informativi */
  --radius-2xl: 13px;  /* card e contenitori lista */
  --radius-pill: 99px; /* switch, pallini, avatar */

  /* ---------- Ombre ---------- */
  --shadow-sm: 0 1px 2px rgba(15,28,31,.10);          /* card sollevate */
  --shadow-md: 0 10px 28px rgba(15,28,31,.14);        /* dropdown, popover */
  --shadow-field-inset: inset 0 1.5px 3px rgba(15,28,31,.06);
  /* 2026-09-26 - le CARD si staccano dalla pagina: bordo un filo piu' scuro di --border-soft
     e un accenno d'ombra. Il fondo dei campi (#f0f5f5) e' quasi quello della pagina (#f2f5f5),
     quindi i campi sembravano bucare la pagina e non si capiva dove finisse una card. */
  --card-border: #d5dfe0;
  --shadow-card: 0 1px 2px rgba(15,28,31,.06), 0 2px 8px rgba(15,28,31,.05);
  --focus-shadow: 0 0 0 3px var(--focus-ring);

  /* ---------- Spaziature ---------- */
  --space-1: 4px;
  --space-2: 6px;
  --space-3: 8px;
  --space-4: 10px;
  --space-5: 12px;
  --space-6: 14px;
  --space-7: 16px;
  --space-8: 18px;
  --space-9: 20px;
  --space-10: 26px;

  --gap-inline: 7px;    /* icona + testo */
  --gap-control: 9px;   /* gruppi di bottoni */
  --gap-card: 14px;     /* dentro le card */
  --gap-section: 20px;  /* tra blocchi di pagina */

  /* ---------- Misure di layout ---------- */
  --sidebar-width: 252px;
  --aside-width: 302px;
  --content-max: 1440px;
  --topbar-height: 58px;
  --control-height: 38px;      /* bottoni e campi standard */
  --control-height-sm: 36px;
  --control-height-lg: 40px;   /* campi principali dell'editor */
  --icon-button-size: 34px;
  --page-padding: 26px;

  --switch-width: 40px;
  --switch-height: 24px;
  --switch-knob-size: 18px;
  --switch-width-sm: 38px;
  --switch-height-sm: 22px;
  --switch-knob-size-sm: 16px;

  --scrollbar-thumb: #cdd6d7;
  --transition: 120ms ease;
}

/* ============================================================
   TEMA SCURO — vedi delta 1 in testa al file per il perché del `:root`
   ============================================================ */
:root[data-theme="dark"],
:root[data-bs-theme="dark"] {
  --surface-1: #12292f;
  --surface-2: #17323a;
  --surface-3: #0b2126;
  --surface-4: #1b3a41;
  --surface-5: #21444c;
  --surface-6: #2a5058;
  --surface-7: #325c65;
  --surface-overlay: rgba(18,41,47,.93);
  /* (`--surface-tabs` era qui il piano rientrato #07161b: rimosso con la 4.9, vedi sopra.) */
  /* CodeMirror nel tema scuro: il fondo dell'editor entra nella famiglia teal del pannello
     invece di restare il grigio-blu di oneDark, che era l'unico blocco di un'altra palette
     in tutta la schermata. La grondaia resta il grigio della libreria: fa da riga di
     separazione fra i numeri e il codice. */
  --cm-bg: #082e36;
  --cm-gutter-bg: #282c34;

  --accent-soft: #103a42;
  --accent-soft-strong: #17515c;
  --success-soft: #12321f;
  --warning-soft: #33280f;
  --warning-soft-alt: #3a2c11;
  --danger-soft: #35201d;

  /* Pastiglia SEO: sul fondo scuro le due tinte a inchiostro bianco sembrano spente, quindi
     salgono di un gradino - restano sopra AA col bianco (4.72 · 4.73) e guadagnano stacco
     dalla superficie.
     ⚠️ Piu' chiare di cosi' non si puo' andare: il bianco scenderebbe sotto 4.5. Da qui
     nasce un limite di cui vale la pena essere consapevoli - il bordo della pastiglia
     contro `--surface-2` sta a 2,86:1, sotto i 3:1 che si chiederebbero a un COMPONENTE.
     Non e' una violazione: la pastiglia non e' un comando e l'informazione sta nel testo,
     che di contrasto ne ha 4,7. Con testo bianco imposto, le due cose non stanno insieme.
     ⭐ Il giallo NON e' qui di proposito: eredita il #f5c211 del tema chiaro. Essendo a
     inchiostro scuro non ha il vincolo degli altri due, e proprio per questo e' l'unico che
     il limite qui sopra non ce l'ha - contro `--surface-2` sta a 8,11:1. */
  --seo-bad-bg:  #d43a2f;
  --seo-ok-bg:   #198449;

  --border: #2b4c54;
  --border-soft: #26454c;
  --border-faint: #1f3d44;
  --border-hairline: #1a353b;
  --border-hover: #3d6d76;

  --text-heading: #eef6f7;
  --text-body: #e3eff0;
  --text-strong: #cddcde;
  --text-default: #b3c6c9;
  --text-secondary: #9bb0b3;
  --text-muted: #8ba1a5;
  --text-faint: #7b9296;
  --text-disabled: #6b8286;
  --text-decor: #567176;
  --text-on-accent: #ffffff;
  --text-on-primary: #04222a;   /* su accento chiaro serve testo scuro */

  --accent: #2ab0c0;
  --accent-hover: #3ec4d3;
  --accent-brand: #0f8c9b;
  --accent-link: #4fc9d8;
  --accent-link-hover: #8fe1ec;
  --accent-text-soft: #7fd2dd;
  --accent-bright: #3fc4d4;
  --focus-ring: #4fc9d833;

  --accent-rgb: 42,176,192;
  --success-rgb: 69,207,136;
  --warning-rgb: 230,178,90;
  --danger-rgb: 255,143,122;
  --text-body-rgb: 227,239,240;
  --surface-1-rgb: 18,41,47;

  --success: #45cf88;
  --success-solid: #2fae63;
  --warning: #e6b25a;
  --warning-alt: #d9a54a;
  --warning-solid: #d9a13c;
  --danger: #ff8f7a;
  --danger-alt: #ff8f7a;
  --danger-solid: #cf5240;
  --danger-fill: #ff8f7a;      /* nel dark il pieno si schiarisce e il testo diventa scuro */
  --danger-fill-fg: #2d0a05;
  --info: #86aef5;
  --serp-url: #86c58f;

  --chart-1: #2f7f8c;
  --chart-2: #12333a;
  --chart-3: #1c5561;
  --chart-4: #3fc4d4;

  --sidebar-bg: #04191d;
  --sidebar-item: #aebdbf;
  --sidebar-item-strong: #c6d3d4;
  --sidebar-label: #7fa0a3;
  --sidebar-muted: #7f9497;
  --sidebar-hover: #0c343a;
  --sidebar-active: #12454c;
  --sidebar-border: #23474e;
  --sidebar-border-hover: #41757c;
  /* ⚠️ Invariato il 2026-08-07: qui la misura dello spazio disco sta già a 5,02:1. È il tema
     CHIARO che è stato corretto (vedi la nota lassù), non questo. */
  --sidebar-card: #073037;
  --sidebar-track: #14454e;
  --sidebar-avatar: #0d3238;

  --field-bg-filled: #17323a;
  --field-border-filled: #2b4c54;
  --field-border-outlined: #3d6d76;
  --switch-knob: #eaf6f8;

  --shadow-sm: 0 1px 2px rgba(0,0,0,.40);
  --shadow-md: 0 12px 30px rgba(0,0,0,.50);
  --shadow-field-inset: inset 0 1.5px 3px rgba(0,0,0,.35);
  /* Nello scuro l'ombra si vede poco sul fondo quasi nero: a staccare la card e' soprattutto
     il BORDO, un filo piu' chiaro di --border-soft (#26454c). L'ombra resta un accenno. */
  --card-border: #325961;
  --shadow-card: 0 1px 2px rgba(0,0,0,.35), 0 2px 8px rgba(0,0,0,.25);

  --scrollbar-thumb: #2a5058;
}


/* ===========================================================================
 * ⬇️ Da qui in giu' e' il vecchio theme.css, invariato.
 * =========================================================================== */

/* ============================================================
   lcRaptor 4.8 "Veste Grafica" — TEMA DEL PANNELLO (M1)
   ------------------------------------------------------------
   Si carica DOPO `tabler.min.css`, `tabler-themes.min.css` e `main.css`.
   Due sezioni:
     A) BRIDGE — rimappa le variabili `--tblr-*` sui token di `tokens.css`.
        È il pezzo che fa il 90% del salto visivo: Tabler è interamente
        pilotato da variabili (anche bottoni e card), quindi la maggior parte
        dei ~63 act si riveste senza toccarne il markup.
     B) COMPONENTI — passata mirata dove il bridge non basta perché Tabler
        cabla il valore nella regola invece di leggerlo da una variabile.

   ⚠️ REGOLA: qui NON si scrivono colori/misure letterali, solo `var(--token)`.
   Le uniche eccezioni sono i valori di layout che i token non prevedono
   (es. hit-area di un'icona), sempre commentate.

   ⚠️ `!important`: usato SOLO dove `main.css` (storico, non si tocca in questa
   milestone) ha già un `!important` che vincerebbe. Ogni occorrenza è marcata
   con «neutralizza main.css». Rollback della veste = togliere i 2 `<link>`
   di tokens.css/theme.css da `inc/header.inc.php`.
   ============================================================ */


/* ════════════════════════════════════════════════════════════
   A) BRIDGE — token → variabili Tabler
   ════════════════════════════════════════════════════════════ */

:root {
	/* --- Tipografia ------------------------------------------------ */
	--tblr-font-sans-serif: var(--font-sans);
	--tblr-body-font-family: var(--font-sans);
	--tblr-font-monospace: var(--font-mono);
	--tblr-body-font-size: var(--text-base);
	--tblr-body-font-weight: var(--weight-regular);
	--tblr-body-line-height: var(--leading-normal);
	--tblr-font-weight-headings: var(--weight-semibold);

	/* --- Superfici e testo ----------------------------------------- */
	--tblr-body-bg: var(--surface-3);
	--tblr-body-color: var(--text-body);
	--tblr-body-color-rgb: var(--text-body-rgb);
	--tblr-emphasis-color: var(--text-heading);
	--tblr-heading-color: var(--text-heading);

	--tblr-bg-surface: var(--surface-1);
	--tblr-bg-surface-primary: var(--surface-1);
	--tblr-bg-surface-secondary: var(--surface-2);
	/* ⚠️ main.css punta `--tblr-bg-surface-tertiary` a #e8f4f5 per colorare
	   `.alert-info`. Qui la variabile torna a essere una SUPERFICIE vera e
	   l'alert viene ricolorato per conto suo più sotto (sezione Alert). */
	--tblr-bg-surface-tertiary: var(--surface-3);
	--tblr-bg-forms: var(--field-bg-filled);

	--tblr-secondary: var(--text-muted);
	--tblr-secondary-color: var(--text-muted);
	--tblr-muted: var(--text-muted);
	--tblr-tertiary-color: var(--text-secondary);
	--tblr-tertiary-bg: var(--surface-4);

	/* --- Accento ---------------------------------------------------- */
	/* Vince su `[data-bs-theme-primary=cyan]` di tabler-themes.min.css:
	   stessa specificità (0,1,0) ma questo file è caricato dopo. */
	--tblr-primary: var(--accent);
	--tblr-primary-rgb: var(--accent-rgb);
	--tblr-primary-fg: var(--text-on-primary);
	--tblr-primary-darken: var(--accent-hover);
	--tblr-primary-lt: var(--accent-soft);

	--tblr-link-color: var(--accent-link);
	--tblr-link-hover-color: var(--accent-link-hover);
	--tblr-link-color-rgb: var(--accent-rgb);
	--tblr-link-decoration: none;
	--tblr-link-hover-decoration: underline;

	/* --- Semantici -------------------------------------------------- */
	--tblr-success: var(--success-solid);
	--tblr-success-rgb: var(--success-rgb);
	--tblr-warning: var(--warning-solid);
	--tblr-warning-rgb: var(--warning-rgb);
	--tblr-danger: var(--danger-solid);
	--tblr-danger-rgb: var(--danger-rgb);
	--tblr-info: var(--info);
	--tblr-green: var(--success-solid);
	--tblr-red: var(--danger-solid);
	--tblr-yellow: var(--warning-solid);
	--tblr-teal: var(--accent);
	--tblr-cyan: var(--accent);

	/* PIASTRE TONALI `bg-*-lt` (2° giro di collaudo, 2026-08-02). Il bridge mappava
	   solo `--tblr-primary-lt`: le altre restavano al default di Tabler, cioè un VELO
	   al 10% del colore pieno. Due conseguenze, misurate sul banco:
	     · il velo si SOMMA a quello del contenitore (badge tonale dentro riquadro
	       tonale: fondo più saturo del previsto e testo sotto AA);
	     · la tinta usciva dal solid, non dai token `*-soft` che il design ha proprio
	       per «chip e riquadri» → banner del semaforo SEO a 4.43:1.
	   Con tinte OPACHE il velo non si somma più e la piastra è quella disegnata. */
	--tblr-success-lt: var(--success-soft);
	--tblr-green-lt: var(--success-soft);
	--tblr-lime-lt: var(--success-soft);
	--tblr-warning-lt: var(--warning-soft);
	--tblr-yellow-lt: var(--warning-soft);
	--tblr-orange-lt: var(--warning-soft);
	--tblr-danger-lt: var(--danger-soft);
	--tblr-red-lt: var(--danger-soft);
	--tblr-azure-lt: var(--accent-soft);
	--tblr-blue-lt: var(--accent-soft);
	--tblr-cyan-lt: var(--accent-soft);
	--tblr-teal-lt: var(--accent-soft);
	--tblr-secondary-lt: var(--surface-4);
	--tblr-muted-lt: var(--surface-4);
	--tblr-purple-lt: var(--surface-4);
	--tblr-indigo-lt: var(--surface-4);
	--tblr-pink-lt: var(--surface-4);

	/* --- Bordi e raggi ---------------------------------------------- */
	--tblr-border-color: var(--border-soft);
	--tblr-border-color-translucent: var(--border-soft);
	--tblr-border-width: 1px;
	--tblr-border-radius: var(--radius-lg);
	--tblr-border-radius-sm: var(--radius-sm);
	--tblr-border-radius-md: var(--radius-md);
	--tblr-border-radius-lg: var(--radius-2xl);   /* card */
	--tblr-border-radius-xl: var(--radius-xl);
	--tblr-border-radius-2xl: var(--radius-2xl);
	--tblr-border-radius-pill: var(--radius-pill);

	/* --- Ombre e focus ---------------------------------------------- */
	/* 2026-09-26 - le card hanno un ACCENNO d'ombra (`--shadow-card`): col solo bordo si
	   confondevano coi campi, che hanno quasi il colore della pagina. Chi non la vuole la
	   toglie da se' (i blocchi `rap-form-plain` lo fanno gia'). */
	--tblr-shadow-card: var(--shadow-card);
	--tblr-box-shadow-sm: var(--shadow-sm);
	--tblr-box-shadow: var(--shadow-md);
	--tblr-box-shadow-lg: var(--shadow-md);
	--tblr-shadow-border: inset 0 0 0 1px var(--border-soft);
	--tblr-focus-ring-color: var(--focus-ring);

	/* --- Stati ------------------------------------------------------ */
	--tblr-active-bg: var(--accent-soft);
	--tblr-border-active-color: var(--accent);
}


/* ════════════════════════════════════════════════════════════
   B) COMPONENTI
   ════════════════════════════════════════════════════════════ */

/* --- Base ------------------------------------------------------- */

body {
	font-feature-settings: var(--font-features);
	color: var(--text-body);
	background-color: var(--surface-3);
}

a { transition: color var(--transition); }

h1, h2, h3, h4, h5, h6,
.h1, .h2, .h3, .h4, .h5, .h6 {
	color: var(--text-heading);
	font-weight: var(--weight-semibold);
	letter-spacing: var(--tracking-heading);
}

/* Il pannello marca i testi secondari con .text-muted: nel design è il
   grigio AA (4.7:1), non un grigio decorativo. */
.text-muted { color: var(--text-muted) !important; }   /* neutralizza main.css (.text-muted di Tabler è già !important) */
.small, small { font-size: var(--text-sm); }

/* Utility semantiche di TESTO (2° giro di collaudo, 2026-08-02).
   Il bridge punta `--tblr-success/warning/danger` ai token `*-solid`, che il design
   destina a PALLINI e BARRE: come inchiostro sono troppo chiari. Tabler 1.4 risolve
   `.text-danger` con `color-mix(in srgb, var(--tblr-danger) …)`, quindi eredita il
   solid e non i tripletti `--*-rgb` (che il bridge aveva già portati sull'inchiostro
   giusto: la regola vecchia di Tabler li usava, quella nuova no → la correzione era
   inerte). Misurato sul banco, tema chiaro:
       .text-warning 1.85:1 · .text-success 2.76:1 · .text-danger 3.51:1
   Riguarda tutta la checklist SEO (percentuali e titoli di ogni voce), la card GEO e
   la card qualità: schermate che il primo giro non aveva guardato. Qui le utility
   tornano sui token d'inchiostro; i fondi pieni restano sui `*-solid`. */
.text-success, .text-green, .text-lime { color: var(--success) !important; }
.text-warning, .text-yellow, .text-orange { color: var(--warning) !important; }
.text-danger, .text-red { color: var(--danger) !important; }

/* Testo secondario sopra una PIASTRA TONALE (`bg-*-lt`) o sulla piastra grigia
   dell'anteprima immagine: il grigio muted è tarato sulle superfici neutre e su un
   fondo colorato scende sotto AA (3.97:1 sul riquadro "qualità redazionale", 4.38:1
   sul segnaposto "Nessuna immagine selezionata"). Lì si usa il grigio forte, che
   resta comunque un secondario. */
.bg-success-lt .text-muted, .bg-warning-lt .text-muted, .bg-danger-lt .text-muted,
.bg-primary-lt .text-muted, .bg-secondary-lt .text-muted, .bg-azure-lt .text-muted,
.bg-blue-lt .text-muted, .bg-orange-lt .text-muted, .bg-green-lt .text-muted,
.bg-yellow-lt .text-muted, .bg-red-lt .text-muted, .bg-teal-lt .text-muted,
.bg-cyan-lt .text-muted,
.rap-media-pv .text-muted { color: var(--text-default) !important; }   /* neutralizza .text-muted qui sopra */

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

*:focus-visible {
	outline: none;
	box-shadow: var(--focus-shadow);
	border-color: var(--accent);
}


/* --- Radice: il rientro della barra di scorrimento (4.8) --------- */
/* 🐛 SPAZIO FRA SIDEBAR E BARRA IN ALTO (segnalato 2026-08-04).
   Tabler dichiara, sopra i 992px:
       :host, :root { margin-left: calc(100vw - 100%); margin-right: 0 }
   È il vecchio trucco anti-salto dei siti a colonna centrata: aggiunge alla RADICE
   un margine pari alla larghezza della barra di scorrimento, così la pagina non
   sobbalza quando la barra compare. In una shell da applicazione fa danno:
   - la sidebar è `position: fixed; left: 0` → si misura sul VIEWPORT e quel margine
     non la tocca, resta incollata al bordo;
   - la barra in alto e `.page-wrapper` sono nel flusso → partono già spostati, e il
     `margin-left: 15rem` di Tabler li porta a 15rem **più** la barra di scorrimento.
   Risultato: una fessura fra il bordo destro della sidebar e la barra in alto, larga
   quanto la barra di scorrimento (10px con la nostra, 15px con quella di sistema).
   Non è un difetto della veste: c'è da quando il pannello è su Tabler, la 4.8 lo rende
   solo più visibile perché la sidebar è scura e lo stacco si vede.
   Qui il margine si azzera e al suo posto si RISERVA la colonna della barra di
   scorrimento (`scrollbar-gutter: stable`): niente fessura a sinistra e niente
   sobbalzo quando si passa da una pagina corta a una lunga - che era il motivo per cui
   Tabler aveva messo quel margine. Dove `scrollbar-gutter` non c'è (Safari < 17) si
   torna al comportamento di prima del trucco: allineato, con un possibile salto di
   10px fra pagine di altezza diversa. */
@media (min-width: 992px) {
	:root {
		margin-left: 0;
		scrollbar-gutter: stable;
	}
}


/* --- Sidebar ---------------------------------------------------- */
/* ⚠️ `!important`: main.css impone `background-color:#023f48 !important`
   sulla `.navbar-vertical`. Finché quel file resta com'è (scelta di
   milestone: rollback = togliere i link), qui serve pari forza. */
.navbar-vertical {
	background-color: var(--sidebar-bg) !important;   /* neutralizza main.css */
	border-right: 0;
}

.navbar-vertical .navbar-nav .nav-link {
	color: var(--sidebar-item);
	font-size: var(--text-base);
	font-weight: var(--weight-medium);
	border-radius: var(--radius-lg);
	padding: 9px 11px;
	margin-bottom: 2px;
	transition: background-color var(--transition), color var(--transition);
}

.navbar-vertical .navbar-nav .nav-link:hover {
	background-color: var(--sidebar-hover);
	color: var(--text-on-accent);
}

.navbar-vertical .navbar-nav .nav-link.active,
.navbar-vertical .navbar-nav .nav-item.active > .nav-link {
	background-color: var(--sidebar-active);
	color: var(--text-on-accent);
	font-weight: var(--weight-semibold);
}

.navbar-vertical .navbar-nav .nav-link .nav-link-icon,
.navbar-vertical .nav-link-icon .ti { opacity: .85; }

.navbar-vertical .navbar-nav .nav-link.active .nav-link-icon,
.navbar-vertical .navbar-nav .nav-link.active .ti { color: var(--accent-bright); opacity: 1; }

/* ⚠️ SOTTOMENU DELLA SIDEBAR (gruppo Utenti, moduli con più voci): si aprono a
   fisarmonica DENTRO la sidebar scura, quindi devono seguire i colori della sidebar,
   non quelli del dropdown chiaro.
   🐛 Segnalato dall'utente il 2026-08-02 (hover bianco su bianco). Causa: la regola
   generica `.dropdown-item:hover` di questo file (0,2,0) portava lo sfondo CHIARO, ma
   Tabler impone `color: inherit` con
   `.navbar-vertical.navbar-expand .navbar-collapse .dropdown-menu .dropdown-item` (0,5,0),
   che vince → il testo restava BIANCO, ereditato dalla sidebar. Serve superare quella
   specificità; `:not(.rap-settings-pinned)` esclude la voce Impostazioni ancorata, il cui
   menu invece fluttua su fondo chiaro ed è già trattato più sotto. */
.navbar-vertical.navbar-expand-lg .navbar-collapse .nav-item:not(.rap-settings-pinned) .dropdown-item {
	color: var(--sidebar-item);
	border-radius: var(--radius-md);
	padding: 7px 11px;
}
.navbar-vertical.navbar-expand-lg .navbar-collapse .nav-item:not(.rap-settings-pinned) .dropdown-item:hover,
.navbar-vertical.navbar-expand-lg .navbar-collapse .nav-item:not(.rap-settings-pinned) .dropdown-item:focus {
	background-color: var(--sidebar-hover);
	color: var(--text-on-accent);
}
.navbar-vertical.navbar-expand-lg .navbar-collapse .nav-item:not(.rap-settings-pinned) .dropdown-item.active {
	background-color: var(--sidebar-active);
	color: var(--text-on-accent);
	font-weight: var(--weight-semibold);
}
/* Il menu a fisarmonica non è una superficie a sé: niente fondo, bordo o ombra */
.navbar-vertical.navbar-expand-lg .navbar-collapse .nav-item:not(.rap-settings-pinned) .dropdown-menu {
	background-color: transparent;
	border: 0;
	box-shadow: none;
	padding: 0 0 0 var(--space-6);
}

/* Etichette di sezione (voci .disabled del menu, vedi make_menu) */
.navbar-vertical .nav-link.disabled {
	color: var(--sidebar-label);
	font-size: 10.5px;                       /* fuori scala token: è l'unica label micro */
	font-weight: var(--weight-semibold);
	letter-spacing: var(--tracking-caps-wide);
	text-transform: uppercase;
	padding: 14px 10px 6px;
}

/* ⚠️ Tabler tiene la sidebar a `overflow-y: scroll` FISSO: la barra di scorrimento è
   sempre riservata anche quando il menu ci sta tutto, e su Windows con le barre "classiche"
   restano le due frecce senza cursore in mezzo - sembrano un comando, non lo sono.
   Con `auto` compaiono solo quando servono davvero (menu lungo, finestra bassa). */
.navbar-vertical.navbar-expand-lg { overflow-y: auto; }

/* ⚠️ BOTTONI "Inserisci nuovo" / "Crea una nuova categoria" (segnalato 2026-08-02).
   Il markup di ~10 punti del core porta `btn btn-primary d-sm-inline-block`: quella
   utility vale `display: inline-block !important` e SCAVALCA l'`inline-flex` di `.btn`.
   Senza flex, icona e testo tornano ad allinearsi sulla LINEA DI BASE invece che sull'asse
   verticale, e la scritta esce dal centro del bottone - il difetto è sempre esistito, la
   veste nuova (bottoni più alti e arrotondati) lo rende evidente.
   Si corregge qui e non nei 10 file perché così vale anche per il markup dei SITI (act e
   hook di modulo), che dal core non si raggiunge. `!important` è l'unico modo di battere
   un'utility Bootstrap, che lo usa a sua volta; il selettore è il più stretto possibile. */
.btn.d-sm-inline-block { display: inline-flex !important; }

/* --- Marchio in cima alla sidebar (4.8) -------------------------- */

/* ⚠️ Il padding va scritto ricalcando il selettore di Tabler
   (`.navbar-vertical.navbar-expand .navbar-brand { padding: .75rem 0; justify-content: center }`,
   specificità 0,3,0): una `.rap-brand` da sola non lo raggiunge e il marchio resta
   incollato ai bordi - misurato, il segno partiva da 0 e la pastiglia arrivava a filo.
   I 16px orizzontali NON sono un valore a caso: è il rientro delle icone delle voci di menu
   (`.nav-link` ha padding 8px 16px), quindi il segno cade sulla stessa colonna della prima
   icona sotto. */
.navbar-vertical.navbar-expand-lg .navbar-brand.rap-brand {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: var(--gap-inline);
	width: 100%;
	padding: 12px 16px;
	margin: 0;
}
.rap-brand-link {
	display: flex;
	align-items: center;
	gap: var(--gap-inline);
	min-width: 0;
	text-decoration: none;
}
/* Il segno arriva come MASCHERA: il file è una silhouette nera, il colore lo mette il CSS
   e segue il tema. Doppia dichiarazione col prefisso -webkit- per i Safari non recenti. */
.rap-brand-mark {
	flex: 0 0 auto;
	width: 38px; height: 38px;
	border-radius: var(--radius-lg);
	background-color: var(--sidebar-avatar);
	position: relative;
}
.rap-brand-mark::before {
	content: "";
	position: absolute;
	inset: 7px;
	background-color: var(--accent-bright);
	-webkit-mask: url("../img/mark-raptor.svg") center / contain no-repeat;
	mask: url("../img/mark-raptor.svg") center / contain no-repeat;
}
.rap-brand-name {
	font-size: var(--text-xl);
	font-weight: var(--weight-semibold);
	letter-spacing: var(--tracking-heading);
	color: var(--sidebar-item-strong);
	white-space: nowrap;
}
/* Pastiglia della versione: porta al changelog, quindi si comporta da comando (hover) */
.rap-brand-ver {
	margin-left: auto;
	flex: 0 0 auto;
	padding: 2px 8px;
	border: 1px solid var(--sidebar-border);
	border-radius: var(--radius-pill);
	font-size: var(--text-2xs);
	font-weight: var(--weight-semibold);
	line-height: 1.5;
	color: var(--sidebar-item);
	text-decoration: none;
}
a.rap-brand-ver:hover,
a.rap-brand-ver:focus {
	border-color: var(--sidebar-border-hover);
	color: var(--accent-bright);
}
/* 6.2 (2026-10-12, segnalato da Luca guardando il pannello dal telefono): sotto lg la testata
   della sidebar e' una riga flessibile che va a capo, e col `width: 100%` qui sopra il marchio
   non ci stava accanto al pulsante del menu: pulsante da solo sulla prima riga, marchio sotto.
   Dalla 4.8 in poi, cioe' da quando il marchio non e' piu' un'immagine stretta. Qui prende lo
   spazio che resta accanto al pulsante; il menu aperto (`.navbar-collapse`, base 100%) va
   comunque sotto, a tutta larghezza. Sopra lg non cambia niente.
   Cucitura #19, solo 6.2 (decisione di Luca): la flotta la riceve col giro della 6.2. */
@media (max-width: 991.98px) {
	.navbar-vertical.navbar-expand-lg .navbar-brand.rap-brand {
		width: auto;
		flex: 1 1 0;
		min-width: 0;
		padding: 8px 0 8px 12px;
	}
}

/* --- Zona bassa della sidebar (4.8 M2) --------------------------- */

.rap-sidebar-foot { padding: 0 12px 4px; }

/* Impostazioni ancorata: stessi stati delle altre voci, ma incorniciata — è un
   comando di servizio, non una destinazione come i moduli (COMPONENTS.md). */
.rap-sidebar-settings { margin-bottom: var(--space-3); }
.rap-settings-pinned > .nav-link {
	border: 1px solid var(--sidebar-border);
	border-radius: var(--radius-lg);
	margin-bottom: 0;
}
.rap-settings-pinned > .nav-link:hover { border-color: var(--sidebar-border-hover); }
.rap-settings-pinned > .nav-link.active { border-color: var(--sidebar-border-hover); }
/* L'ingranaggio porta il colore di accento anche a riposo (nei mockup è così): in fondo a
   una colonna di icone tutte grigie è il modo più rapido per ritrovarlo. Le altre voci lo
   accendono solo da attive, quindi il colore resta un segnale, non decorazione diffusa. */
.rap-settings-pinned > .nav-link .nav-link-icon,
.rap-settings-pinned > .nav-link .ti { color: var(--accent-bright); opacity: 1; }

/* ⚠️ Tabler rende i sottomenu della sidebar INLINE e trasparenti
   (`.navbar-vertical.navbar-expand-lg .navbar-collapse .dropdown-menu{position:static;background:initial}`):
   è giusto per i gruppi in mezzo all'elenco, che si aprono a fisarmonica, ma non per la
   voce ancorata in FONDO — aprendosi in giù finirebbe fuori dallo schermo (misurato:
   727px su una viewport di 720). Qui il menu torna a fluttuare e si apre verso l'ALTO.
   Il selettore ricalca quello di Tabler + `.rap-settings-pinned` per superarlo in
   specificità senza ricorrere a `!important`. */
.navbar-vertical.navbar-expand-lg .navbar-collapse .rap-settings-pinned .dropdown-menu {
	position: absolute;
	inset: auto auto 100% 0;
	min-width: 100%;
	margin-bottom: var(--space-2);
	background-color: var(--surface-1);
	border: 1px solid var(--border-soft);
	border-radius: var(--radius-xl);
	box-shadow: var(--shadow-md);
	padding: var(--space-2);
}
/* Dentro il menu fluttuante valgono i colori del dropdown, non quelli della sidebar:
   la sidebar tinge di bianco tutto ciò che sta al suo interno (è scura), e su un menu a
   fondo chiaro darebbe bianco-su-bianco — misurato. Stessa scala di specificità di sopra. */
.navbar-vertical.navbar-expand-lg .navbar-collapse .rap-settings-pinned .dropdown-item {
	color: var(--text-strong);
	border-radius: var(--radius-md);
	padding: 8px 11px;
}
.navbar-vertical.navbar-expand-lg .navbar-collapse .rap-settings-pinned .dropdown-item:hover,
.navbar-vertical.navbar-expand-lg .navbar-collapse .rap-settings-pinned .dropdown-item:focus {
	background-color: var(--surface-3);
	color: var(--text-heading);
}
.navbar-vertical.navbar-expand-lg .navbar-collapse .rap-settings-pinned .dropdown-item.active {
	background-color: var(--accent-soft);
	color: var(--accent-text-soft);
}
.navbar-vertical.navbar-expand-lg .navbar-collapse .rap-settings-pinned .dropdown-item .ti { color: var(--text-secondary); }

/* Piede della sidebar: versione, Changelog e firma su UNA riga, SENZA filetto sopra (la
   riga di separazione è stata tolta il 2026-08-02: la zona bassa è già staccata dal
   riquadro Impostazioni, e il filetto la faceva sembrare un secondo piede).
   `white-space: nowrap` è il punto: senza, in una colonna da 252px l'ultima voce va a capo
   da sola e sembra un errore di impaginazione. Se un giorno non ci stesse più (traduzione
   lunga, versione a tre cifre) si vedrebbe subito, invece di degradare in silenzio. */
.rap-sidebar-credits {
	/* Nessun padding orizzontale: la riga è già dentro i 12px di `.rap-sidebar-foot` e va a
	   filo del riquadro Impostazioni. Lo spazio serve tutto: a 12,5px (la misura che `small`
	   si porta da Tabler) la riga stava a 208px contro 206 disponibili e finiva in ellissi. */
	padding: 8px 0 2px;
	font-size: var(--text-2xs);
	color: var(--sidebar-muted);
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}
/* ⚠️ `small` in Tabler ha una misura ASSOLUTA (`--tblr-font-size-sm`, 12,5px), quindi non
   eredita quella del contenitore: senza questa riga la riga del piede resta a 12,5px e
   sfora comunque - misurato, 208px contro 206 disponibili. */
.rap-sidebar-credits small { font-size: inherit; }
.rap-sidebar-credits a { color: var(--sidebar-item); text-decoration: none; }
.rap-sidebar-credits a:hover { color: var(--accent-bright); text-decoration: underline; }

/* Box spazio disco.
   4.8 (2026-08-04): allineato ai mockup ora che APCu è attiva e il riquadro si vede
   davvero. Tre righe - icona+titolo, barra, misura - invece di titolo+percentuale e
   barra. Il bordo è quello della voce "Impostazioni" qui sopra: nei mockup i due
   riquadri in fondo alla sidebar sono la stessa famiglia, e con il solo fondo pieno
   il box si perdeva sul blu scuro. */
.rap-disk-box {
	background: var(--sidebar-card);
	border: 1px solid var(--sidebar-border);
	border-radius: var(--radius-xl);
	padding: 12px;
	margin-bottom: var(--space-3);
}
.rap-disk-head {
	display: flex;
	align-items: center;
	gap: var(--space-3);
	margin-bottom: var(--space-3);
	font-size: var(--text-sm);
	font-weight: var(--weight-medium);
	color: var(--sidebar-item-strong);
}
/* L'icona porta l'accento, come nei mockup: è l'unico colore del riquadro insieme al
   riempimento della barra, e lega le due cose. In bianco pesava quanto il titolo e il
   box diventava una fila di grigi. */
.rap-disk-head .ti { font-size: 18px; color: var(--accent-bright); flex: 0 0 auto; }
.rap-disk-meas {
	margin-top: var(--space-2);
	font-size: var(--text-xs);
	color: var(--sidebar-label);   /* il grigio AA della famiglia sidebar (4.9:1) */
}
.rap-disk-track {
	height: 5px;
	border-radius: var(--radius-pill);
	background: var(--sidebar-track);
	overflow: hidden;
}
.rap-disk-fill { height: 100%; border-radius: var(--radius-pill); background: var(--accent-bright); }
.rap-disk-fill.is-alert { background: var(--danger-solid); }

.navbar-vertical .border-top { border-color: var(--sidebar-border) !important; }   /* neutralizza .border-top di Tabler */
/* Footer della sidebar: `--sidebar-muted` (il token previsto per «footer, versione»)
   dà 4.32:1 sul fondo scuro, sotto AA. Si usa `--sidebar-label`, che è il grigio
   AA della stessa famiglia (4.9:1) — misurato sul DOM il 2026-08-01. */
.navbar-vertical .mt-auto small { color: var(--sidebar-label); }
.navbar-vertical .mt-auto a { color: var(--sidebar-item); }
.navbar-vertical .mt-auto a:hover { color: var(--accent-bright); }


/* --- Topbar ----------------------------------------------------- */

.navbar:not(.navbar-vertical) {
	background-color: var(--surface-1);
	border-bottom: 1px solid var(--border-soft) !important;   /* neutralizza .border-bottom di Tabler */
	min-height: var(--topbar-height);
}

/* Pill del sito: pallino di stato + dominio + icona "apri" a destra (COMPONENTS.md) */
.rap-site-pill {
	display: inline-flex;
	align-items: center;
	gap: var(--gap-inline);
	border: 1px solid var(--border);
	border-radius: var(--radius-md);
	padding: 5px 10px 5px 9px;
	font-size: var(--text-sm);
	font-weight: var(--weight-medium);
	color: var(--text-strong);
	text-decoration: none;
	transition: border-color var(--transition), color var(--transition);
}
.rap-site-pill:hover { border-color: var(--accent); color: var(--accent-link); }
.rap-site-dot {
	width: 6px; height: 6px;              /* misura del pallino, fuori scala token */
	border-radius: var(--radius-pill);
	background: var(--success-solid);
	flex: 0 0 auto;
}
/* Sito in manutenzione: lo dice il pallino, senza entrare in Impostazioni */
.rap-site-dot.is-off { background: var(--warning-solid); }
.rap-site-go { font-size: 15px; color: var(--text-muted); }
.rap-site-pill:hover .rap-site-go { color: var(--accent-link); }

/* Icone della barra (campanella, aiuto): quadrato con area di clic vera, non icone
   appoggiate. ⚠️ Il lato è **40px e non i 34 di COMPONENTS.md**: Tabler dà alle
   `.nav-link` un `min-height:40px` che detta il ritmo verticale della barra, e il
   `min-height` batte sempre l'`height`. Invece di combatterlo lo si dichiara, così la
   misura è nostra e prevedibile e le icone restano allineate col menu utente accanto.
   Il colore pieno (non `text-muted` come prima) è ciò che nei mockup le fa leggere più
   decise: la differenza percepita era quella, non il diametro. */
.navbar:not(.navbar-vertical) .rap-topbar-icon {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 40px;  min-width: 40px;
	height: 40px; min-height: 40px;
	padding: 0 !important;                /* neutralizza .px-1/.p-1 di Tabler */
	border-radius: var(--radius-lg);
	color: var(--text-default);
}
.navbar:not(.navbar-vertical) .rap-topbar-icon .ti { font-size: 19px; }
.navbar:not(.navbar-vertical) .rap-topbar-icon:hover { background-color: var(--surface-3); color: var(--text-heading); }

/* --- Menu utente (4.8 M2) ---------------------------------------- */

.rap-user-menu > .nav-link { border-radius: var(--radius-md); padding: 4px 8px 4px 4px !important; }   /* neutralizza .p-1 di Tabler */
.rap-user-menu > .nav-link:hover { background-color: var(--surface-3); }

.rap-avatar {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 28px; height: 28px;              /* misura d'avatar, fuori scala token */
	border-radius: var(--radius-pill);
	background: var(--sidebar-avatar);
	color: var(--chart-4);
	font-size: var(--text-xs);
	font-weight: var(--weight-semibold);
	letter-spacing: .02em;
	flex: 0 0 auto;
}

.rap-user-name { font-size: var(--text-sm); color: var(--text-body); font-weight: var(--weight-medium); }
.rap-user-caret { font-size: 15px; color: var(--text-muted); }

.rap-user-dropdown { min-width: 216px; }
.rap-user-head {
	padding: 4px 11px 9px;
	margin-bottom: var(--space-1);
	border-bottom: 1px solid var(--border-faint);
}
.rap-user-head-name { font-size: var(--text-sm); font-weight: var(--weight-semibold); color: var(--text-heading); }
.rap-user-head-role { font-size: var(--text-sm); color: var(--text-muted); }

/* Le voci portano un'icona a sinistra: allineamento e colore uniformi */
.rap-user-dropdown .dropdown-item { display: flex; align-items: center; gap: var(--gap-inline); width: 100%; text-align: left; border: 0; background: transparent; }
.rap-user-dropdown .dropdown-item > .ti { font-size: 17px; color: var(--text-secondary); flex: 0 0 auto; }
.rap-user-dropdown .rap-item-danger { color: var(--danger); }
.rap-user-dropdown .rap-item-danger > .ti { color: var(--danger); }
.rap-user-dropdown .rap-item-danger:hover { background-color: var(--danger-soft); color: var(--danger); }
.rap-user-dropdown .rap-item-danger:hover > .ti { color: var(--danger); }

/* Icone e nome utente a destra */
.navbar:not(.navbar-vertical) .nav-link,
.navbar:not(.navbar-vertical) .navbar-nav > a {
	color: var(--text-default);
	border-radius: var(--radius-lg);
	transition: background-color var(--transition), color var(--transition);
}
.navbar:not(.navbar-vertical) .nav-link:hover,
.navbar:not(.navbar-vertical) .navbar-nav > a:hover {
	background-color: var(--surface-3);
	color: var(--text-heading);
}


/* --- Intestazione di pagina -------------------------------------- */

/* ⚠️ 4.9 — ARIA SOTTO IL TITOLO. Tabler scrive `.page-wrapper .page-header { margin:
   var(--tblr-page-padding-y) 0 0 }`: una **shorthand** a specificità (0,2,0) che azzera il
   margine SOTTO e batte qualunque `.page-header` singolo (0,1,0). Qui c'era per l'appunto un
   `.page-header { margin-bottom: … }` che **non ha mai avuto effetto**: il titolo restava
   incollato a ciò che veniva dopo. Non si vedeva sulle liste dei moduli solo perché lì sotto
   c'è la riga di riepilogo `.rap-list-sub`, che si portava un margine sopra tutto suo; si
   vedeva su tutte le altre (elenco prodotti col box "Nascondi obsoleti" dell'hook di sito,
   promo col bottone "Aggiorna scadenze", commenti con l'avviso, statistiche, richieste
   prezzi, redirect: segnalate dal campo il 2026-08-07).
   Si ricalca il selettore di Tabler, senza `!important`.
   ⚠️ Il margine SOPRA resta quello di Tabler, che è ciò che la flotta ha sempre visto: qui si
   aggiunge soltanto l'aria che mancava sotto. */
.page-wrapper .page-header { margin-bottom: var(--space-7); }

/* Form di un record (moduli con `form_blocks`): l'intestazione di pagina è VUOTA perché il
   titolo lo porta la barra del form (vedi `$_is_record_form` in inc/header.inc.php). Tabler
   però dà a `.page-header` un `min-height: 2.25rem` - 36px di contenitore vuoto che, sommati
   ai 24 del margine, staccavano la barra di 60px dalla barra in alto. Qui l'altezza va a
   zero e resta il solo margine, cioè lo stesso stacco di ogni altra schermata.
   Specificità (0,2,0): serve a battere il `.page-header` di Tabler.
   ⚠️ E niente margine sotto: il contenitore è vuoto, quindi la barra del form deve partire
   dove parte il titolo di ogni altra schermata. Selettore a (0,3,0) per stare sopra la regola
   qui sopra a prescindere dall'ordine nel file. */
.page-header.rap-page-header-form { min-height: 0; }
.page-wrapper .page-header.rap-page-header-form { margin-bottom: 0; }

.page-title {
	font-size: var(--text-3xl);
	line-height: 1.2;
	font-weight: var(--weight-semibold);
	letter-spacing: var(--tracking-title);
	color: var(--text-heading);
}

.page-subtitle { color: var(--text-secondary); font-size: var(--text-base); }

/* Briciole di pane sopra il titolo, nei soli moduli (4.8). Il separatore è un'icona
   `aria-hidden`: chi usa uno screen reader sente le voci, non i chevron. */
.rap-crumbs {
	display: flex;
	align-items: center;
	gap: var(--space-1);
	margin-bottom: var(--space-2);
	font-size: var(--text-sm);
	color: var(--text-muted);
}
.rap-crumbs a { color: var(--text-secondary); text-decoration: none; }
.rap-crumbs a:hover { color: var(--accent-link); text-decoration: underline; }
.rap-crumb-sep { font-size: 14px; color: var(--text-decor); }

/* Riga di riepilogo sotto il titolo delle liste ("12 record · 8 attivi"). Vive nel corpo
   della pagina e non nell'intestazione, perché i numeri li conosce solo l'azione.
   ⚠️ Il margine sopra ha una storia: prima NEGATIVO (per riavvicinarla al titolo), poi
   positivo perché sul pannello vero le due righe finivano appiccicate. Dal 2026-08-07 è di
   nuovo ZERO, e stavolta è giusto: l'aria sotto al titolo la dà l'intestazione di pagina
   (vedi `.page-wrapper .page-header` sopra), che finalmente ce l'ha davvero. Rimetterlo
   qui sommerebbe due stacchi e la riga di riepilogo starebbe più bassa di ogni altro
   contenuto di prima riga. */
.rap-list-sub {
	margin: 0 0 var(--gap-section);
	font-size: var(--text-sm);
	color: var(--text-muted);
}
.page-body { margin-top: 0; }


/* --- Card -------------------------------------------------------- */

/* L'ombra la porta il bridge (`--tblr-shadow-card: var(--shadow-card)`, che è la
   variabile letta da `.card`): NON si dichiara qui un `box-shadow`, sennò si litiga con
   chi l'ombra la vuole diversa (es. la card del login, `.shadow-sm`).
   2026-09-26 - bordo `--card-border` e non piu' `--border-soft`: vedi i token. */
.card {
	background-color: var(--surface-1);
	border: 1px solid var(--card-border);
	border-radius: var(--radius-2xl);
}

.card-header {
	background-color: transparent;
	border-bottom: 1px solid var(--border-faint);
	padding: 15px 18px;
	min-height: auto;
}

.card-title {
	font-size: var(--text-md);
	font-weight: var(--weight-semibold);
	color: var(--text-heading);
	letter-spacing: var(--tracking-tight);
}

.card-subtitle { font-size: var(--text-sm); color: var(--text-secondary); }
.card-footer { background-color: transparent; border-top: 1px solid var(--border-faint); }

/* Titoletti maiuscoli usati nelle preview record (main.css ne fissa la scala) */
.card-body h5.text-uppercase { color: var(--text-secondary); letter-spacing: var(--tracking-caps); }


/* --- Tabelle e righe di lista ------------------------------------ */

.table {
	--tblr-table-bg: transparent;
	--tblr-table-color: var(--text-body);
	--tblr-table-border-color: var(--border-hairline);
	--tblr-table-hover-bg: var(--surface-2);
	--tblr-table-striped-bg: var(--surface-2);
	font-size: var(--text-base);
}

.table thead th,
.card-table thead th {
	background-color: var(--surface-2);
	border-bottom: 1px solid var(--border-faint);
	color: var(--text-secondary);
	font-size: var(--text-xs);
	font-weight: var(--weight-semibold);
	letter-spacing: var(--tracking-caps);
	text-transform: uppercase;
	padding: 10px 18px;
}

/* ⚠️ `.table-light` (usata per evidenziare una riga, es. "DB lcRaptor" nella dashboard)
   porta un fondo CHIARO cablato: nel tema scuro restava chiaro col testo chiaro sopra,
   2.6:1. Rimappata sulle nostre superfici, così segue il tema come tutto il resto. */
.table-light {
	--tblr-table-color: var(--text-body);
	--tblr-table-bg: var(--surface-2);
	--tblr-table-border-color: var(--border-hairline);
	--tblr-table-striped-bg: var(--surface-2);
	--tblr-table-hover-bg: var(--surface-3);
}

.table td { border-bottom-color: var(--border-hairline); }
.table tbody tr:last-child td { border-bottom: 0; }
.table-hover tbody tr:hover td { background-color: var(--surface-2); }

/* Titolo del record: nel design è il link accento, non il grigio opaco.
   Stessa specificità della regola di main.css, ma questo file viene dopo. */
/* `.rap-row-title` sta accanto al selettore per figlio diretto perché nell'elenco pagine
   il titolo è annidato nel div dell'indentazione e restava a 13,5px/400, cioè più smilzo
   dei titoli record dei moduli. Stessa riga, stesso peso, ovunque. */
.card-table td > a,
.card-table td .rap-row-title {
	color: var(--accent);
	font-size: var(--text-md);
	font-weight: var(--weight-semibold);
	letter-spacing: var(--tracking-tight);
	opacity: 1;
	text-decoration: none;
}
.card-table td > a:hover,
.card-table td .rap-row-title:hover { color: var(--accent-hover); text-decoration: underline; opacity: 1; }

/* Parola con tooltip (chi ha inserito / chi ha modificato, elenco pagine): il tratteggio
   è l'unico segnale che c'è qualcosa da leggere sotto il puntatore. */
.rap-meta-who { text-decoration: underline dotted; text-underline-offset: 2px; cursor: help; }

/* Le colonne azioni restano icone neutre: il colore accento è del titolo */
.card-table td.w-1 > a,
.card-table td.text-end > a { color: var(--text-default); }
.card-table td.w-1 > a:hover,
.card-table td.text-end > a:hover { color: var(--text-heading); text-decoration: none; }
.card-table td > a .ti-trash { color: var(--danger); }
.card-table td > a .ti-plus  { color: var(--success); }

/* Lista unificata: la scheda delle categorie parte alla stessa altezza della TABELLA e non
   del titolo "Categoria X" che la precede nella colonna di sinistra. I 40px compensano
   quel titolo (riga + `mb-3`), che esiste solo a sinistra. ⚠️ Solo da `lg` in su: sotto
   quella soglia le colonne sono impilate e il margine sarebbe uno spazio vuoto in mezzo. */
@media (min-width: 992px) {
	.rap-unified .rap-cat-sidebar { margin-top: 40px; }
}

/* --- Riga record: miniatura in testa e cella unica delle azioni (4.8) ------ */

/* Miniatura davanti al nome. `contain` e non `cover`: nei moduli della flotta questa
   colonna ospita tanto ritratti quanto LOGHI di marchi, e ritagliarli al quadrato li
   sfigurerebbe. Chi non ha immagine mostra le iniziali. */
/* Misure alzate il 2026-08-02 (erano 40px di altezza e 72 di larghezza massima): a quella
   taglia una foto di persona era un francobollo e un logo di marchio illeggibile. La
   colonna ha un minimo di 100px così i titoli restano incolonnati anche fra righe con
   immagini di forma diversa. */
.rap-row-thumb { width: 1%; min-width: 100px; text-align: center; padding-right: 0 !important; }
/* Se in TUTTA la tabella nessuna cella miniatura ha contenuto, la colonna sparisce - riga
   di intestazione compresa, sennò l'allineamento salta (segnalato 2026-08-02 sull'elenco
   categorie di lcPhotos, dove le immagini di categoria non ci sono mai e restava una
   colonna bianca da 100px).
   ⚠️ Il test è su `*` e non su `img`: nelle liste dei RECORD la cella contiene le iniziali
   di ripiego, che sono un contenuto vero e devono tenere in piedi la colonna. */
table:not(:has(td.rap-row-thumb > *)) .rap-row-thumb,
table:not(:has(td.rap-row-thumb > *)) .rap-row-thumb-h { display: none; }
.rap-row-thumb img {
	height: 60px; width: auto; max-width: 100px;
	object-fit: contain;
	border-radius: var(--radius-md);
	background-color: var(--surface-3);
}
.rap-row-ini {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 60px; height: 60px;
	border-radius: var(--radius-md);
	background-color: var(--surface-3);
	color: var(--text-secondary);
	font-size: var(--text-base);
	font-weight: var(--weight-semibold);
	letter-spacing: .02em;
}

/* Cella unica delle azioni: icone accostate, NEUTRE a riposo e colorate solo al passaggio
   del mouse. Il selettore prende `a` diretto e non una classe, così vale anche per i link
   che arrivano dagli HOOK dei siti (es. l'anteprima delle landing di fw), che dal core non
   si raggiungono. */
.rap-row-actions { width: 1%; white-space: nowrap; text-align: right; }
/* ⚠️ Il selettore ricalca quello del tema per le celle (`.card-table td > a`, che vale
   (0,1,2)): una `.rap-row-actions a` da sola perde per un elemento e le icone restavano
   color accento a riposo, cioè esattamente ciò che si voleva togliere. */
/* ⚠️ 5.0 M2 — dal passaggio della cancellazione a POST il comando non e' piu' un `a` ma un
   `button`, e le regole qui sotto - scritte per i link, come dice il commento sopra - non lo
   incrociavano affatto: il cestino usciva col bordo e lo sfondo predefiniti del browser, cioe'
   un pulsante squadrato in mezzo a icone piatte.
   🔴 2026-08-22 — ED E' RICAPITATO, per una ragione che vale la pena ricordare. La prima
   correzione aveva scritto i selettori come `form.rap-confirm > button`, perche' allora il
   bottone stava DENTRO il suo form, nella cella. Poi il fix dei form annidati (report `713`)
   ha STACCATO il form - ora si stampa dopo `</form>` e il bottone lo raggiunge con
   `form="<id>"` - e il bottone e' rimasto figlio diretto della cella. Ogni selettore che
   pretendeva l'antenato ha smesso di incrociarlo, in silenzio, e il bordo e' tornato.
   ⭐ Ora i selettori chiedono SOLO `button` dentro `.rap-row-actions`: valgono sia col form
   attorno sia senza, quindi non si rompono di nuovo se il markup si sposta ancora.
   ⚠️ Il form NON si tocca con `display`: `rap_confirm_form()` gli mette `d-inline`, che in
   Bootstrap e' `display: inline !important` - qualunque regola nostra qui perderebbe.
   Il bottone invece viene azzerato (`border`/`background`/`font`) e riceve lo stesso vestito
   dei link. */
.card-table td.rap-row-actions > button,
.rap-row-actions button {
	border: 0;
	background: none;
	font: inherit;
	cursor: pointer;
}
.card-table td.rap-row-actions > a,
.card-table td.rap-row-actions > button,
.rap-row-actions a,
.rap-row-actions button {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-width: 32px; height: 32px;
	padding: 0 var(--space-1);
	border-radius: var(--radius-md);
	color: var(--text-default);
	text-decoration: none;
}
.card-table td.rap-row-actions > a:hover,
.card-table td.rap-row-actions > a:focus-visible,
.card-table td.rap-row-actions > button:hover,
.card-table td.rap-row-actions > button:focus-visible,
.rap-row-actions a:hover,
.rap-row-actions a:focus-visible,
.rap-row-actions button:hover,
.rap-row-actions button:focus-visible {
	background-color: var(--surface-3);
	color: var(--accent-brand);
	text-decoration: none;
}
.card-table td.rap-row-actions > a.is-danger:hover,
.card-table td.rap-row-actions > a.is-danger:focus-visible,
.card-table td.rap-row-actions > button.is-danger:hover,
.card-table td.rap-row-actions > button.is-danger:focus-visible,
.rap-row-actions a.is-danger:hover,
.rap-row-actions a.is-danger:focus-visible,
.rap-row-actions button.is-danger:hover,
.rap-row-actions button.is-danger:focus-visible { background-color: var(--danger-soft); color: var(--danger); }
/* ⚠️ Il cestino era rosso SEMPRE (regola qui sopra, `.card-table td > a .ti-trash`): nella
   cella unica le icone devono essere tutte neutre, sennò il rosso attira l'occhio su ogni
   riga come se fosse l'azione principale. Si colora al passaggio del mouse, come le altre. */
.card-table td.rap-row-actions > a .ti-trash,
.card-table td.rap-row-actions > button .ti-trash,
.rap-row-actions a .ti-trash,
.rap-row-actions button .ti-trash { color: inherit; }
/* Azione non disponibile (inserimento vietato, categoria non cancellabile): stessa
   impronta delle altre icone ma spenta e senza reazione al mouse. Sparire non va bene:
   la riga perderebbe l'allineamento e l'azione sembrerebbe non esistere affatto. */
.rap-row-actions .rap-act.is-off {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-width: 32px; height: 32px;
	/* `--text-faint` e non `--text-disabled`: un comando disattivato è esente dalla soglia
	   di contrasto, ma col grigio più chiaro scendeva a 2,25:1 e spariva - prima di questa
	   riscrittura stava intorno a 4,5. Deve leggersi come spento, non come assente. */
	color: var(--text-faint);
	cursor: default;
}
.rap-row-actions .rap-act.is-off .ti { color: inherit; }

.rap-act-count {
	margin-left: 2px;
	font-size: var(--text-2xs);
	font-weight: var(--weight-semibold);
	color: var(--text-muted);
}

/* --- Interruttore di stato in lista (4.8 blocco B) ----------------------- */

.rap-status-cell { white-space: nowrap; }
/* Data sotto l'interruttore: sta su una riga sua, piccola e tenue - è un'informazione, non
   un comando. "programmata" prende il colore d'avviso perché quel record NON è ancora
   visibile al pubblico anche se l'interruttore è acceso. */
.rap-status-when {
	display: block;
	margin-top: var(--space-1);
	font-size: var(--text-2xs);
	color: var(--text-muted);
	white-space: nowrap;
}
.rap-status-when.is-sched { color: var(--warning); }
.rap-status-when .ti { font-size: 12px; vertical-align: -1px; margin-right: 3px; }
.rap-status {
	display: inline-flex;
	align-items: center;
	gap: var(--gap-inline);
	cursor: pointer;
	padding: 0;
	min-height: 0;
}
.rap-status .form-check-input { margin: 0; float: none; cursor: pointer; }
/* `.form-check-label` di Tabler vale (0,1,0) come la nostra: si stringe il selettore,
   sennò l'etichetta "Bozza" resta col nero del corpo invece del grigio secondario. */
.rap-status .rap-status-label { font-size: var(--text-sm); color: var(--text-secondary); }
.rap-status .form-check-input:checked + .rap-status-label { color: var(--success); }
.rap-status .form-check-input:disabled { opacity: .55; }
/* Rifiuto dal server: la cella lampeggia in rosso e il `title` dice perché. Senza un
   segnale, un interruttore che torna indietro da solo sembra un bug del pannello. */
.rap-status-cell.is-error .rap-status-label { color: var(--danger); }
.rap-status-cell.is-error { background-color: var(--danger-soft); border-radius: var(--radius-md); }

/* Pastiglia SEO accanto al titolo del record (sostituisce pallino + percentuale grigia).
   Il testo dice "SEO" a parole, quindi il colore è un rinforzo e non l'unica informazione:
   chi non distingue verde e arancione legge comunque la percentuale. */
.rap-seo-pill {
	display: inline-block;
	margin-left: var(--space-2);
	padding: 1px 7px;
	border-radius: var(--radius-sm);
	font-size: var(--text-2xs);
	font-weight: var(--weight-semibold);
	letter-spacing: .02em;
	white-space: nowrap;
	vertical-align: 1px;
	font-variant-numeric: tabular-nums;
}
.rap-seo-pill.is-ok   { background-color: var(--seo-ok-bg);   color: var(--seo-ink); }
/* ⚠️ L'unica delle tre con inchiostro scuro: e' cio' che tiene il giallo un giallo vero
   invece del marrone che serviva a reggere il bianco. Vedi i token in testa al file. */
.rap-seo-pill.is-warn { background-color: var(--seo-warn-bg); color: var(--seo-warn-ink); }
.rap-seo-pill.is-bad  { background-color: var(--seo-bad-bg);  color: var(--seo-ink); }
/* `--text-muted` su `--surface-4` dava 4,38:1, sotto la soglia: serve l'inchiostro più scuro */
.rap-seo-pill.is-none { background-color: var(--surface-4);    color: var(--text-secondary); }

.table td small.text-muted { font-size: var(--text-sm); color: var(--text-muted) !important; }   /* neutralizza .text-muted */

.card-table img { border-radius: var(--radius-xl); background-color: var(--surface-4); }

/* 🐛 Angoli in alto della card quadrati quando la tabella parte SUBITO sotto (senza
   intestazione di scheda): la riga di testata ha un fondo grigino e lo dipingeva fin dentro
   lo spigolo arrotondato. Segnalato 2026-08-02. Si arrotondano le due celle d'angolo invece
   di mettere `overflow:hidden` sul contenitore, che è in scorrimento orizzontale e
   taglierebbe le tabelle larghe. */
.card > .table-responsive:first-child .card-table thead tr:first-child th:first-child { border-top-left-radius: var(--radius-2xl); }
.card > .table-responsive:first-child .card-table thead tr:first-child th:last-child  { border-top-right-radius: var(--radius-2xl); }

.ordertd .ti { color: var(--text-decor); }


/* --- Bottoni ----------------------------------------------------- */

.btn {
	--tblr-btn-border-radius: var(--radius-lg);
	font-size: var(--text-base);
	font-weight: var(--weight-semibold);
	min-height: var(--control-height);
	padding: 0 16px;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: var(--gap-inline);
	transition: background-color var(--transition), border-color var(--transition), color var(--transition);
}

.btn-sm,
.btn-group-sm > .btn {
	min-height: var(--control-height-sm);
	padding: 0 13px;
	font-size: var(--text-sm);
}
/* 6.2 (2026-10-12, segnalato da Luca nella griglia della libreria media): un pulsante di sola
   icona con `py-0 px-1` veniva alto 36px (l'altezza minima qui sopra) e largo ~26, cioe' piu'
   alto che largo. `rap-btn-quadro` lo fa quadrato all'altezza del suo controllo. Cucitura #19,
   solo 6.2. */
.btn.rap-btn-quadro {
	width: var(--control-height);
	min-width: var(--control-height);
	padding: 0;
}
.btn.btn-sm.rap-btn-quadro {
	width: var(--control-height-sm);
	min-width: var(--control-height-sm);
}

/* Primario: pieno accento. `--tblr-primary-fg` porta il testo scuro nel dark. */
.btn-primary { box-shadow: none; }

/* Secondario: nel design è bianco col bordo, non grigio pieno */
.btn-secondary {
	--tblr-btn-bg: var(--surface-1);
	--tblr-btn-color: var(--text-strong);
	--tblr-btn-border-color: var(--border);
	--tblr-btn-hover-bg: var(--surface-2);
	--tblr-btn-hover-color: var(--text-heading);
	--tblr-btn-hover-border-color: var(--border-hover);
	--tblr-btn-active-bg: var(--surface-3);
	--tblr-btn-active-color: var(--text-heading);
	--tblr-btn-active-border-color: var(--border-hover);
	box-shadow: none;
}

.btn-outline-secondary {
	--tblr-btn-color: var(--text-strong);
	--tblr-btn-border-color: var(--border);
	--tblr-btn-hover-bg: var(--surface-2);
	--tblr-btn-hover-color: var(--text-heading);
	--tblr-btn-hover-border-color: var(--border-hover);
}

/* Distruttivo pieno: `--danger-solid` è il rosso di pallini e barre e col testo
   bianco si ferma a 4.37:1. Qui serve la coppia dedicata (vedi delta 4 dei token). */
.btn-danger {
	--tblr-btn-bg: var(--danger-fill);
	--tblr-btn-color: var(--danger-fill-fg);
	--tblr-btn-hover-bg: var(--danger-fill);
	--tblr-btn-hover-color: var(--danger-fill-fg);
	--tblr-btn-active-bg: var(--danger-fill);
	--tblr-btn-active-color: var(--danger-fill-fg);
	--tblr-btn-border-color: transparent;
	box-shadow: none;
}
.btn-danger:hover { filter: brightness(.92); }

/* 5.0 (2026-08-24) — AMBRA E VERDE PIENI: mancava l'inchiostro, e senza si EREDITA.
   Trovato provando dal vivo la A2: il bottone «Torna amministratore» vive dentro la fascia
   `.alert-warning`, quindi ereditava il testo ambra di quella e finiva a 1,19:1 nel tema
   scuro - illeggibile, e per giunta è la via d'uscita dalla simulazione. Fuori dalla fascia
   non andava meglio: il testo chiaro del pannello su ambra piena dà 2,20:1 (2,08:1 nel
   chiaro), il verde pieno 2,73:1 (3,22:1). `--tblr-btn-color` non era mai stato dichiarato
   per queste due varianti, mentre primary e danger ce l'hanno - ed è per questo che loro
   stavano a 6,37:1 e 8,18:1 e queste no.
   ⚠️ Il giro visivo della M7 non poteva vederlo: nessuna delle 15 schermate misurate
   contiene un `.btn-warning` o un `.btn-success`. Vanno aggiunti al banco.
   Misure con gli inchiostri dedicati: ambra 5,55:1 chiaro / 5,23:1 scuro · verde 5,11:1
   chiaro / 6,03:1 scuro. */
.btn-warning {
	--tblr-btn-bg: var(--warning-solid);
	--tblr-btn-color: var(--warning-solid-ink);
	--tblr-btn-hover-bg: var(--warning-solid);
	--tblr-btn-hover-color: var(--warning-solid-ink);
	--tblr-btn-active-bg: var(--warning-solid);
	--tblr-btn-active-color: var(--warning-solid-ink);
	--tblr-btn-border-color: transparent;
	box-shadow: none;
}
.btn-warning:hover { filter: brightness(.92); }

.btn-success {
	--tblr-btn-bg: var(--success-solid);
	--tblr-btn-color: var(--success-solid-ink);
	--tblr-btn-hover-bg: var(--success-solid);
	--tblr-btn-hover-color: var(--success-solid-ink);
	--tblr-btn-active-bg: var(--success-solid);
	--tblr-btn-active-color: var(--success-solid-ink);
	--tblr-btn-border-color: transparent;
	box-shadow: none;
}
.btn-success:hover { filter: brightness(.92); }

.btn-outline-danger {
	--tblr-btn-color: var(--danger);
	--tblr-btn-border-color: var(--danger);
	--tblr-btn-hover-bg: var(--danger-soft);
	--tblr-btn-hover-color: var(--danger);
	--tblr-btn-hover-border-color: var(--danger);
}

/* ⚠️ UNICO punto in cui Tabler cabla un colore invece di leggerlo da una
   variabile: `.btn-link{color:rgb(7,124,234)}` (blu, letterale). Il bridge non
   può raggiungerlo — verificato sul DOM il 2026-08-01: `--tblr-btn-color` era
   già corretto ma il `color` vinceva. Serve la dichiarazione esplicita. */
.btn-link {
	--tblr-btn-color: var(--accent-link);
	--tblr-btn-hover-color: var(--accent-link-hover);
	color: var(--accent-link);
	font-weight: var(--weight-semibold);
}
.btn-link:hover, .btn-link:focus { color: var(--accent-link-hover); }

.btn:disabled, .btn.disabled { opacity: .5; cursor: not-allowed; }
.btn-close { color: var(--text-muted); }


/* --- Badge ------------------------------------------------------- */

.badge {
	border-radius: var(--radius-sm);
	padding: 2px 7px;
	font-size: var(--text-2xs);
	font-weight: var(--weight-semibold);
	line-height: 1.45;
}

/* I badge del design sono a FONDO TENUE con testo colorato, non pieni
   (COMPONENTS.md: «mai bordi: il colore del fondo distingue lo stato»).
   Non è solo estetica — i pieni di Tabler col testo quasi bianco sono sempre stati
   illeggibili, misurato sul DOM il 2026-08-01 con e senza questo tema:
       warning/yellow 2.04:1 · success 2.63:1 · danger 4.46:1
       secondary 1.00:1  ← grigio su grigio, invisibile
   Con la ricetta tenue tutti salgono sopra AA. Il `!important` neutralizza le utility
   `.bg-*`/`.text-*-fg` di Tabler, che lo portano già. Scoped a `.badge`: barre di
   avanzamento e altri usi di `.bg-*` restano pieni.

   ⚠️ Le varianti `-lt` vanno elencate INSIEME alle piene (2° giro di collaudo,
   2026-08-02). Il pannello le usa - `bg-orange-lt` sul badge "password legacy",
   `bg-danger-lt` sui segnali della card qualità, `bg-secondary-lt` sui conteggi della
   sidebar categorie - e senza queste righe restavano ai valori di Tabler: fondo a
   velo del 10% che si SOMMA a quello del contenitore quando il badge sta dentro una
   piastra tonale (2.73:1 il badge arancio, 3.11:1 quello rosso dentro il riquadro
   rosso). Col fondo pieno tenue il velo non si somma più. */
/* Il viola del log modifiche (`ed_changes`: badge "AI" e "content_edit") non ha un
   token: la tavolozza del design si ferma ad accento + 3 semantici + neutri. Diventa
   il badge NEUTRO - a 4.22:1 nel chiaro e 2.92:1 nello scuro non era leggibile - e la
   distinzione con "User" resta, perché quello è accento e l'etichetta lo dice. */
.badge.bg-secondary, .badge.bg-secondary-lt,
.badge.bg-muted, .badge.bg-muted-lt,
.badge.bg-purple, .badge.bg-purple-lt,
.badge.bg-indigo, .badge.bg-indigo-lt,
.badge.bg-pink, .badge.bg-pink-lt {
	background-color: var(--surface-4) !important;
	color: var(--text-secondary) !important;
}
.badge.bg-success, .badge.bg-green, .badge.bg-lime,
.badge.bg-success-lt, .badge.bg-green-lt, .badge.bg-lime-lt {
	background-color: var(--success-soft) !important;
	color: var(--success) !important;
}
.badge.bg-warning, .badge.bg-yellow, .badge.bg-orange,
.badge.bg-warning-lt, .badge.bg-yellow-lt, .badge.bg-orange-lt {
	background-color: var(--warning-soft) !important;
	color: var(--warning) !important;
}
.badge.bg-danger, .badge.bg-red,
.badge.bg-danger-lt, .badge.bg-red-lt {
	background-color: var(--danger-soft) !important;
	color: var(--danger) !important;
}
.badge.bg-primary, .badge.bg-blue, .badge.bg-azure, .badge.bg-cyan, .badge.bg-teal,
.badge.bg-primary-lt, .badge.bg-blue-lt, .badge.bg-azure-lt, .badge.bg-cyan-lt, .badge.bg-teal-lt {
	background-color: var(--accent-soft) !important;
	color: var(--accent-text-soft) !important;
}

/* 5.0 M1 T3 — LA PASTIGLIA «OBSOLETO», UNICO BADGE PIENO DEL PANNELLO.
   È un'eccezione dichiarata alla regola qui sopra («i badge sono a fondo tenue»), e la
   ragione è il posto in cui vive: sta su una RIGA GIÀ TINTA (i siti che usano `old` la
   colorano d'ambra), cioè proprio il caso che la ricetta tenue non regge - è lo stesso
   «velo che si somma» descritto nel commento sopra, ma portato all'estremo: un badge
   `--warning-soft` su una riga `--warning-soft` semplicemente sparisce, e col badge neutro
   (primo tentativo, 2026-08-21) si legge poco perché il grigio su fondo ambra si smorza.
   Fondo `--warning-solid`, che è la stessa ambra del resto del pannello. Il testo NON può
   essere bianco: misurato, 2,17:1 nel chiaro. `--warning-solid-ink` dà 5,55:1 nel chiaro e
   5,23:1 nello scuro - l'ambra piena è chiara in entrambi i temi, quindi l'inchiostro
   scuro va bene in tutti e due e il token non si ridefinisce. */
.badge.rap-badge-old {
	background-color: var(--warning-solid);
	color: var(--warning-solid-ink);
}

/* 2026-09-26 — LA CATEGORIA PRINCIPALE nella lista di una categoria: seconda eccezione
   dichiarata ai badge tenui. Compare sui record che stanno nella categoria aperta solo come
   SECONDARIA (`rap_cat_row_badges()`, `inc/cat_counts.inc.php`), in fila con le altre
   categorie del record in grigio tenue. A fondo tenue anche lei le due pastiglie si
   confondevano: segnalato sulla lista dei libri di sbamcomics, «lo stacco è poco».
   Ricetta di `.rap-tab-count`, gia' misurata: `--accent` con `--text-on-primary`, che
   inverte polarita' nel tema scuro. **4,87:1** nel chiaro e **6,37:1** nello scuro.
   La corona dice «principale» a colpo d'occhio; la parola sta nel `title` e in un testo
   nascosto per il lettore di schermo. */
.badge.rap-cat-primary {
	background-color: var(--accent);
	color: var(--text-on-primary);
}
.badge.rap-cat-primary .ti {
	font-size: 1.1em;
	margin-right: 3px;
	vertical-align: -1px;
}

/* 5.0 M1 T4 — RIGA OBSOLETA: si sbiadisce la MINIATURA, e solo quella.
   L'opacity su tutta la riga darebbe l'effetto "messo da parte" che si cerca, ma porta con
   sé testo, link, pastiglia, icone azione e interruttore di stato: misurato, il nome del
   record scende a 2,43:1 nel tema scuro. E non varrebbe nemmeno l'esenzione WCAG 1.4.3 per
   i componenti inattivi, perché una riga obsoleta resta operabile - si apre, si modifica,
   si cancella - e il suo testo è l'unico modo per ritrovarla fra migliaia.
   La miniatura invece è decorativa: il nome accanto porta l'informazione, quindi si può
   attenuare senza togliere niente a nessuno. Stesso valore nei due temi: è una foto, non
   un colore, e non ha un verso da invertire. */
.rap-row-old .rap-row-thumb img { opacity: .30; }

/* Badge "bianco su riga attiva": lo emette la sidebar categorie della lista
   unificata (act_list, 4.6 M1) col conteggio record. `bg-white text-dark` sono
   letterali di Bootstrap → nel tema scuro restava una pastiglia bianca accesa
   sopra la riga selezionata. Qui diventa la pastiglia del design, che si legge
   sopra l'accento in entrambi i temi. */
.badge.bg-white {
	background-color: var(--surface-1) !important;
	color: var(--text-strong) !important;
}


/* --- Campi form -------------------------------------------------- */

.form-control,
.form-select {
	background-color: var(--field-bg-filled);
	border-color: var(--field-border-filled) !important;   /* neutralizza main.css (#bbced1 !important) */
	border-radius: var(--radius-lg);
	min-height: var(--control-height);
	font-size: var(--text-base);
	color: var(--text-body);
	box-shadow: none;
	transition: border-color var(--transition), box-shadow var(--transition);
}

.form-control:focus,
.form-select:focus {
	background-color: var(--surface-1);
	border-color: var(--accent) !important;   /* neutralizza main.css */
	box-shadow: var(--focus-shadow);
}

/* 🐛 Il testo-guida dei campi stava su `--text-disabled`: **2,04:1** nel tema chiaro e
   3,32:1 nello scuro, cioè sotto AA in tutto il pannello, login compreso. Non l'aveva visto
   nessuno dei tre audit perché misurano gli ELEMENTI del DOM e `::placeholder` è uno
   pseudo-elemento, che in quella passeggiata non compare.
   ⚠️ `--text-muted` NON basta: sul fondo pieno dei campi dà **4,49:1**, cioè manca la soglia
   per un centesimo (sul bianco andava bene: la differenza è tutta nel fondo). Serve
   `--text-secondary`, che porta tutti i campi sopra 5:1 restando comunque molto più tenue
   del testo digitato, che sta sopra 12:1. */
.form-control::placeholder { color: var(--text-secondary); }
/* 🐛 4.9 (2026-08-06) — il fix qui sopra copriva `.form-control`, ma i campi a scelta
   multipla sono rifatti da **Tom Select**, che si porta il SUO input e il suo grigio:
   `#757575`, cioè **3,40:1** sul fondo scuro dei campi - sotto AA. Si vedeva su "Seleziona
   categorie aggiuntive" e su ogni campo tag. Misurato, non stimato.
   ⚠️ `opacity: 1`: Firefox smorza i placeholder con un'opacità propria, che rimangerebbe
   parte di quello che qui si sta guadagnando. */
.ts-wrapper .ts-control > input::placeholder,
.ts-control > input::placeholder { color: var(--text-secondary); opacity: 1; }

/* Ricerca delle liste: campo BIANCO (nei mockup è così), non "pieno" come i campi dei form.
   Il motivo è che qui non si compila una scheda, si filtra un elenco: il campo sta su una
   pagina, non dentro una card, e col fondo dei form si confondeva con lo sfondo
   dell'applicazione. Il bottone con la lente resta dov'è. */
.rap-list-search .form-control,
.rap-list-filter { background-color: var(--surface-1); }
.form-control:disabled, .form-control[readonly] { background-color: var(--surface-4); color: var(--text-disabled); }

.form-control-sm, .form-select-sm { min-height: var(--control-height-sm); font-size: var(--text-sm); }

/* Il filtro di stato sta sulla STESSA riga della ricerca: `.form-select-sm` nasce a 36px e
   il campo di ricerca (un `.form-control` dentro un `.input-group-sm`) resta a 38, così i
   due controlli affiancati facevano uno scalino di 2px. Si allinea il select. */
.rap-list-filter { min-height: var(--control-height); }

textarea.form-control { line-height: var(--leading-normal); resize: vertical; }

.form-label,
.card-body label {
	font-size: var(--text-sm);
	font-weight: var(--weight-semibold);
	color: var(--text-strong);
	margin-bottom: var(--space-2);
}

.form-hint, .form-text { font-size: var(--text-xs); color: var(--text-muted); }
.form-required, .required { color: var(--danger); }

.input-group-text {
	background-color: var(--surface-2);
	border-color: var(--field-border-filled);
	color: var(--text-muted);
	font-size: var(--text-sm);
}

.is-invalid, .form-control.is-invalid { border-color: var(--danger) !important; }   /* neutralizza main.css */
.invalid-feedback { font-size: var(--text-xs); color: var(--danger); }


/* --- Check e switch ---------------------------------------------- */

.form-check-input {
	background-color: var(--surface-1);
	border-color: var(--border-hover);
	transition: background-color var(--transition), border-color var(--transition);
}
.form-check-input:checked {
	background-color: var(--accent);
	border-color: var(--accent);
}
.form-check-input:focus { box-shadow: var(--focus-shadow); border-color: var(--accent); }
.form-check-label { font-size: var(--text-base); color: var(--text-strong); font-weight: var(--weight-regular); }
/* 🐛 SWITCH E ETICHETTA: si smette di usare il float di Bootstrap (2026-08-04).
   Due difetti sullo stesso pezzo in tre giorni, ed è lo stesso meccanismo a produrli:
   Tabler mette l'interruttore in `float:left` con `margin-left:-2.5rem` e lo fa rientrare
   nel `padding-left` del contenitore. Un incastro di misure che il tema 4.8 rompe, perché
   disegna lo switch a 40px invece dei 32 nativi.
     · 2026-08-02: testo a ridosso del cursore (rientro insufficiente) → toppato con un
       `margin-right` sull'input, che però allargava il float oltre il rientro;
     · 2026-08-04, «Impostazioni sito»: l'etichetta "Sito online" andava a capo dopo la
       prima parola. Causa vera: `main.css` ha `.card-body label { display: inline-block }`,
       che vale (0,1,1) e batte il `display:block` di `.form-check` (0,1,0). Il contenitore
       diventa così a LARGHEZZA DEL CONTENUTO, e la larghezza massima di una scatola che
       contiene un float si risolve sul float stesso: restavano ~40px per il testo, che
       andava a capo parola per parola.
   Rimedio: niente float, una riga flex - switch, gap, etichetta. È la stessa forma che
   `.rap-status` (interruttore in lista) usa già dal blocco B, quindi il pannello ha un
   modo solo di disporre un interruttore invece di due.
   ⚠️ `inline-flex` e non `flex`: in lista lo switch sta in una cella centrata, e un
   contenitore a tutta larghezza lo sposterebbe a sinistra. Qui la larghezza-contenuto non
   fa danni proprio perché il float non c'è più: il testo conta per intero nella misura.
   ⚠️ `main.css` NON si tocca: è condiviso col master 4.7, che senza `theme.css` sta bene
   com'è (lì lo switch è quello nativo, più stretto, e il rientro basta).
   ⚠️ SOLO dove l'etichetta sta DENTRO il contenitore (`:has(> .form-check-label)`), cioè
   Impostazioni sito e l'interruttore di lista. I campi `toggle` dei moduli hanno invece
   l'etichetta FUORI - `<label>` e poi `<div class="form-check form-switch">` - e lì la riga
   flex li affiancava, mandando l'interruttore accanto al testo invece che sotto: succedeva
   in tutta la scheda SEO ("Escludi dai motori di ricerca", segnalato 2026-08-04) e ovunque
   un modulo dichiari un toggle. Per quelli resta il comportamento di sempre: etichetta
   sopra, interruttore a capo. */
.form-check.form-switch:has(> .form-check-label) {
	display: inline-flex;
	align-items: center;
	gap: var(--gap-inline);
	padding-left: 0;
}
.form-check.form-switch:has(> .form-check-label) > .form-check-input {
	float: none;
	flex: 0 0 auto;
	margin-left: 0;
	margin-right: 0;
}
/* ⚠️ Qui c'era `.rap-settings-page > .card:first-child, form > .card:first-child {
   margin-top: var(--space-3) }`, cioè un altro cerotto sullo stesso taglio: il `page-header`
   non aveva margine sotto e in Impostazioni la prima scheda partiva incollata al titolo.
   Rimosso il 2026-08-07 con la cura vera (`.page-wrapper .page-header`, in cima al file).
   Toglierlo serve, non è pulizia estetica: era un `form > .card:first-child` NON ancorato
   all'intestazione, quindi valeva per qualsiasi form che cominci con una scheda, ovunque
   stia nella pagina, e sommato al margine nuovo avrebbe dato uno stacco doppio proprio
   nelle Impostazioni. */

/* Toggle (tipo campo `toggle` dei moduli, reso da Tabler come form-switch) */
.form-switch .form-check-input {
	width: var(--switch-width);
	height: var(--switch-height);
	border-radius: var(--radius-pill);
	background-color: var(--surface-6);
	border-color: transparent;
}
.form-switch .form-check-input:checked { background-color: var(--accent); border-color: transparent; }


/* --- Tab --------------------------------------------------------- */

.nav-tabs {
	border-bottom-color: var(--border-soft);
	gap: var(--space-10);
}

.nav-tabs .nav-link {
	border: 0;
	border-bottom: 2px solid transparent;
	padding: 14px 0;
	margin-bottom: -1px;
	font-size: var(--text-base);
	font-weight: var(--weight-semibold);
	color: var(--text-secondary);
	background: transparent;
}

.nav-tabs .nav-link:hover { color: var(--text-strong); border-bottom-color: var(--border-hover); background: transparent; }

.nav-tabs .nav-link.active {
	color: var(--accent-link);
	background-color: transparent;
	border-color: transparent transparent var(--accent);
	border-bottom-width: 2px;
}


/* --- Dropdown ---------------------------------------------------- */

.dropdown-menu {
	background-color: var(--surface-1);
	border: 1px solid var(--border-soft);
	border-radius: var(--radius-xl);
	box-shadow: var(--shadow-md);
	padding: var(--space-2);
	font-size: var(--text-sm);
}

.dropdown-item {
	border-radius: var(--radius-md);
	padding: 8px 11px;
	color: var(--text-strong);
	font-weight: var(--weight-medium);
}
.dropdown-item:hover, .dropdown-item:focus { background-color: var(--surface-3); color: var(--text-heading); }
.dropdown-header { color: var(--text-muted); font-size: var(--text-xs); font-weight: var(--weight-semibold); letter-spacing: var(--tracking-caps); text-transform: uppercase; }
.dropdown-divider { border-color: var(--border-faint); }


/* --- Alert ------------------------------------------------------- */

.alert {
	border: 0;
	border-radius: var(--radius-xl);
	padding: 12px 14px;
	font-size: var(--text-base);
	line-height: var(--leading-normal);
}
.alert .alert-title, .alert strong { font-weight: var(--weight-semibold); }

/* main.css punta .alert-info su --tblr-bg-surface-tertiary: qui l'alert prende
   il proprio token e la variabile di superficie resta una superficie. */
.alert-info    { background-color: var(--accent-soft) !important; color: var(--accent-text-soft); }   /* neutralizza main.css */
.alert-success { background-color: var(--success-soft); color: var(--success); }
.alert-warning { background-color: var(--warning-soft); color: var(--warning); }
.alert-danger  { background-color: var(--danger-soft);  color: var(--danger); }
/* 🔴 5.0 (2026-08-24) — `:not(.btn)` NON è cosmetico. Senza, questa riga vince su `.btn`
   (classe+tipo batte classe) e ogni BOTTONE dentro un avviso eredita il testo dell'avviso:
   è così che il bottone «Torna amministratore» della fascia A2 è finito ambra su ambra,
   1,19:1 nel tema scuro. Qui si vuole tingere i LINK testuali dell'avviso, non i bottoni,
   che hanno un fondo proprio e quindi un inchiostro proprio. */
.alert-info a:not(.btn), .alert-success a:not(.btn), .alert-warning a:not(.btn), .alert-danger a:not(.btn) { color: inherit; text-decoration: underline; }


/* --- Paginazione ------------------------------------------------- */

.pagination {
	--tblr-pagination-color: var(--text-strong);
	--tblr-pagination-bg: transparent;
	--tblr-pagination-border-color: transparent;
	--tblr-pagination-hover-bg: var(--surface-3);
	--tblr-pagination-hover-color: var(--text-heading);
	--tblr-pagination-hover-border-color: transparent;
	--tblr-pagination-active-bg: var(--accent);
	--tblr-pagination-active-color: var(--text-on-primary);
	--tblr-pagination-active-border-color: var(--accent);
	--tblr-pagination-border-radius: var(--radius-md);
	font-size: var(--text-sm);
	font-weight: var(--weight-semibold);
}


/* --- List group (sidebar categorie 4.6 M1, elenchi vari) --------- */

.list-group {
	--tblr-list-group-bg: transparent;
	--tblr-list-group-border-color: var(--border-hairline);
	--tblr-list-group-color: var(--text-strong);
	--tblr-list-group-action-hover-bg: var(--surface-2);
	--tblr-list-group-action-hover-color: var(--text-heading);
	--tblr-list-group-active-bg: var(--accent-soft);
	--tblr-list-group-active-color: var(--accent-text-soft);
	--tblr-list-group-active-border-color: var(--border-hairline);
}

/* 4.8 (2026-08-04) — LA LISTA UNIFICATA SI SDOPPIA DA 1200px, NON DA 992.
   A 1024 (tablet orizzontale) le due colonne ci stavano solo sulla carta: la sidebar
   scendeva a ~240px - dove "Crea una nuova categoria" non ci sta - e la tabella restava
   con ~700px per miniatura, nome, categoria, data, stato e azioni, con la colonna dello
   stato spinta fuori vista. Meglio impilare: elenco categorie sopra, record sotto, ognuno
   a tutta larghezza. Il markup è passato a `col-xl-*`/`order-xl-*`, quindi qui vanno
   ri-agganciate le due regole che `main.css` scriveva sui vecchi breakpoint.
   ⚠️ `main.css` NON si tocca (condiviso col master 4.7): le sue regole su `.col-lg-3`
   restano lì e semplicemente non trovano più nulla da applicare. */
@media (min-width: 992px) and (max-width: 1199.98px) {
	/* in questa fascia la sidebar è impilata: sticky e altezza massima la
	   incollerebbero in mezzo alla pagina con un elenco che scrolla dentro l'elenco */
	.rap-cat-sidebar { position: static; }
	.rap-cat-list    { max-height: none; overflow-y: visible; }
}
@media (min-width: 1400px) {
	/* il cap a 320px stava su `.col-lg-3`, che ora non esiste più in quel markup */
	.rap-unified > .col-xl-3 { flex: 0 0 320px; width: 320px; max-width: 320px; }
}

.rap-cat-list .list-group-item { font-size: var(--text-base); }
/* 🐛 CATEGORIA SELEZIONATA: si vedeva appena (segnalato 2026-08-04).
   `.list-group-item.active` prendeva `--accent-soft` (#eef4f5), che è un velo pensato per i
   chip su fondo bianco: dentro una card bianca, accanto a un hover `--surface-2`, la riga
   selezionata era indistinguibile dalle altre - e in quella lista la selezione è
   l'informazione principale, perché dice quali record stai guardando.
   Serve un gradino vero, non un velo: `--accent-soft-strong`, tinta che si legge come
   "acceso" ma resta un fondo, con l'inchiostro dei chip accento sopra.
   ⚠️ NON si è ritoccato `--accent-soft`: lo usano chip e riquadri in tutto il pannello, e
   alzarlo lì avrebbe reso pesanti una dozzina di componenti per risolverne uno.
   ⚠️ Il grassetto resta: la selezione non deve dipendere dal solo colore (WCAG 1.4.1).
   Contrasto misurato sul banco: **5,42:1** chiaro · **5,14:1** scuro (AA). Lo stacco dal fondo
   della card passa da 1,06:1 a **1,32:1** nel chiaro e **1,71:1** nello scuro. */
.rap-cat-list .list-group-item.active {
	font-weight: var(--weight-semibold);
	background-color: var(--accent-soft-strong);
	color: var(--accent-text-soft);
	border-color: var(--border-hairline);
}
.rap-cat-list .list-group-item .badge { background-color: var(--surface-4); color: var(--text-secondary); }
/* Il contatore sulla riga selezionata: il grigio di `--surface-4` su fondo tinto sparisce.
   Fondo della card (bianco nel chiaro, scuro nello scuro) + inchiostro dell'accento. */
.rap-cat-list .list-group-item.active .badge { background-color: var(--surface-1); color: var(--accent-text-soft); }


/* --- Progress ---------------------------------------------------- */

.progress {
	background-color: var(--surface-4);
	border-radius: var(--radius-pill);
	height: 7px;
}
.progress-bar { background-color: var(--accent); }
.progress-bar.bg-success { background-color: var(--success-solid) !important; }   /* neutralizza .bg-* */
.progress-bar.bg-danger  { background-color: var(--danger-solid)  !important; }
.progress-bar.bg-warning { background-color: var(--warning-solid) !important; }


/* Autore in linea nelle "Ultime modifiche": sta a destra ma non deve rubare spazio al
   titolo della pagina, che è il dato principale della riga. */
.rap-recent-author { max-width: 40%; overflow: hidden; text-overflow: ellipsis; }

/* --- Pagine: freccia di discendenza nell'albero (4.8 M4) --------- */
.rap-page-child { color: var(--text-decor); font-size: 15px; vertical-align: -1px; }

/* --- Dashboard: intestazione e stat card (4.8 M3) ---------------- */

.rap-dash-head {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: space-between;
	gap: var(--gap-control);
	margin-bottom: var(--gap-section);
}
.rap-dash-title {
	margin: 0;
	font-size: var(--text-3xl);
	font-weight: var(--weight-semibold);
	letter-spacing: var(--tracking-title);
	color: var(--text-heading);
}
.rap-dash-sub { margin: var(--space-1) 0 0; font-size: var(--text-sm); color: var(--text-muted); }

/* Occhiello al posto del titolo di pagina: la dashboard ha già il suo titolo grande (il
   saluto), quindi qui sopra basta una riga che dica in che schermata siamo. Il testo arriva
   in tondo da `$language['main']` e lo mette in maiuscolo il CSS. */
/* ⚠️ Tabler scrive `.page-wrapper .page-header { margin: 1.5rem 0 0 }` - una shorthand con
   specificità (0,2,0), che azzera il margine sotto e batte qualsiasi `.classe` singola (lo
   stesso `.page-header` di questo file, poco sopra, è già scavalcato così). Per staccare
   l'occhiello dal saluto si ricalca il selettore di Tabler + la nostra classe, senza
   `!important`. */
.page-wrapper .page-header.rap-page-header-dash { margin-bottom: var(--space-2); }
.rap-dash-eyebrow {
	font-size: var(--text-sm);
	font-weight: var(--weight-semibold);
	letter-spacing: var(--tracking-caps-wide);
	text-transform: uppercase;
	color: var(--text-secondary);
}
.rap-dash-actions { display: flex; align-items: center; gap: var(--gap-control); }

/* ⚠️ `.dropdown-menu-end` di Bootstrap allinea a destra SOLO quando Popper ha già
   posizionato il menu (la regola è `.dropdown-menu-end[data-bs-popper]`). Prima di quel
   momento il menu resta allineato a SINISTRA del pulsante: e siccome questi pulsanti
   stanno a filo destro, il menu sborda dalla pagina (misurato: 5px di scroll orizzontale
   sulla dashboard). Qui l'allineamento a destra vale comunque; quando Popper interviene
   scrive stili inline e vince lui, quindi le due cose non litigano. */
.rap-dash-actions .dropdown-menu-end,
.rap-user-dropdown.dropdown-menu-end { right: 0; left: auto; }

/* Tessere dei numeri secchi in fondo a "Risorse hosting" (email, database, peso del DB).
   Riquadri leggeri: il bordo tenue basta a separarli, un fondo pieno li farebbe pesare
   quanto le card vere. Su schermo stretto scendono a una colonna sola. */
.rap-mini-tiles {
	display: grid;
	grid-template-columns: repeat(3, minmax(0, 1fr));
	gap: var(--gap-control);
}
.rap-mini-tile {
	border: 1px solid var(--border);
	border-radius: var(--radius-xl);
	padding: var(--space-5) var(--space-4);
	min-width: 0;
}
.rap-mini-value {
	font-size: var(--text-lg);
	font-weight: var(--weight-semibold);
	line-height: var(--leading-tight);
	letter-spacing: var(--tracking-heading);
	color: var(--text-heading);
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}
.rap-mini-label { margin-top: var(--space-1); font-size: var(--text-sm); color: var(--text-secondary); }
@media (max-width: 400px) { .rap-mini-tiles { grid-template-columns: 1fr; } }

/* Scheda "Dettagli contratto": etichetta e valore su due colonne vere. La colonna di
   sinistra è larga `max-content`, cioè quanto la più lunga delle etichette: nessuna va a
   capo e non ci sono numeri di colonna da ritarare quando cambia una traduzione. Filetto
   fra le righe come nelle liste. */
.rap-contract {
	display: grid;
	/* ⚠️ `auto` e NON `max-content` sulla colonna delle etichette (corretto il 2026-08-02,
	   quando la scheda ha iniziato a dividere la riga col consenso cookie): `max-content`
	   non si stringe MAI, così su una card stretta - stessa col-md-6 vista a 1024px - il
	   valore restava con 55px e "Bonifico Bancario - 30 gg f.m." andava su cinque righe.
	   Con `auto` l'etichetta sta su una riga finché c'è spazio e cede solo quando serve; il
	   minimo di 150px sul valore stabilisce chi dei due deve cedere per primo. */
	grid-template-columns: auto minmax(150px, 1fr);
	column-gap: var(--gap-section);
	margin: 0;
}
.rap-contract dt,
.rap-contract dd {
	margin: 0;
	padding: var(--space-4) 0;
	font-weight: var(--weight-regular);
	min-width: 0;
}
.rap-contract dt { color: var(--text-secondary); }
.rap-contract dt:first-of-type, .rap-contract dd:first-of-type { padding-top: 0; }
.rap-contract dt:not(:first-of-type),
.rap-contract dd:not(:first-of-type) { border-top: 1px solid var(--border-hairline); }
.rap-contract dd:last-of-type, .rap-contract dt:last-of-type { padding-bottom: 0; }
/* Su schermo stretto le due colonne non ci stanno: etichetta sopra, valore sotto. */
@media (max-width: 575.98px) {
	.rap-contract { grid-template-columns: 1fr; }
	.rap-contract dt { padding-bottom: 0; }
	.rap-contract dd { padding-top: var(--space-1); }
	.rap-contract dd:not(:first-of-type) { border-top: 0; }
}

/* Consenso cookie: legenda + barra impilata + riga di sintesi (ricetta dei mockup).
   Il pallino colorato porta il colore, l'etichetta lo ripete e il numero resta scuro:
   così il dato si legge anche senza distinguere i colori. */
/* `auto-fit` invece di `repeat(3, 1fr)`: dal 2026-08-02 la scheda sta a METÀ larghezza
   accanto al contratto, e sotto una certa misura tre colonne spezzerebbero "ACCETTATO
   TUTTO" a metà parola. Così scendono a due (o una) e le etichette restano intere. */
.rap-consent-legend {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(118px, 1fr));
	gap: var(--gap-card);
	margin-bottom: var(--space-5);
}
.rap-consent-key {
	display: flex;
	align-items: center;
	gap: var(--gap-inline);
	font-size: var(--text-sm);
	font-weight: var(--weight-semibold);
	letter-spacing: var(--tracking-caps);
	text-transform: uppercase;
}
.rap-consent-dot {
	width: 8px; height: 8px;
	border-radius: var(--radius-pill);
	background: currentColor;
	flex: 0 0 auto;
}
.rap-consent-key.is-accept { color: var(--success); }
.rap-consent-key.is-reject { color: var(--danger); }
.rap-consent-key.is-custom { color: var(--warning); }
.rap-consent-num {
	margin-top: var(--space-2);
	font-size: var(--text-2xl);
	font-weight: var(--weight-semibold);
	line-height: var(--leading-tight);
	letter-spacing: var(--tracking-heading);
	color: var(--text-heading);
}
.rap-consent-bar {
	display: flex;
	height: 10px;
	border-radius: var(--radius-pill);
	overflow: hidden;
	background: var(--surface-4);
}
.rap-consent-bar > span { min-width: 4px; }
.rap-consent-bar > .is-accept { background: var(--success-solid); }
.rap-consent-bar > .is-reject { background: var(--danger-solid); }
.rap-consent-bar > .is-custom { background: var(--warning-solid); }
.rap-consent-note { margin: var(--space-5) 0 0; font-size: var(--text-sm); color: var(--text-secondary); }

/* Le KPI sono le uniche card sollevate: nel design è ciò che le stacca dal resto */
.rap-kpi { box-shadow: var(--shadow-sm); }
.rap-kpi .card-body { padding: 16px 17px; }
.rap-kpi-top { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--space-3); }
.rap-kpi-label {
	font-size: var(--text-sm);
	font-weight: var(--weight-semibold);
	letter-spacing: .04em;
	text-transform: uppercase;
	color: var(--text-secondary);
}
.rap-kpi-icon { font-size: 17px; color: var(--text-faint); flex: 0 0 auto; }
/* "+N nel mese" ACCANTO al numero e non sotto (richiesta dal campo, 2026-09-03): con
   una sola card su quattro che porta il delta, andare a capo la rendeva più alta
   delle altre e la griglia usciva sfalsata — a ogni larghezza, non solo sotto 768px
   (era così fino al 2026-08-06, poi solo il caso mobile era stato corretto).
   `inline-block` su entrambi basta - si affiancano da soli - e la linea di base
   comune li tiene posati sullo stesso appoggio, nonostante i corpi molto diversi. */
.rap-kpi-value {
	display: inline-block;
	vertical-align: baseline;
	margin-top: var(--space-2);
	font-size: var(--text-4xl);
	font-weight: var(--weight-semibold);
	letter-spacing: -1px;
	line-height: 1.1;
	color: var(--text-heading);
}
.rap-kpi-delta {
	display: inline-block;
	vertical-align: baseline;
	margin-top: 0;
	margin-left: var(--space-2);
	font-size: var(--text-sm);
	font-weight: var(--weight-semibold);
	color: var(--success);
}

/* --- Bot rilevati: barra di confronto per riga (4.8) ------------- */
/* Il numero da solo non dice se 28 hit sono tanti o pochi: la barra, in scala sul bot
   più attivo, lo dice a colpo d'occhio. */
.rap-bot-barcell { width: 45%; padding-right: var(--space-3) !important; }   /* neutralizza il padding di .card-table */
.rap-bot-track { height: 6px; border-radius: var(--radius-pill); background: var(--surface-4); overflow: hidden; }
.rap-bot-fill  { height: 100%; border-radius: var(--radius-pill); background: var(--chart-1); }

/* Barra su tetto di RIFERIMENTO (risorse senza limite reale): più tenue, così non si
   confonde con una barra che misura un limite vero */
.progress.rap-bar-ref .progress-bar { background-color: var(--chart-1); }

/* --- Grafico traffico della dashboard (4.8) ---------------------- */
/* Barre in CSS puro, nessuna libreria: l'altezza è una percentuale del mese di picco. */
.rap-traffic-chart {
	display: flex;
	align-items: flex-end;
	gap: var(--space-2);
	height: 96px;                    /* misura del riquadro, non un valore di scala */
}
/* ⚠️ L'etichetta è FUORI dal flusso e la colonna ha `box-sizing: border-box`: così
   l'altezza percentuale della barra si misura sul solo spazio delle barre. Con
   l'etichetta nel flusso, tutte le barre sopra ~79% venivano schiacciate alla stessa
   altezza (misurato: 82% e 100% rendevano entrambe 76px) e il grafico mentiva. */
.rap-traffic-col {
	position: relative;
	flex: 1 1 0;
	display: flex;
	flex-direction: column;
	justify-content: flex-end;
	align-items: center;
	height: 100%;
	padding-bottom: 18px;            /* riga delle etichette */
	box-sizing: border-box;
}
.rap-traffic-bar {
	width: 100%;
	max-width: 34px;
	flex: 0 0 auto;
	border-radius: var(--radius-xs) var(--radius-xs) 0 0;
	background: var(--chart-1);
	transition: background-color var(--transition);
}
.rap-traffic-col:hover .rap-traffic-bar { background: var(--accent); }
/* Il mese in corso è incompleto: si distingue senza dover leggere l'etichetta */
.rap-traffic-bar.is-partial { background: var(--chart-3); opacity: .75; }
.rap-traffic-label {
	position: absolute;
	left: 0; right: 0; bottom: 0;
	text-align: center;
	font-size: var(--text-2xs);
	color: var(--text-muted);
}

/* --- Empty state / avatar ---------------------------------------- */

.empty { padding: 52px 24px; }
.empty-title { font-size: var(--text-md); font-weight: var(--weight-semibold); color: var(--text-heading); }
/* `!important`: l'empty state sta sullo sfondo applicazione e spesso porta anche
   .text-muted, che è !important in Tabler. Qui vince il token giusto (COMPONENTS.md). */
.empty-subtitle { font-size: var(--text-base); color: var(--text-secondary) !important; }
.empty-icon { color: var(--text-disabled); }

.avatar { background-color: var(--surface-4); color: var(--text-secondary); border-radius: var(--radius-pill); }


/* ════════════════════════════════════════════════════════════
   Superfici introdotte da 4.6 e 4.7 — restano dove sono, cambia la veste
   ════════════════════════════════════════════════════════════ */

/* Contatore dentro una tab (Revisioni 4, Commenti 2): pastiglia tenue, non un badge
   pieno - la tab è già un comando, il numero è solo un'informazione di corredo.
   `is-todo` = ci sono commenti in attesa di moderazione, cioè qualcosa da fare. */
/* 4.9 (2026-08-11) — la pastiglia neutra passa dal grigio all'ACCENTO: un contatore su una
   linguetta è un richiamo, e in grigio su grigio si perdeva. Vale per i contatori senza stato
   proprio - voci scelte, Revisioni, totale Commenti; SEO (is-ok/warn/bad) e commenti da leggere
   (is-todo) tengono i loro colori, che dicono un'altra cosa.
   ⚠️ Il testo è `--text-on-primary`, NON `#fff` cablato: è il token nato per stare sul fondo
   accento e **inverte polarità nel tema scuro** (bianco → #04222a), perché lì l'accento è chiaro.
   Misurato: **4,87:1** nel chiaro e **6,37:1** nello scuro, entrambi sopra il minimo AA.
   ⚠️ Con `--accent-bright` - il primo tentativo, più squillante - il bianco sopra stava a
   **2,09:1**: la stessa famiglia di colore, ma fuori norma. */
.nav-tabs .rap-tab-count {
	display: inline-block;
	margin-left: var(--space-2);
	padding: 0 6px;
	border-radius: var(--radius-pill);
	background-color: var(--accent);
	color: var(--text-on-primary);
	font-size: var(--text-2xs);
	font-weight: var(--weight-semibold);
	font-variant-numeric: tabular-nums;
}
.nav-tabs .rap-tab-count.is-todo { background-color: var(--warning-soft); color: var(--warning); }
/* Punteggio SEO nell'etichetta della tab: stessi tre colori del semaforo che si vede nelle
   liste e nel widget, così il numero vuol dire la stessa cosa ovunque compaia.
   `is-off` = keyphrase non impostata: la pastiglia resta vuota e non si disegna, sennò
   comparirebbe un pallino grigio senza contenuto. */
.nav-tabs .rap-tab-count.is-ok   { background-color: var(--success-soft); color: var(--success); }
.nav-tabs .rap-tab-count.is-warn { background-color: var(--warning-soft); color: var(--warning); }
.nav-tabs .rap-tab-count.is-bad  { background-color: var(--danger-soft);  color: var(--danger); }
.nav-tabs .rap-tab-count.is-off  { display: none; }

/* Freccia "indietro" nella barra del form record (4.8): bersaglio da 36px, neutro a
   riposo, si accende al passaggio come le icone di riga. */
.rap-form-back {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	flex: 0 0 auto;
	width: 36px; height: 36px;
	border: 1px solid var(--border);
	border-radius: var(--radius-lg);
	color: var(--text-default);
	text-decoration: none;
}
.rap-form-back:hover, .rap-form-back:focus-visible {
	border-color: var(--border-hover);
	background-color: var(--surface-3);
	color: var(--accent-brand);
}

/* 4.6 M2 — barra sticky del form a blocchi (briciole + titolo + Anteprima/Salva).
   4.8 (2026-08-04): era rimasta una fascia a tutta larghezza, squadrata e col testo a filo
   del bordo - l'unico elemento della schermata a non essere un contenitore come gli altri.
   Ora prende la stessa veste dei blocchi: bordo intero, raggio delle card e lo stesso
   rientro laterale del `.card-body` (20px), così il testo non tocca più il bordo. Il
   riquadro resta a tutta larghezza, allineato con la barra delle tab e col pannello che
   sta sotto - le card dei blocchi sono un livello più dentro, ed è giusto che rientrino.
   Il fondo resta semi-trasparente col velo sfocato, e la barra
   resta `sticky` (main.css): quando ci si scorre sotto, il contenuto si intravede nei due
   angoli arrotondati in alto - è il prezzo del raggio su un elemento che si appiccica al
   bordo, e si preferisce alla fascia squadrata. */
.rap-form-bar {
	padding: var(--space-5) var(--space-9);   /* neutralizza il `.75rem 0` di main.css */
	background: var(--surface-overlay);
	backdrop-filter: blur(6px);
	border: 1px solid var(--border-soft);     /* neutralizza il solo border-bottom di main.css */
	border-radius: var(--radius-2xl);         /* stesso raggio delle card dei blocchi */
}

/* 4.9 (2026-08-07) — LA BARRA NON VA A CAPO DA lg IN SU.
   Il markup porta `flex-wrap`, e in un contenitore che va a capo le righe si decidono
   sulla misura NATURALE degli elementi, non su quella a cui potrebbero stringersi: un
   titolo lungo spinge Anteprima/Salva sulla riga sotto anche se il troncamento
   (`text-truncate` + `min-w-0`) saprebbe benissimo evitarlo. Misurato sul banco con un
   titolo di notizia vero: a 1280px di finestra la barra passa da 69px a 123px - e sono
   pixel che restano occupati per tutta la scorsa della pagina, perché la barra è STICKY.
   ⚠️ `!important` obbligato: `flex-wrap` di Bootstrap è a sua volta `!important`. Si
   sovrascrive solo da lg in su - sotto il telefono la barra DEVE andare a capo, ed è la
   ragione per cui quella classe sta nel markup (dove sopravvive anche a una veste spenta).
   ⚠️ Selettori posizionali e non `.d-flex`: in `cat_ins_mod` il secondo figlio è il
   BOTTONE Salva, non un `div.d-flex` - un `> .d-flex:last-child` lì non aggancerebbe
   niente e il bottone si lascerebbe schiacciare da un nome di categoria lungo. */
@media (min-width: 992px) {
	.rap-form-bar { flex-wrap: nowrap !important; }
	.rap-form-bar > :first-child      { flex: 1 1 auto; min-width: 0; }  /* cede spazio */
	.rap-form-bar > :not(:first-child) { flex: 0 0 auto; }               /* i comandi no */
}

/* 4.9 (2026-08-07) — MISURA DELLA SCHEDA RECORD.
   `.container-wide` (1700px, main.css) è tarato sulle LISTE, dove le colonne sono tante e
   la larghezza serve davvero. Nel form a blocchi la stessa misura dà una colonna principale
   di ~1200px su un monitor da 1920: il campo "Titolo" diventa un righello, e fra
   un'etichetta e la successiva l'occhio deve attraversare tutto lo schermo per tornare a
   capo. `--content-max` (1440px) è il token che il design system ha già per la misura di
   lettura di una scheda, e finora non lo usava nessuno: main ≈ 990px, cioè quanto la
   colonna di una pagina in `ed_ins_mod` (che gira su `container-xl` e non ha mai avuto il
   problema).
   ⚠️ La classe la mette il PHP (`inc/header.inc.php`) accanto a `container-wide`, non un
   `body:has(#form_ins_mod)`: così vale nello stesso identico modo per i TRE contenitori
   della pagina - barra in alto, intestazione e corpo - che sono incolonnati fra loro e
   devono restarlo. A veste spenta la classe non fa nulla e si torna a 1700px. */
.rap-container-form { max-width: var(--content-max); }

/* ────────────────────────────────────────────────────────────
   4.8 M5 — Form record: i quattro pezzi della schermata
   ──────────────────────────────────────────────────────────── */

/* 1) BLOCCO NUDO (`'plain' => 1` nel config del modulo). Il blocco resta un `.card`
      nel markup - così il PHP non deve biforcare le chiusure - ma qui perde ogni
      traccia di card: dentro c'è l'editor, che la sua cornice ce l'ha già, e due
      bordi concentrici a 3px di distanza sono la cosa che si nota di più in tutta
      la schermata. Il margine sotto resta: separa dal blocco successivo. */
/* 0) AREA DELLE LINGUETTE del form (`rap-tab-panel`, emessa da act_ins_mod e dal motore
      dei blocchi).
      ⭐ 4.9 (2026-08-07) — NON È PIÙ UNA SUPERFICIE.
      Fino alla 4.8 era un riquadro vero: `border border-top-0 rounded-bottom p-3` nel
      markup e, nel tema scuro, un fondo un gradino sotto quello dell'applicazione
      (`--surface-tabs`). L'intenzione era far staccare i blocchi; col layout a blocchi
      l'effetto era l'opposto:
        · una cornice attorno a card che la cornice ce l'hanno già (bordi dentro bordi);
        · le card rientrate di 16px rispetto alle linguette e alla barra del form, cioè
          TRE bordi sinistri diversi in un palmo di schermo.
      Resta solo lo stacco SOPRA la prima card. A dire "queste sono tab" basta la riga
      sottile sotto le linguette (`.nav-tabs`, che il suo bordo ce l'ha già): i blocchi si
      posano sul fondo dell'applicazione come in ogni altra schermata del pannello.
      ⚠️ `border`, `p-3` e `rounded-bottom` sono state tolte dal MARKUP e non neutralizzate
      qui: sono utility Bootstrap `!important`, combatterle da CSS voleva dire tre
      `!important` di rimbalzo su una cosa che è nostra e si può semplicemente non scrivere.
      ⚠️ La classe `rap-tab-panel` resta: `.tab-content` da sola la usano anche l'elenco
      pagine e i Credits, dove questa spaziatura non serve.
      ⚠️ Vale anche per il form CLASSICO (modulo senza `form_blocks` ma con la tab SEO):
      lì dentro non ci sono card ma campi nudi, che però stanno già dentro la card del
      form - il contenitore non manca, era doppio. */
.tab-content.rap-tab-panel { padding-top: var(--gap-section); }

.rap-form-block.rap-form-plain {
	background: transparent;
	border: 0;
	box-shadow: none;
}
.rap-form-block.rap-form-plain > .card-body { padding: 0; }

/* 1-bis) FASCIA DI CODA del form a blocchi: ci finisce quello che il core aggiunge dopo
      il ciclo dei campi - campi personalizzati, campi di sistema non posizionati nel
      config, selettore Autore. Nel markup è una card come i blocchi (vedi act_ins_mod),
      ma va nascosta quando resta VUOTA, cosa che succede su tutti i moduli che
      dichiarano i propri campi di sistema e non hanno campi personalizzati: senza questa
      regola comparirebbe un riquadro vuoto in fondo a ogni scheda.
      ⚠️ Il test non può essere `:empty` (dentro ci sono comunque i ritorni a capo del
      markup): si guarda se la coda contiene almeno un controllo di form. */
/* 4.9 M5: stessa regola per i blocchi che DICHIARANO di poter restare vuoti
   (`'hide_if_empty' => 1` nel config): gli "ambiti" spariscono se la tabella delle relazioni
   è vuota, l'autore se il ruolo non può assegnarlo, e il contenitore si apre prima che il
   PHP possa saperlo. */
.rap-form-tail:not(:has(input, select, textarea)),
.rap-form-block.rap-form-optional:not(:has(input, select, textarea)) { display: none; }

/* ── 4.9 (2026-08-07) — RITMO VERTICALE DENTRO I BLOCCHI ──────────────────────
   Ogni campo è una colonna dentro una `.row.g-3` (16px di gutter) e porta a sua volta il
   `.mb-3` dello shim QuickForm (altri 16px): fra un campo e il successivo lo stacco è 32px,
   e sotto l'ULTIMO campo restano 16px di vuoto che si sommano al padding della card. Si
   azzera il margine del campo e si lascia lavorare il solo gutter: uno stacco solo, uguale
   ovunque, e le card si accorciano sensibilmente senza che nulla si tocchi.
   ⚠️ `!important` obbligato: `.mb-3` di Bootstrap è `!important`.
   ⚠️ SOLO dentro i blocchi: nel form classico il `.mb-3` resta l'unica spaziatura verticale
   che c'è (là il template del form non mette sempre una `.row.g-3` sotto ogni campo).
   ⚠️ ⭐ IL CAMPO FILE È ESCLUSO, e non è una raffinatezza: `.rap-file-field` è una colonna
   ma è anche una GRIGLIA con `row-gap: 0` (vedi più sotto), dove a distanziare selettore,
   testo alternativo e indicazioni sono proprio quei `.mb-3`. Azzerarli lì fa collassare le
   righe una sull'altra; e la via alternativa - dare un `row-gap` alla griglia - riaprirebbe
   il buco delle righe VUOTE chiuso il 2026-08-07 (`align-content: start`). */
.rap-form-block .card-body > .row > [class*="col-"]:not(.rap-file-field) > .mb-3 { margin-bottom: 0 !important; }

/* La riga di spiegazione sotto un campo ("I tag vanno inseriti in minuscolo…") è corredo
   dell'etichetta, non un blocco a sé: arrivava con la scala del testo di interfaccia e col
   margine di paragrafo di Bootstrap (16px SOTTO, 0 sopra), quindi stava attaccata al campo
   sbagliato - il proprio - e spinta lontano dal successivo. Qui prende la misura degli
   aiuti in linea (`--text-xs` attenuato, come `.form-hint`) e si posa sotto il suo campo. */
.rap-form-block .card-body > .row > [class*="col-"] > p.form {
	margin: var(--space-2) 0 0;
	font-size: var(--text-xs);
	line-height: var(--leading-relaxed);
	color: var(--text-muted);
}

/* Intestazione del blocco incolonnata col suo contenuto: `.card-header` del tema ha 18px di
   rientro laterale, il `.card-body` ne ha 20 (spacer di Tabler) - due pixel di sfasamento
   fra il titolo del blocco e le etichette dei campi che ci stanno sotto.
   ⚠️ Si tocca il solo asse orizzontale: il verticale lo decide il `py-2` del markup, che è
   `!important` e va bene com'è (intestazione compatta). */
.rap-form-block > .card-header {
	padding-left: var(--space-9);
	padding-right: var(--space-9);
}

/* 2) CAMPO SLUG come gruppo unico: [ /notizie/ ][ campo ][ Genera da titolo ].
      Il prefisso non è un campo, è un promemoria: fondo neutro e testo attenuato,
      così l'occhio capisce che la parte scrivibile è quella in mezzo. */
.rap-url-group .rap-url-prefix {
	background-color: var(--surface-3);
	border-color: var(--field-border-filled);
	color: var(--text-muted);
	font-size: var(--text-sm);
	white-space: nowrap;
}
/* Il campo dentro un input-group non deve portarsi dietro i propri angoli tondi:
   li disegna il gruppo. Bootstrap lo fa già, ma `.form-control` del tema rimette
   il radius pieno e ricomparirebbe una cucitura fra prefisso e campo. */
.rap-url-group > .form-control:not(:first-child) { border-top-left-radius: 0; border-bottom-left-radius: 0; }
.rap-url-group > .form-control:not(:last-child)  { border-top-right-radius: 0; border-bottom-right-radius: 0; }
.rap-url-group > .btn { white-space: nowrap; }
/* ⚠️ `main.css` forza `width: 100% !important` su OGNI campo dentro `#form_ins_mod`
   (regola nata quando nei form ins/mod non c'erano input-group: il commento lì lo dice).
   Su un campo dentro un input-group "100%" vuol dire "prenditi tutta la riga da solo",
   e il bottone accanto finirebbe a capo SEMPRE, anche su uno schermo largo.
   Qui si rimette la regola di Bootstrap - `flex: 1 1 auto; width: 1%` - con specificità
   più alta e lo stesso `!important`, senza toccare main.css.
   ⭐ 4.9 (2026-08-07): la regola vale ora per QUALSIASI `.input-group` del form, non più
   per le sole due classi del core. Il difetto non era degli slug: era di `main.css`, che
   rompe ogni input-group messo in quel form - compresi quelli costruiti da un **hook di
   sito**. Segnalato sul «Genera codice» delle promo di perego (`.rap-code-group`, creato
   da `promo_ins_mod-top`), che andava a capo mentre il «Genera da titolo» accanto no:
   due pulsanti gemelli con due comportamenti diversi, per una classe in un elenco. */
#form_ins_mod .input-group > .form-control,
#rap_cat_ins_mod .input-group > .form-control { width: 1% !important; flex: 1 1 auto; }
/* Sotto i 576px il gruppo non ci sta e Bootstrap manda il bottone a capo da sé: lì il
   campo resterebbe con l'angolo destro squadrato senza niente accanto. Si accompagna
   la cosa invece di combatterla - bottone a tutta riga e angoli rimessi a posto.
   Selettore a tre classi per superare quello di Bootstrap senza `!important`. */
@media (max-width: 575.98px) {
	/* Anche qui il selettore è quello di Bootstrap (`>:not(:first-child):not(…)`, che
	   azzera gli angoli sinistri e tira l'elemento addosso al precedente con un margine
	   negativo) più la propria classe: il bottone su una riga sua vuole i suoi angoli e
	   nessun margine negativo. */
	.rap-url-group.input-group > .btn:not(:first-child):not(.dropdown-menu):not(.valid-tooltip):not(.valid-feedback):not(.invalid-tooltip):not(.invalid-feedback) {
		flex: 1 0 100%;
		margin-left: 0;
		margin-top: var(--space-2);
		border-radius: var(--radius-lg);
	}
	/* ⚠️ Si RICALCA il selettore di Bootstrap con in più la propria classe: quello originale
	   pesa cinque `:not()` e un `.form-control:not(:first-child)` non lo scavalca. Stessa
	   ricetta usata per i sottomenu della sidebar, e sempre senza `!important`.
	   Il prefisso si esclude DENTRO il selettore (`:not(.rap-url-prefix)`) e non con una
	   regola a parte: quella peserebbe meno e non lo raggiungerebbe. */
	.rap-url-group.input-group:not(.has-validation) > :not(:last-child):not(.dropdown-toggle):not(.dropdown-menu):not(.form-floating):not(.rap-url-prefix) {
		border-top-right-radius: var(--radius-lg);
		border-bottom-right-radius: var(--radius-lg);
	}
}

/* 3) INTERRUTTORI DI SISTEMA (stato, in evidenza): etichetta a sinistra, comando a
      destra, su una riga sola. Prima erano etichetta sopra e interruttore sotto, che
      nella colonna stretta della spalla sprecava due righe per un sì/no.
      Lo STATO porta anche il riquadro tinto e il pallino: è l'unico comando della
      schermata che decide se il contenuto si vede dal sito, e va trovato al primo
      colpo d'occhio. L'"in evidenza" resta una riga nuda, è una preferenza. */
.rap-status-field > .mb-3,
.rap-flag-field   > .mb-3 {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: var(--space-5);
}
/* ⭐ 4.9 M2-ter (2026-08-07) — L'ETICHETTA È L'AREA DI TOCCO DELLA RIGA.
   Il cursore misura 40×24: rispetta il minimo WCAG (24×24) ma col pollice è poco, ed era
   l'UNICA cosa toccabile perché l'etichetta non aveva `for` (ora ce l'ha, vedi
   `input_status`/`input_special` e `toggle_label_for` in act_ins_mod). Con l'associazione
   fatta, basta dire all'etichetta di occupare tutto lo spazio che le resta: si tocca la riga,
   non si cerca il cursore.
   ⚠️ Si allarga l'AREA, NON il disegno: ingrandire il cursore ha già rotto il layout una volta
   (il float di Tabler si incastra su misure precise, vedi la nota sugli switch).
   ⚠️ Margini negativi + padding uguale e contrario sullo STATO: quel riquadro ha 10/12px di
   padding suo, e senza questo scambio l'etichetta si fermerebbe al bordo interno lasciando
   fuori dal bersaglio proprio la cornice colorata, che è la parte che si vede di più.
   Risultato misurato: da 40×24 a **~250×46** (stato) e **~126×44** (in evidenza), a costo
   ZERO di impaginazione - le righe erano già alte così. */
.rap-status-field > .mb-3 > label,
.rap-flag-field   > .mb-3 > label {
	margin-bottom: 0;
	flex: 1 1 auto;
	min-width: 0;
	align-self: stretch;
	display: flex;
	cursor: pointer;
}
/* 🐛 4.9 (2026-08-07, subito dopo M2-ter) — LA DIREZIONE NON È LA STESSA PER I DUE CAMPI, e
   sbagliarla si vede: lo STATO porta il pallino come `::before`, che dentro un flex diventa un
   elemento della riga; con `column` finiva SOPRA la parola, e l'interruttore usciva col pallino
   su una riga e «Online» su quella sotto. Qui va `row`, col pallino accanto al testo.
   ⚠️ L'avvisaglia c'era ed è stata letta male: la riga dello stato era passata da 46 a 49px, e
   quei 3px erano proprio l'impilamento. Una misura che cambia senza un motivo chiaro è un
   difetto finché non si dimostra il contrario.
   L'«in evidenza» invece `column` la vuole davvero: sotto l'etichetta c'è la riga di
   spiegazione (`.form-hint`), che deve stare sotto e non di fianco. */
.rap-status-field > .mb-3 > label { flex-direction: row; align-items: center; }
.rap-flag-field   > .mb-3 > label { flex-direction: column; justify-content: center; }
.rap-status-field > .mb-3 > label {
	margin: calc(var(--space-4) * -1) 0 calc(var(--space-4) * -1) calc(var(--space-5) * -1);
	padding: var(--space-4) 0 var(--space-4) var(--space-5);
}
/* "In evidenza" è una riga nuda: senza la riga di spiegazione starebbe a 19px, e lì il minimo
   serve davvero. Con la spiegazione è già più alta e questo non cambia nulla. */
.rap-flag-field > .mb-3 > label { min-height: 44px; }
/* `.form-check.form-switch` arriva con `mt-1` dallo shim e col padding di riga di
   Bootstrap: qui è una cella allineata, non una riga di checklist. */
.rap-status-field .form-check.form-switch,
.rap-flag-field   .form-check.form-switch {
	margin: 0 !important;
	padding-left: 0;
	min-height: 0;
	flex: 0 0 auto;
}
.rap-status-field .form-check-input,
.rap-flag-field   .form-check-input { margin: 0; float: none; cursor: pointer; }

.rap-status-field > .mb-3 {
	padding: var(--space-4) var(--space-5);
	border: 1px solid var(--border-soft);
	border-radius: var(--radius-lg);
	background-color: var(--surface-3);
}
.rap-status-field > .mb-3 > label::before {
	content: "";
	display: inline-block;
	width: 8px; height: 8px;
	margin-right: var(--space-3);
	border-radius: var(--radius-pill);
	background-color: var(--text-disabled);
	vertical-align: middle;
}
/* Il pallino verde lo accende lo stato dell'interruttore. `:has()` guarda in giù, che è
   l'unico verso in cui il CSS sa guardare: dal contenitore di campo verso la casella.
   Stesso meccanismo già in uso per la scheda note. */
.rap-status-field > .mb-3:has(input[type="checkbox"]:checked) {
	border-color: var(--success-solid);
	background-color: var(--success-soft);
}
.rap-status-field > .mb-3:has(input[type="checkbox"]:checked) > label { color: var(--success); }
.rap-status-field > .mb-3:has(input[type="checkbox"]:checked) > label::before { background-color: var(--success-solid); }
/* La riga di spiegazione sotto "In evidenza" non deve spingere in basso l'interruttore */
.rap-flag-field .form-hint { margin: 2px 0 0; font-size: var(--text-xs); color: var(--text-muted); }

/* 4) CAMPO FILE: anteprima grande a sinistra, comandi a destra.
      Il campo file è una GRIGLIA a due colonne quando c'è un'immagine già caricata:
      l'anteprima occupa la colonna di sinistra per tutta l'altezza, a destra si
      impilano il selettore del file, il testo alternativo (portato dentro da
      `initFileFieldLayout()`) e le indicazioni.

      ⚠️ Nel markup i pezzi NON arrivano in quest'ordine - il PHP li concatena da sei
      punti diversi e riordinarli vorrebbe dire riscriverli tutti - quindi a metterli
      al posto giusto sono le `grid-area`, che dall'ordine del DOM non dipendono.
      ⚠️ `.rap-file-meta` è `display: contents`: è un puro involucro senza sfondo né
      bordo, e serve che i suoi due figli entrino nella griglia del NONNO. Su un div
      vuoto di semantica è l'uso per cui `display: contents` esiste. */
/* ⚠️ Le AREE si dichiarano anche nel caso a una colonna, non solo in quello a due.
   Un `grid-area: file` che non trova l'area corrispondente non viene ignorato: diventa
   un nome di LINEA inesistente, il browser crea tracce implicite e gli elementi finiscono
   sovrapposti in una colonna fantasma. Succedeva su ogni campo file SENZA anteprima -
   cioè su ogni record nuovo e sull'allegato PDF. Dichiarandole sempre, la stessa regola
   vale nei due casi e il layout degrada in modo sano anche dove `:has()` non arrivasse. */
/* 🐛 4.9 (2026-08-07) — `align-content: start` è LOAD-BEARING, non una rifinitura.
   Il campo file è una griglia, ma è anche una colonna Bootstrap, cioè un elemento
   flex che la riga ALLUNGA fino all'altezza del vicino più alto. Con l'altezza
   così imposta dall'esterno, il valore iniziale di `align-content` (stretch)
   spalma lo spazio avanzato su TUTTE le righe automatiche, comprese quelle vuote.
   Accanto a un campo immagine con anteprima si vedeva così:
     · l'etichetta del secondo campo più bassa di quella del primo (la riga `pv`,
       vuota, si prendeva la sua fetta e spingeva giù tutto il resto);
     · le indicazioni staccate dal campo di una novantina di pixel (la fetta della
       riga `alt`, anch'essa vuota, si apriva in mezzo).
   Segnalato dal campo su lcNews di perego. `start` impacchetta le righe in alto e
   le righe vuote tornano a valere zero. */
.rap-file-field {
	display: grid;
	gap: 0 var(--space-5);
	grid-template-areas: "pv" "file" "alt" "hints" "nota";
	align-content: start;
	align-items: start;
}
.rap-file-meta  { display: contents; }

/* ⚠️ Due colonne SOLO con un'anteprima vera, cioè un'IMMAGINE. Un allegato non
   visualizzabile (il PDF) produce lo stesso `.current-file-link`, ma dentro c'è il
   nome del file: una colonna da 200px per due parole, e il selettore del file
   strizzato in quello che resta. Lì si resta a colonna singola (regola sotto). */
.rap-file-field:has(.current-file-link img) {
	grid-template-columns: minmax(0, 200px) minmax(0, 1fr);
	/* ⚠️ L'anteprima attraversa le tre righe ed è più alta della loro somma: la
	   differenza va distribuita, e su righe tutte `auto` il browser la divide in
	   parti uguali - anche alla riga vuota del testo alternativo, che tornerebbe ad
	   aprire il buco di cui sopra. Con l'ultima riga flessibile l'avanzo finisce
	   tutto lì, sotto le indicazioni, dove non si vede. */
	grid-template-rows: auto auto 1fr auto;
	grid-template-areas:
		"pv file"
		"pv alt"
		"pv hints"
		"nota nota";
}
/* Allegato senza anteprima (PDF, documenti): colonna singola, e il nome del file
   allegato va SOTTO il selettore - se restasse sopra (l'ordine di default delle
   aree) spingerebbe giù l'etichetta e il campo tornerebbe disallineato dal vicino
   appena si carica un allegato. */
.rap-file-field:has(.current-file-link):not(:has(.current-file-link img)) {
	grid-template-areas: "file" "alt" "pv" "hints" "nota";
}
/* ⚠️ Indicazioni e anteprima si selezionano SENZA `>`: `display: contents` toglie
   `.rap-file-meta` dall'albero dei BOX, non da quello del DOM. I due figli diventano
   elementi della griglia del nonno, ma per i selettori restano figli dell'involucro -
   un `.rap-file-field > .rap-file-hints` non li raggiunge, e finivano piazzati a caso. */
.rap-file-field > .mb-3              { grid-area: file; }
.rap-file-field > .mb-3.rap-file-alt { grid-area: alt; }
.rap-file-field .rap-file-hints      { grid-area: hints; }
.rap-file-field .current-file-link   { grid-area: pv; }
/* 🐛 5.0 M5 - la NOTA del campo (`'info'` nel config, resa da act_ins_mod come
   `<p class="form">`) non aveva un'area: finiva in una traccia IMPLICITA, che la griglia
   apre sotto la prima colonna - cioe' incolonnata sotto l'anteprima, in ~200px. Su una nota
   lunga - il campo immagine di lcBanners ne ha una da 400 caratteri - diventava una striscia
   altissima e strettissima a sinistra, con mezza scheda vuota a destra. Segnalata dal campo.
   ⭐ Ora ha la sua riga, **a tutta larghezza in fondo**: e' una nota che riguarda il campo
   intero, non l'anteprima, e a due colonne non c'entra da nessuna delle due parti.
   ⚠️ Vale per QUALUNQUE campo file con `info`, non solo per i banner. */
.rap-file-field > p.form             { grid-area: nota; margin-bottom: 0; }


/* ============================================================================
   4.9 M1 — LISTA RECORD SUL TELEFONO
   ----------------------------------------------------------------------------
   Il difetto (audit, report `511`): la riga di lista è una tabella a 6 colonne
   larga ~711px, e con ~372px di schermo utile restano FUORI proprio le due cose
   che servono - la colonna AZIONI e l'INTERRUTTORE di stato, cioè il comando
   più usato del pannello. In `act_list` non c'era una sola regola responsive:
   nessuna colonna veniva mai nascosta, a nessuna larghezza.

   Il rimedio: sotto il breakpoint md la riga smette di essere una riga di
   tabella e diventa una SCHEDA. Ordine voluto:

       [miniatura]  Titolo del record          [interruttore]
                    badge · date
       ─────────────────────────────────────────────────────
       [azioni]

   ⭐ Perché FLEX e non GRID: la riga NON ha un numero fisso di celle. Oltre a
   quelle note (selezione, ordine, miniatura, titolo, azioni, stato) un modulo
   può averne altre - `files_exist`, colonne aggiunte dagli hook di sito. Con
   grid finirebbero in posizioni impreviste; con flex + `order` si accodano in
   fondo a tutta larghezza senza rompere nulla.

   ⚠️ Selezione multipla e maniglia di trascinamento si nascondono: valgono
   ~200px dei ~372 utili e col dito non si usano comunque. Nascondere
   `.ordertd` **disattiva anche il drag&drop**, perché SortableJS è agganciato
   a quella maniglia (`handle: '.ordertd'`, js/func.js) - ed è voluto: sennò
   basterebbe uno scorrimento storto per riordinare il catalogo. Riordino e
   azioni di massa restano lavoro da scrivania.
   ============================================================================ */

@media (max-width: 767.98px) {

	/* Non ci sono più colonne da intestare. */
	.rap-list-table thead { display: none; }

	.rap-list-table,
	.rap-list-table tbody { display: block; width: 100%; }

	.rap-list-table tbody tr {
		display: flex;
		flex-wrap: wrap;
		align-items: flex-start;
		gap: var(--space-3) var(--space-4);
		padding: var(--space-4) var(--space-3);
		border-bottom: 1px solid var(--border-soft);
	}
	.rap-list-table tbody tr:last-child { border-bottom: 0; }

	/* Le celle perdono i bordi di tabella: il bordo è quello della scheda.
	   ⚠️ `padding: 0` deve essere `!important`: Tabler dà alle celle di bordo un
	   `.card-table td:first-child { padding-left: 1.5rem }` con specificità più alta di
	   questo selettore. Senza, la cella della miniatura conservava ~20px di rientro,
	   l'immagine (larga quanto la cella) partiva spostata e **sfondava di 20px dentro il
	   titolo**: sull'elenco categorie del catalogo di perego il nome finiva scritto sopra
	   la foto. Il distacco fra le celle lo dà il `gap` della riga, non il padding. */
	.rap-list-table tbody td {
		display: block;
		border: 0 !important;
		padding: 0 !important;
		width: auto;
		order: 5;          /* default: le celle non previste vanno in fondo… */
		flex: 1 0 100%;    /* …a tutta larghezza, senza spostare le altre */
	}

	.rap-list-table tbody td:has(> .bulk-check),
	.rap-list-table tbody td.ordertd { display: none; }

	/* ⚠️ La larghezza va messa sulla CELLA, non solo sull'immagine: la cella della miniatura
	   si teneva 100px dei ~372 utili e al titolo ne restavano 131. E serve azzerare il
	   `min-width: 100px` che arriva dalla veste della lista: un `width` più stretto NON lo
	   batte - il minimo vince sempre sulla larghezza. */
	.rap-list-table tbody .rap-row-thumb   { order: 1; flex: 0 0 56px; width: 56px; min-width: 0; }
	/* ⚠️ `flex-basis: 60%` e non `0`: il ritorno a capo si decide sulle BASI, non sulle
	   larghezze finali. Con base 0 la somma thumb+titolo+azioni+stato restava sotto la
	   larghezza della scheda e finiva tutto su UNA riga; con 60% il titolo si prende la
	   prima riga (e cresce a riempirla), e azioni+interruttore vanno a capo insieme. */
	.rap-list-table tbody .rap-row-main    { order: 2; flex: 1 1 60%; min-width: 0; }
	/* Interruttore in fondo alla riga delle azioni, spinto a destra dal margine
	   automatico: è la posizione chiesta dal campo - il pollice ce l'ha già lì. */
	.rap-list-table tbody .rap-row-actions { order: 4; flex: 1 1 auto; }
	.rap-list-table tbody .rap-status-cell { order: 5; flex: 0 0 auto; margin-left: auto; text-align: right; align-self: center; }

	/* Un titolo lungo va a capo invece di allargare la scheda. */
	.rap-list-table .rap-row-main { overflow-wrap: anywhere; }

	/* ⭐ Fuori la riga "Inserito … - Ultima modifica …" (2026-08-05, richiesta dal campo).
	   Vale per TUTTE le liste, non solo per una: dal telefono ci si lavora di ripiego -
	   il cliente in ferie apre il pannello per un ritocco, non per una revisione - e chi
	   ha inserito un record e quando, lì, non serve quasi mai. Costava tre righe di testo
	   su quattro di scheda. Da 768px in su resta esattamente com'era.
	   ⚠️ Selettore su `small` come ELEMENTO, a qualsiasi profondità: nelle liste dei moduli
	   è figlio diretto della cella, nell'elenco pagine (`ed_list`) sta dentro il div che fa
	   l'indentazione della gerarchia. Il numero di record delle categorie, che deve
	   restare, è invece uno `<span class="small">` - una classe, non un elemento.
	   ⚠️ `!important` obbligatorio: la riga porta `d-block` di Bootstrap, che è a sua volta
	   `display: block !important` - senza, questa regola non ha alcun effetto. */
	.rap-list-table .rap-row-main small { display: none !important; }

	/* Azioni: area di tocco vera (erano 20×17px).
	   ⚠️ NIENTE bordo/padding solo qui: azioni e interruttore stanno sulla stessa riga ma
	   sono due celle distinte, e un `padding-top` su una sola spingeva giù le icone
	   lasciando l'interruttore appeso più in alto. Lo stacco dal titolo lo dà già il `gap`
	   della riga; l'allineamento verticale lo dà `align-self: center` su entrambe. */
	.rap-list-table .rap-row-actions {
		display: flex;
		flex-wrap: wrap;
		align-items: center;
		gap: var(--space-2);
		align-self: center;
	}
	.rap-list-table .rap-row-actions .rap-act {
		display: inline-flex;
		align-items: center;
		justify-content: center;
		min-width: 44px;
		min-height: 44px;
	}

	/* (l'area di tocco dell'interruttore di stato non è più qui: vale a ogni larghezza,
	   vedi la regola fuori da questa media query) */

	/* La miniatura non deve mangiarsi mezza scheda. `100%` e non `56px`: così l'immagine è
	   legata alla SUA cella e non può traboccarne, qualunque cosa succeda al contorno. */
	.rap-list-table .rap-row-thumb img,
	.rap-list-table .rap-row-thumb .rap-row-ini { max-width: 100%; }

	/* Rientro delle sottocategorie: `ps-3`/`ps-5` di Bootstrap valgono 1 e 3 rem, che su
	   225px di titolo sono tanti. Dimezzati: la gerarchia si legge lo stesso. */
	.rap-list-table tbody .rap-row-main.ps-3 { padding-left: .5rem !important; }
	.rap-list-table tbody .rap-row-main.ps-5 { padding-left: 1.25rem !important; }

	/* ── 4.9 M2 — rifiniture ────────────────────────────────────────────────
	   ⚠️ `.rap-meta-who` è un tooltip: sul telefono NON si apre (non c'è il
	   passaggio del mouse), ma il tratteggio resta e si legge come un link da
	   toccare. Si toglie la decorazione: l'informazione è già tutta nel testo,
	   il tooltip resta per chi sta al computer. */
	.rap-list-table .rap-meta-who {
		text-decoration: none;
		border-bottom: 0;
		cursor: default;
	}

	/* Il filtro Stato stava a 96px. ⚠️ Il problema NON era la select (un `width:100%`
	   su di lei non serve a niente): era il suo contenitore `d-flex`, largo quanto
	   il contenuto - il 100% di 96px fa 96px. Si allarga la riga, e la select prende
	   lo spazio che resta accanto all'etichetta. */
	div:has(> .rap-list-filter) { width: 100%; }
	.rap-list-filter           { flex: 1 1 auto; width: auto !important; }

	/* 🐛 2026-08-07 — IL SELETTORE DI CATEGORIA SBORDAVA (trovato sull'elenco prodotti di
	   perego: 541px dentro 380 di schermo, con la parte destra semplicemente TAGLIATA, non
	   scorrevole). La regola qui sopra allarga il `div` interno, ma quel div sta dentro un
	   `<form>` che è a sua volta un elemento flex e si dimensiona sul CONTENUTO: cioè sulla
	   voce più lunga del menu a tendina, che su un albero di 294 categorie è lunghissima.
	   Il tetto va messo sul form, e serve `min-width: 0` perché un elemento flex, di suo,
	   si rifiuta di stringersi sotto la propria larghezza minima. */
	#form_sel_cat            { flex: 1 1 100%; min-width: 0; max-width: 100%; }
	#form_sel_cat .form-select { max-width: 100%; }
	/* ⚠️ E la riga interna deve poter andare a capo: accanto al menu c'è anche il pulsante
	   «Seleziona» (il percorso senza JS), e con la tendina già larga quanto lo schermo il
	   pulsante restava fuori - stesso taglio di prima, 30px più in là. Il `gap` della riga
	   fa da distanza anche fra le due righe. */
	div:has(> .rap-list-filter) { flex-wrap: wrap; }

	/* ⭐ Le barre a tab non vanno MAI a capo (richiesta dal campo, 2026-08-06: in
	   `ed_ins_mod` "Revisioni" finiva su una riga sua sotto CONTENUTO/IMPOSTAZIONI/SEO).
	   Una nav che va a capo non si legge come una barra: la seconda riga sembra un
	   elemento di un'altra cosa. Meglio una riga sola che scorre di lato.
	   ⚠️ Vale per tutte le barre del pannello, non solo per quella delle pagine: la
	   stessa cosa succedeva alle tre finestre delle statistiche promo. */
	.nav-tabs                { flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none; }
	.nav-tabs::-webkit-scrollbar { display: none; }
	.nav-tabs .nav-link      { white-space: nowrap; }

	/* "+1 nel mese" accanto al numero: regola ora GLOBALE (vedi .rap-kpi-value/-delta
	   più sopra, 2026-09-03), non serve più ripeterla qui sotto i 768px. */
}

/* ⭐ 4.9 M2-ter (2026-08-07) — AREA DI TOCCO DELL'INTERRUTTORE IN LISTA, A OGNI LARGHEZZA.
   L'area che risponde al tocco è il LABEL, non il cursore, ed era 85×24: larga ma bassa. La
   M1 l'aveva alzata a 44, ma **solo sotto i 768px** - cioè la copertura finiva dove i
   dispositivi touch non finiscono affatto: su un tablet in orizzontale, o su un portatile
   touch, si tornava a 24px di bersaglio.
   ⚠️ Si alza l'AREA, non il disegno: il cursore resta 40×24 (ingrandirlo ha già rotto il
   layout una volta, il float di Tabler si incastra su misure precise).
   ⭐ Fuori da qualsiasi media query perché **non costa niente**: misurata sul pannello vero,
   la riga di lista è alta **85px a 768, 992 e 1440**, con 61px di spazio interno - 44 ci
   stanno comodi e nulla si sposta. */
.rap-list-table .rap-status-cell label { min-height: 44px; }

.rap-file-hints {
	margin: 0 0 var(--space-3);
	font-size: var(--text-xs);
	line-height: var(--leading-normal, 1.5);
	color: var(--text-muted);
}
.rap-file-field .current-file-link {
	margin: 0;
	font-size: var(--text-xs);
	color: var(--text-muted);
}
/* `width`/`height` al 50% sono attributi HTML messi dal PHP sulle anteprime grandi:
   qui l'immagine si adatta alla colonna, che è la misura che conta. */
.rap-file-field .current-file-link img {
	display: block;
	width: auto !important;
	height: auto !important;
	max-width: 100%;
	max-height: 260px;
	margin: var(--space-2) 0;
	padding: var(--space-1);
	border: 1px solid var(--border-soft);
	border-radius: var(--radius-md);
	background-color: var(--surface-2);
}
/* Il pulsante "Usa il titolo" sta a destra del campo: stesse cuciture del gruppo slug */
.rap-alt-group > .btn { white-space: nowrap; }
#form_ins_mod .rap-alt-group > .form-control,
#rap_cat_ins_mod .rap-alt-group > .form-control { width: 1% !important; flex: 1 1 auto; }

/* Sotto i 700px la colonna dell'anteprima non lascia spazio ai comandi: si impila. */
@media (max-width: 699.98px) {
	.rap-file-field:has(.current-file-link img) {
		grid-template-columns: minmax(0, 1fr);
		/* ⚠️ Le righe si riportano ad `auto`: `auto auto 1fr` è scritto per le TRE righe
		   del layout a due colonne, qui le aree tornano quattro e la riga flessibile
		   cadrebbe su `alt` - cioè sulla riga vuota, che si riaprirebbe. */
		grid-template-rows: none;
		/* 🔴 `nota` VA ELENCATA ANCHE QUI. Le dichiarazioni di `grid-template-areas` per
		   questo campo sono QUATTRO (base, due colonne, senza anteprima, e questa): se se
		   ne dimentica una, `grid-area: nota` punta a un'area che li' non esiste e il
		   browser apre COLONNE IMPLICITE - misurato sotto i 700px: da una colonna da 298px
		   a `0px 0px 274px`, con indicazioni e anteprima schiacciate a larghezza ZERO e
		   alte 2467 e 660 pixel. Una riga dimenticata, tutta la scheda a pezzi. */
		grid-template-areas: "pv" "file" "alt" "hints" "nota";
	}
	.rap-file-field .current-file-link img { max-width: 200px; }
	/* Sotto questa soglia un campo file non sta in una frazione di riga: il selettore
	   del sistema operativo ("Scegli file" + nome) vuole i suoi ~200px e un `cols`
	   scritto per lo schermo grande lo ridurrebbe a un bottone mozzato. Qui prende
	   tutta la riga, qualunque `col-sm-*` gli abbia messo il config del modulo. */
	.rap-file-field[class*="col-sm-"] { width: 100%; }
}

/* 4.7 M1 — badge della campanella. Stesso rosso "pieno" del bottone distruttivo:
   il numero è minuscolo (0.55rem da main.css) e col rosso dei pallini stava a 4.37:1. */
.rap-ntf-badge {
	background: var(--danger-fill);
	color: var(--danger-fill-fg);
	box-shadow: 0 0 0 1.5px var(--surface-1);
}
.rap-ntf-title { color: var(--text-heading); font-weight: var(--weight-semibold); }
.rap-ntf-text  { color: var(--text-body); }

/* 4.1 M6 / 4.7 M2 — aiuto in linea e centro aiuto */
.rap-help > summary { background-color: var(--accent-soft) !important; color: var(--accent-text-soft); }   /* neutralizza main.css */
.rap-help-body { color: var(--text-body); }
.rap-help-index { color: var(--text-secondary); }

/* Note dei moduli: l'accento seguiva un hex cablato in main.css. Dentro un box
   `--accent-soft` il testo va su `--accent-text-soft` (6.44:1); l'accento pieno
   ci starebbe a 4.38:1, sotto AA. Il pallino dell'elenco resta accento pieno:
   è decorativo, non testo. */
.alert .note-title, .alert .note-intro { --note-accent: var(--accent-text-soft); color: var(--accent-text-soft); }
.alert .note-list li::before { --note-accent: var(--accent); }
.alert .note-list code { color: var(--danger); background: var(--danger-soft); }

/* ── 4.8 — La "scheda note" diventa un BOX BIANCO con icona e titolo (ricetta dei
      mockup). Prima era un alert tinto di accento: dentro una pagina che ha già le sue
      card, una fascia colorata a piè di elenco urla più di quanto valga il suo contenuto.
      ⚠️ Si aggancia con `:has(.note-card)` invece di aggiungere una classe: il contenitore
      è emesso da OTTO punti del core (liste, form, categorie, campi, moduli, pagine…) e
      il contenuto arriva dai file di lingua dei 21 siti. Così non si tocca né l'uno né
      l'altro. Le note ancora nel vecchio formato `<p class="note">` non hanno `.note-card`
      e restano com'erano: la conversione è progressiva (skill `/note-moduli`). */
.alert-info:has(.note-card) {
	background-color: var(--surface-1) !important;
	border: 1px solid var(--border-soft);
	border-radius: var(--radius-2xl);
	color: var(--text-body);
	padding: var(--gap-card) var(--space-6);
}
.alert-info:has(.note-card) .note-title {
	display: flex;
	align-items: center;
	gap: var(--gap-inline);
	color: var(--text-heading);
	font-size: var(--text-base);
	letter-spacing: 0;
	text-transform: none;
	margin-bottom: var(--space-4);
}
/* L'icona è il glifo del font tabler già caricato dal pannello: nessuna richiesta in più
   e segue il colore del testo. */
.alert-info:has(.note-card) .note-title::before {
	content: "\eac5";
	font-family: "tabler-icons";
	font-weight: normal;
	font-size: 17px;
	line-height: 1;
	color: var(--accent);
}
.alert-info:has(.note-card) .note-intro {
	color: var(--text-secondary);
	border-left-color: var(--border);
}
/* Elenco: puntato MANTENUTO (l'accorpamento del mockup si legge peggio), ma più compatto -
   un punto di corpo in meno e meno aria fra le voci. */
.alert-info:has(.note-card) .note-intro,
.alert-info:has(.note-card) .note-list { font-size: var(--text-sm); }
.alert-info:has(.note-card) .note-list { gap: var(--space-4); }
.alert-info:has(.note-card) .note-list li { line-height: var(--leading-normal); }
.alert-info:has(.note-card) .note-list li::before { top: .45em; }


/* ════════════════════════════════════════════════════════════
   Librerie di terze parti — si armonizzano, non si sostituiscono
   ════════════════════════════════════════════════════════════ */

/* Tom Select (selettori categorie/tag) */
.ts-control {
	background-color: var(--field-bg-filled) !important;   /* neutralizza il tema bootstrap5 di tom-select */
	border-color: var(--field-border-filled) !important;
	border-radius: var(--radius-lg) !important;
	color: var(--text-body);
	min-height: var(--control-height);
}
.ts-wrapper.focus .ts-control { border-color: var(--accent) !important; box-shadow: var(--focus-shadow); }
.ts-control .item {
	background-color: var(--accent-soft) !important;
	color: var(--accent-text-soft) !important;
	border-radius: var(--radius-sm) !important;
	border: 0 !important;
	font-size: var(--text-sm);
	font-weight: var(--weight-medium);
}
.ts-dropdown {
	--bs-body-bg: var(--surface-1);
	--bs-body-color: var(--text-body);   /* il tema bootstrap5 di tom-select legge QUESTA */
	background-color: var(--surface-1);
	border: 1px solid var(--border-soft);
	border-radius: var(--radius-xl);
	box-shadow: var(--shadow-md);
	color: var(--text-body);
}
/* ⚠️ Il colore delle voci va messo ESPLICITAMENTE, non lasciato ereditare dal dropdown:
   basta una regola di tom-select (o del suo tema bootstrap5) su `.option` per scavalcare
   l'ereditarietà, e nel tema scuro il risultato è scuro-su-scuro, cioè voci invisibili.
   Segnalato dal campo il 2026-08-06 sul selettore "Gruppi utenti" del form utente.
   Il contenuto prende anche il fondo: se il dropdown viene reso fuori dal suo contenitore
   (tom-select sa spostarlo) il fondo del genitore non è più garantito. */
.ts-dropdown,
.ts-dropdown .ts-dropdown-content { background-color: var(--surface-1); }
.ts-dropdown .option,
.ts-dropdown .optgroup-header,
.ts-dropdown .no-results,
.ts-dropdown .create { color: var(--text-body); }
.ts-dropdown .optgroup-header { color: var(--text-secondary); }
.ts-dropdown .option[data-disabled],
.ts-dropdown .option.disabled { color: var(--text-disabled); }
.ts-dropdown .active { background-color: var(--accent-soft); color: var(--accent-text-soft); }

/* Flatpickr (campi data) */
.flatpickr-calendar {
	background: var(--surface-1);
	border: 1px solid var(--border-soft);
	border-radius: var(--radius-xl);
	box-shadow: var(--shadow-md);
	color: var(--text-body);
}
.flatpickr-months .flatpickr-month, .flatpickr-weekdays, span.flatpickr-weekday {
	background: var(--surface-1);
	color: var(--text-secondary);
	fill: var(--text-secondary);
}
.flatpickr-day { color: var(--text-body); border-radius: var(--radius-md); }
.flatpickr-day:hover { background: var(--surface-3); border-color: transparent; }
.flatpickr-day.selected, .flatpickr-day.selected:hover {
	background: var(--accent);
	border-color: var(--accent);
	color: var(--text-on-primary);
}
.flatpickr-day.today { border-color: var(--accent); }
/* Giorni del mese precedente/successivo: restano volutamente attenuati (come in ogni
   date picker), ma sono CLICCABILI - portano al mese vicino - quindi devono stare
   sopra AA. `--text-faint` li dava a 2.86:1 (misurato il 2026-08-02, 2° giro): si
   passa al grigio muted, 4.94:1 su bianco, che resta comunque più chiaro dei giorni
   del mese corrente. Il default di flatpickr era ~1.9:1. */
.flatpickr-day.prevMonthDay, .flatpickr-day.nextMonthDay { color: var(--text-muted); }
.flatpickr-day.flatpickr-disabled { color: var(--text-disabled); }

/* TinyMCE — il chrome dell'editor deve stare dentro la card, non sopra.
   ℹ️ Il tema scuro dell'editor NON si rincorre con override CSS (sarebbe fragile e
   vale la regola «armonizzare, non sostituire»): TinyMCE non legge le nostre
   variabili. La via supportata è scegliere la skin al momento dell'init, ed è ciò che
   `js/func.js` fa dalla M2 — `skin:'oxide-dark'` + `content_css:'dark'` quando il
   tema attivo è scuro. CodeMirror usa invece SEMPRE `oneDark`, in entrambi i temi:
   è una scelta, non una svista, ed è il motivo per cui l'audit di contrasto segnala
   il suo gutter (3.6-3.9:1) - colori della libreria, fuori dal nostro perimetro. */
.tox.tox-tinymce {
	border: 1px solid var(--field-border-filled) !important;   /* neutralizza lo skin oxide */
	border-radius: var(--radius-lg) !important;
}
.tox .tox-editor-header { box-shadow: none !important; border-bottom: 1px solid var(--border-faint) !important; }
/* Link di branding nella barra di stato: la skin lo dà a ~1.5:1 sul fondo scuro,
   cioè praticamente invisibile. Non è testo nostro, ma sta dentro il nostro pannello. */
.tox .tox-statusbar a, .tox .tox-statusbar__branding a { color: var(--text-muted) !important; }   /* neutralizza lo skin */

/* 5.0 M7 — AREE DI TOCCO della barra dell'editor.
   Trovato dal giro visivo del 2026-08-22 (report `736`): la skin oxide dà ai pulsanti
   `height: 28px` e alla freccetta del pulsante composto `width: 16px`.
   🔴 Le due misure NON sono la stessa cosa, e vale la pena distinguerle invece di
   fare un unico ritocco «per accessibilità»:
     · i 28px di altezza passano WCAG 2.2 AA (il minimo è 24x24) e stanno sotto la
       soglia di 32 che ci siamo dati NOI, la stessa che la 4.9 M2-ter ha applicato ai
       nostri interruttori;
     · i **16px di larghezza** della freccetta sono sotto il minimo dello STANDARD.
   Qui si alzano entrambe, ma con due perimetri diversi, e la differenza è la ragione
   di cui sopra: l'altezza è una soglia NOSTRA e vale solo sotto md - sul desktop c'è il
   mouse, e allargare la barra le farebbe occupare una riga in più per niente - mentre la
   larghezza della freccetta è il minimo dello STANDARD e vale a ogni larghezza.
   ⚠️ `body` in testa al selettore NON è decorativo: la skin dichiara `.tox .tox-tbtn`
   con la nostra stessa specificità (0,2,0) e viene iniettata dall'editor a runtime,
   quindi DOPO questo foglio. A parità vincerebbe lei. Con `body` si passa a (0,2,1) e
   l'ordine di caricamento smette di contare.
   ℹ️ Nessun `height` fisso sul gruppo: `.tox-toolbar__group` è flex con `flex-wrap`,
   quindi la barra cresce di 4px e non taglia nulla. */
/* La freccetta sta FUORI dalla media query dal 2026-08-25: i 24x24 di WCAG 2.2 sono un
   minimo che NON dipende dal puntatore, quindi 16px sono sotto lo standard anche sul
   desktop. Costo misurato: la barra ha due soli pulsanti composti (`forecolor` e
   `backcolor`), cioè +16px in tutto su una barra larga centinaia di pixel. */
body .tox .tox-split-button__chevron { width: 24px; }

@media (max-width: 767.98px) {
	body .tox .tox-tbtn { height: 32px; }
}

/* CodeMirror — la scrollbar chiara serviva il tema scuro dell'editor */
.cm-editor { border-radius: var(--radius-lg); overflow: hidden; }
.cm-editor.cm-focused { outline: none !important; box-shadow: var(--focus-shadow); }

/* 4.9 (2026-08-07) — FONDO DELL'EDITOR nella palette del pannello (solo tema scuro: nel
   chiaro i token valgono il oneDark di sempre, quindi queste due righe non cambiano nulla).
   ⚠️ NON si usano le classi generate da CodeMirror (`.ͼo`, `.ͼ1`, `.ͼ15`…): non sono API,
   se le fabbrica `style-mod` a runtime contandole, e la stessa `.cm-editor` di questo
   pannello ne porta cinque. Ricostruire il bundle o montare un altro StyleModule le
   rinumera, e la regola smetterebbe di applicarsi senza che nulla lo segnali. Si usano le
   classi PUBBLICHE `.cm-editor` / `.cm-gutters`.
   ⚠️ Sulla specificità non serve `!important`: `style-mod` inserisce il suo `<style>` come
   PRIMO figlio di `<head>` (verificato), quindi i nostri fogli vengono dopo e a parità di
   peso vincono. `.cm-editor` pareggia `.ͼo` (0,1,0) e `.cm-editor .cm-gutters` pareggia
   `.ͼo .cm-gutters` (0,2,0). */
.cm-editor { background-color: var(--cm-bg); }
.cm-editor .cm-gutters { background-color: var(--cm-gutter-bg); }


/* --- Scrollbar --------------------------------------------------- */

* { scrollbar-color: var(--scrollbar-thumb) transparent; scrollbar-width: thin; }
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: var(--scrollbar-thumb); border-radius: var(--radius-pill); border: 2px solid transparent; background-clip: content-box; }
