/* ═══════════════════════════════════════════════════════════════════════════
   IODAH Intelligence Portal — foglio di stile di base
   Riferimento normativo: CLAUDE.md §5 (design system) e §6 (shell del viewer).

   Regola d'oro di questo file: nessun colore letterale fuori dal blocco
   dei token al §2. Se un valore esadecimale compare altrove, è un errore.

   Indice
     1. Font
     2. Token
     3. Reset e base
     4. Ponte verso Bootstrap 5
     5. Tipografia
     6. Componenti
     7. Layout
     8. Utility
     9. Responsive e preferenze di sistema
   ═══════════════════════════════════════════════════════════════════════════ */


/* ═══ 1. Font ══════════════════════════════════════════════════════════════
   Poppins self-hostato in /public/fonts. Nessuna chiamata a Google Fonts:
   l'IP degli utenti non deve uscire da questo server (requisito PA) e la CSP
   resta senza domini esterni.
   Sottoinsiemi: latin + latin-ext. Pesi: 400, 500, 600, 700.
   ═══════════════════════════════════════════════════════════════════════════ */

/* Dune Rise — font display del marchio, lo stesso di agents.iodah.com.
   SIL Open Font License 1.1, copia in /public/fonts/Dune_Rise-OFL.txt.
   Convertito da TTF a WOFF2: 23 KB → 7 KB.
   È un carattere decorativo a sole maiuscole: si usa sul marchio e sui titoli
   brevi, mai sul testo corrente. */
@font-face {
  font-family: 'Dune Rise';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/fonts/dune-rise-400-normal.woff2') format('woff2');
}

@font-face {
  font-family: 'Poppins';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/fonts/poppins-latin-400-normal.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Poppins';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/fonts/poppins-latin-ext-400-normal.woff2') format('woff2');
  unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF,
    U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: 'Poppins';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('/fonts/poppins-latin-500-normal.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Poppins';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('/fonts/poppins-latin-ext-500-normal.woff2') format('woff2');
  unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF,
    U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: 'Poppins';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('/fonts/poppins-latin-600-normal.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Poppins';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('/fonts/poppins-latin-ext-600-normal.woff2') format('woff2');
  unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF,
    U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: 'Poppins';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('/fonts/poppins-latin-700-normal.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Poppins';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('/fonts/poppins-latin-ext-700-normal.woff2') format('woff2');
  unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF,
    U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}


/* ═══ 2. Token ═════════════════════════════════════════════════════════════ */

:root {

  /* ── Colori — CLAUDE.md §5 ──────────────────────────────────────────────
     Nota: il foglio di stile di IODAH Agent Insights usa un verde diverso
     (--accent #007959, chiaro #00a87a). Se si decide di allineare i due
     prodotti, bastano le tre righe --primary / --primary-hover / --primary-soft
     qui sotto, più --primary-rgb. Nient'altro nel progetto tocca il verde. */

  --bg:             #0A0E12;   /* fondo pagina, nero bluastro */
  --bg-alt:         #0D141B;   /* sezioni alternate */
  --surface:        #111A22;   /* card */
  --surface-hover:  #16212B;
  --surface-sunken: #0D1319;   /* campi di input, aree incassate */

  --border:         rgba(255, 255, 255, 0.07);
  --border-strong:  rgba(255, 255, 255, 0.14);   /* bordo in stato hover/focus */

  --primary:        #10B981;   /* verde IODAH */
  --primary-hover:  #0EA372;
  --primary-soft:   rgba(16, 185, 129, 0.12);    /* fondo tile icone */
  --primary-rgb:    16, 185, 129;
  --on-primary:     #04120C;   /* testo sul pulsante primario */

  --text:           #F2F6F8;
  --text-muted:     #93A4B3;
  --text-dim:       #5A6A7E;   /* metadati, timestamp, note di servizio */

  --danger:         #E5556B;
  --danger-rgb:     229, 85, 107;
  --warning:        #F0B23C;   /* allineato al tema Power BI, CLAUDE.md §8 */
  --info:           #5EAAD8;
  --success:        var(--primary);

  /* ── Tipografia ─────────────────────────────────────────────────────────
     Tre famiglie, con ruoli distinti:
       --font-ui       testo, interfaccia, tutto il resto
       --font-heading  titoli — resta Poppins, che regge testi lunghi
       --font-display  marchio e titoli brevi in maiuscolo — Dune Rise, lo
                       stesso di agents.iodah.com
     Dune Rise è decorativo: usarlo su un paragrafo o su un H1 lungo lo rende
     illeggibile. Per questo i titoli hanno una variabile propria e chi vuole
     un titolo "da marchio" applica la classe .title-display. */

  --font-ui: 'Poppins', system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
  --font-heading: var(--font-ui);
  --font-display: 'Dune Rise', var(--font-ui);
  --font-mono: ui-monospace, SFMono-Regular, 'Cascadia Mono', Menlo, monospace;

  --ls-display: 0.12em;   /* Dune Rise ha bisogno di respiro fra le lettere */

  --fs-h1: clamp(2rem, 1.25rem + 3.4vw, 3.5rem);   /* fino a 56px */
  --fs-h2: clamp(1.625rem, 1.15rem + 2.1vw, 2.5rem); /* fino a 40px */
  --fs-h3: clamp(1.25rem, 1.1rem + 0.7vw, 1.5rem);
  --fs-lead: clamp(1rem, 0.96rem + 0.2vw, 1.125rem);
  --fs-body: 1rem;      /* 16px */
  --fs-sm: 0.875rem;    /* 14px */
  --fs-label: 0.8125rem; /* 13px — label UI */
  --fs-xs: 0.75rem;     /* 12px — eyebrow */

  --lh-h1: 1.1;
  --lh-h2: 1.2;
  --lh-body: 1.65;

  --ls-eyebrow: 0.12em;
  --ls-label: 0.08em;

  /* ── Spaziature ─────────────────────────────────────────────────────── */

  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: 0.75rem;
  --space-4: 1rem;
  --space-5: 1.5rem;
  --space-6: 1.75rem;   /* padding della card, 28px */
  --space-7: 2.5rem;
  --space-8: 4rem;
  --space-9: 6rem;      /* respiro verticale fra sezioni */

  /* ── Raggi ──────────────────────────────────────────────────────────── */

  --radius-sm: 8px;
  --radius: 12px;       /* pulsanti, tile icona */
  --radius-lg: 16px;    /* card */
  --radius-pill: 999px;

  /* ── Ombre ──────────────────────────────────────────────────────────── */

  --bg-blur:        rgba(10, 14, 18, 0.85);   /* barra fissa, sopra il contenuto */

  /**
   * Fascia verde piena — la chiusura della landing.
   *
   * Non è `--primary`: il §5 dice che il verde acceso non va su grandi
   * superfici, e una fascia alta 500px di #10B981 è esattamente quello. Qui
   * serve un verde **profondo**, che regge il bianco sopra e non urla: è lo
   * stesso del sito nuovo, e nel tema scuro scende ancora un po' per non
   * staccarsi dal fondo.
   */
  --fascia:         #0A4527;
  --su-fascia:      #FFFFFF;

  --shadow-primary: 0 8px 24px rgba(var(--primary-rgb), 0.25);
  --shadow-overlay: 0 20px 60px rgba(0, 0, 0, 0.55);   /* dropdown, modali */

  /* ── Movimento ──────────────────────────────────────────────────────── */

  --t-fast: 120ms;
  --t: 200ms;
  --t-slow: 320ms;
  --ease: cubic-bezier(0.2, 0, 0.2, 1);

  /* ── Piani ──────────────────────────────────────────────────────────── */

  --z-sidebar: 1030;
  --z-topbar: 1040;
  --z-dropdown: 1050;
  --z-overlay: 2000;

  /* ── Misure della shell del portale — CLAUDE.md §6 ───────────────────
     Dichiarate qui perché sono decisioni di design, non di implementazione.
     Le userà il viewer allo step E5. */

  --topbar-h: 48px;
  --sidebar-w: 220px;
  --sidebar-w-collapsed: 56px;
  --content-max: 1240px;
}


/* ═══ Tema chiaro ══════════════════════════════════════════════════════════
   ═══════════════════════════════════════════════════════════════════════════

   ┌── UN SOLO BLOCCO DI TOKEN, NESSUN COMPONENTE RISCRITTO ─────────────────┐
   │ Il tema chiaro non ha un foglio suo e non tocca nessuna regola dei        │
   │ componenti: ridefinisce **solo** i token. È possibile perché nel progetto │
   │ i colori scritti a mano fuori da `:root` erano dieci, e nove erano tinte │
   │ traslucide che funzionano su entrambi i fondi; il decimo — il fondo della │
   │ barra fissa — è diventato `--bg-blur` mentre si scriveva questo blocco.  │
   │                                                                          │
   │ Il corollario vale per il futuro: **un componente nuovo che scrive un     │
   │ colore invece di usare un token funziona in un tema solo**, e nessun      │
   │ errore lo segnala. Si scopre guardando la pagina nell'altro tema.         │
   └──────────────────────────────────────────────────────────────────────────┘

   ┌── PERCHÉ IL VERDE CAMBIA ───────────────────────────────────────────────┐
   │ `#10B981` sul fondo scuro sta a 7,6:1; su bianco sta a 2,2:1, cioè       │
   │ illeggibile. Nel tema chiaro il primario diventa `#0B6839` — il verde    │
   │ profondo del sito nuovo — che su bianco sta a 6,9:1. Non è una scelta     │
   │ estetica: è l'unico modo di avere un primario che si legge su carta.      │
   │ Di conseguenza il testo sul pulsante primario passa da quasi-nero a       │
   │ bianco.                                                                  │
   └──────────────────────────────────────────────────────────────────────────┘

   I valori sono verificati, non scelti a occhio: sul fondo carta il testo sta
   a 17:1, il secondario a 6,5:1, i metadati a 5,0:1 e tutti i toni — primario,
   errore, avviso, informazione — fra 5,4:1 e 6,3:1. */

[data-tema='chiaro'] {
  --bg:             #F5F5F5;   /* la carta del sito nuovo */
  --bg-alt:         #FFFFFF;
  --surface:        #FFFFFF;
  --surface-hover:  #F0F1F2;
  --surface-sunken: #F7F7F8;
  --bg-blur:        rgba(245, 245, 245, 0.85);

  --fascia:         #0B6839;   /* il verde della fascia del sito nuovo */
  --su-fascia:      #FFFFFF;

  --border:         rgba(0, 0, 0, 0.10);
  --border-strong:  rgba(0, 0, 0, 0.22);

  --primary:        #0B6839;
  --primary-hover:  #095630;
  --primary-soft:   rgba(11, 104, 57, 0.10);
  --primary-rgb:    11, 104, 57;
  --on-primary:     #FFFFFF;

  --text:           #101418;
  --text-muted:     #4B5A67;
  --text-dim:       #5E6B77;

  --danger:         #B32B41;
  --danger-rgb:     179, 43, 65;
  --warning:        #8A5A00;
  --info:           #1A6491;

  /* Sul chiaro un'ombra da 0,55 di nero è una macchia: si alleggerisce. */
  --shadow-primary: 0 8px 24px rgba(var(--primary-rgb), 0.18);
  --shadow-overlay: 0 20px 60px rgba(0, 0, 0, 0.18);
}

/* La selezione del testo e la barra di scorrimento seguono il tema come tutto
   il resto: sono due punti in cui il fondo scuro si vede anche sul chiaro. */
[data-tema='chiaro'] ::selection {
  background: rgba(11, 104, 57, 0.18);
  color: var(--text);
}


/* ═══ 3. Reset e base ══════════════════════════════════════════════════════ */

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

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;

  /* La barra è appiccicata in cima: senza questo scarto, un'ancora porta il
     titolo della sezione **sotto** la barra, e chi ha cliccato «I moduli»
     atterra su un titolo che non vede. Il valore è l'altezza della barra
     (0,75rem di spazio sopra e sotto più il marchio) con un margine. */
  scroll-padding-top: 5rem;
}

/* Colonna verticale: tiene il footer in fondo anche sulle pagine corte. */
body {
  margin: 0;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  background-color: var(--bg);
  color: var(--text);
  font-family: var(--font-ui);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  font-weight: 400;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: hidden;
}

main {
  flex: 1 0 auto;
}

img,
svg {
  max-width: 100%;
  height: auto;
  vertical-align: middle;
}

hr {
  border: 0;
  border-top: 1px solid var(--border);
  opacity: 1;
  margin: var(--space-6) 0;
}

::selection {
  background: rgba(var(--primary-rgb), 0.28);
  color: var(--text);
}

/* Focus da tastiera sempre visibile — requisito di qualità minima del §5. */
:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 3px;
  border-radius: var(--radius-sm);
}

:focus:not(:focus-visible) {
  outline: none;
}

/* Barra di scorrimento discreta, coerente con il fondo scuro. */
* {
  scrollbar-width: thin;
  scrollbar-color: var(--surface-hover) transparent;
}

::-webkit-scrollbar {
  width: 8px;
  height: 8px;
}

::-webkit-scrollbar-track {
  background: transparent;
}

::-webkit-scrollbar-thumb {
  background: var(--surface-hover);
  border-radius: var(--radius-pill);
}

::-webkit-scrollbar-thumb:hover {
  background: var(--border-strong);
}

/* Salto al contenuto: visibile solo quando riceve il focus da tastiera. */
.skip-link {
  position: absolute;
  left: var(--space-4);
  top: -100px;
  z-index: var(--z-overlay);
  padding: var(--space-3) var(--space-5);
  background: var(--primary);
  color: var(--on-primary);
  border-radius: var(--radius);
  font-weight: 600;
  text-decoration: none;
  transition: top var(--t) var(--ease);
}

.skip-link:focus-visible {
  top: var(--space-4);
}


/* ═══ 4. Ponte verso Bootstrap 5 ═══════════════════════════════════════════
   Bootstrap 5.3 è costruito su variabili CSS. Rimappandole sui token IODAH,
   ogni componente Bootstrap che useremo dagli step successivi — tabelle,
   form, modali, dropdown, paginazione — nasce già scuro e coerente, senza
   override sparsi pagina per pagina.
   ═══════════════════════════════════════════════════════════════════════════ */

:root,
[data-bs-theme='dark'] {
  --bs-body-bg: var(--bg);
  --bs-body-bg-rgb: 10, 14, 18;
  --bs-body-color: var(--text);
  --bs-body-font-family: var(--font-ui);
  --bs-body-font-size: var(--fs-body);
  --bs-body-line-height: var(--lh-body);

  --bs-emphasis-color: var(--text);
  --bs-heading-color: var(--text);
  --bs-secondary-color: var(--text-muted);
  --bs-tertiary-color: var(--text-dim);

  --bs-secondary-bg: var(--bg-alt);
  --bs-tertiary-bg: var(--surface);

  --bs-border-color: var(--border);
  --bs-border-color-translucent: var(--border);
  --bs-border-radius: var(--radius);
  --bs-border-radius-sm: var(--radius-sm);
  --bs-border-radius-lg: var(--radius-lg);
  --bs-border-radius-pill: var(--radius-pill);

  --bs-primary: var(--primary);
  --bs-primary-rgb: var(--primary-rgb);
  --bs-primary-text-emphasis: var(--primary);
  --bs-primary-bg-subtle: var(--primary-soft);
  --bs-primary-border-subtle: rgba(var(--primary-rgb), 0.35);

  --bs-danger: var(--danger);
  --bs-danger-rgb: var(--danger-rgb);

  --bs-link-color: var(--primary);
  --bs-link-color-rgb: var(--primary-rgb);
  --bs-link-hover-color: var(--primary-hover);
  --bs-link-hover-color-rgb: var(--primary-rgb);

  --bs-focus-ring-color: rgba(var(--primary-rgb), 0.3);
  --bs-focus-ring-width: 3px;

  --bs-code-color: var(--primary);
  --bs-highlight-bg: var(--primary-soft);
}

/* I campi di Bootstrap: fondo incassato, bordo dei token, anello verde. */
.form-control,
.form-select {
  background-color: var(--surface-sunken);
  border-color: var(--border);
  color: var(--text);
  border-radius: var(--radius-sm);
}

.form-control:focus,
.form-select:focus {
  background-color: var(--surface-sunken);
  border-color: var(--primary);
  color: var(--text);
  box-shadow: 0 0 0 3px rgba(var(--primary-rgb), 0.2);
}

.form-control::placeholder {
  color: var(--text-dim);
}


/* ═══ 5. Tipografia ════════════════════════════════════════════════════════ */

h1, h2, h3, h4, h5, h6,
.h1, .h2, .h3 {
  font-family: var(--font-heading);
  color: var(--text);
  margin: 0 0 var(--space-4);
  text-wrap: balance;
}

h1, .h1 {
  font-size: var(--fs-h1);
  line-height: var(--lh-h1);
  font-weight: 700;
  letter-spacing: -0.02em;
}

h2, .h2 {
  font-size: var(--fs-h2);
  line-height: var(--lh-h2);
  font-weight: 700;
  letter-spacing: -0.015em;
}

h3, .h3 {
  font-size: var(--fs-h3);
  line-height: 1.3;
  font-weight: 600;
}

p {
  margin: 0 0 var(--space-4);
  color: var(--text-muted);
}

p:last-child {
  margin-bottom: 0;
}

a {
  color: var(--primary);
  text-decoration: none;
  transition: color var(--t) var(--ease);
}

a:hover {
  color: var(--primary-hover);
}

/* Eyebrow: la riga breve maiuscola sopra il titolo. */
.eyebrow {
  display: inline-block;
  font-size: var(--fs-xs);
  font-weight: 600;
  line-height: 1.4;
  text-transform: uppercase;
  letter-spacing: var(--ls-eyebrow);
  color: var(--primary);
  margin-bottom: var(--space-4);
}

/* Label UI: intestazioni di campo, di colonna, di gruppo. */
.label-ui {
  display: block;
  font-size: var(--fs-label);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: var(--ls-label);
  color: var(--text-muted);
}

.lead {
  font-size: var(--fs-lead);
  line-height: var(--lh-body);
  color: var(--text-muted);
  font-weight: 400;
}

.text-meta {
  font-size: var(--fs-xs);
  color: var(--text-dim);
}

/* Titolo "da marchio": Dune Rise, maiuscolo, molto spaziato. Va usato su testi
   brevi — intestazioni di sezione, non frasi. */
.title-display {
  font-family: var(--font-display);
  font-weight: 400;
  text-transform: uppercase;
  letter-spacing: var(--ls-display);
  line-height: 1.25;
}

/* La parola accentata dentro un titolo. Il verde si usa così, non a superficie. */
.text-accent {
  color: var(--primary);
}


/* ═══ 6. Componenti ════════════════════════════════════════════════════════ */

/* ── Card — §5: surface, bordo 1px, radius 16, padding 28, nessuna ombra ── */

.iodah-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: var(--space-6);
  transition: background-color var(--t) var(--ease), border-color var(--t) var(--ease);
}

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

.iodah-card-title {
  font-size: 1.125rem;
  font-weight: 600;
  color: var(--text);
  margin: 0 0 var(--space-2);
}

/* Variante cliccabile: l'intera card è un link o un pulsante. */
.iodah-card-link {
  display: block;
  color: inherit;
  cursor: pointer;
}

.iodah-card-link:hover,
.iodah-card-link:focus-visible {
  background: var(--surface-hover);
  border-color: var(--border-strong);
  color: inherit;
}

/* ── Tile icona — §5: 48×48, radius 12, fondo primary-soft, icona 22px ──── */

.icon-tile {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 48px;
  height: 48px;
  border-radius: var(--radius);
  background: var(--primary-soft);
  color: var(--primary);
  font-size: 22px;
  line-height: 1;
}

.icon-tile-sm {
  width: 36px;
  height: 36px;
  border-radius: var(--radius-sm);
  font-size: 16px;
}

/* ── Pulsanti ───────────────────────────────────────────────────────────── */

.btn-iodah,
.btn-iodah-outline {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  font-family: var(--font-ui);
  font-size: var(--fs-body);
  font-weight: 600;
  line-height: 1.2;
  border-radius: var(--radius);
  padding: 0.875rem 1.75rem;   /* 14 / 28 */
  border: 1px solid transparent;
  cursor: pointer;
  text-align: center;
  text-decoration: none;
  transition: background-color var(--t) var(--ease), border-color var(--t) var(--ease),
    color var(--t) var(--ease), transform var(--t) var(--ease), box-shadow var(--t) var(--ease);
}

/* Primario */
.btn-iodah {
  background: var(--primary);
  color: var(--on-primary);
  box-shadow: var(--shadow-primary);
}

.btn-iodah:hover {
  background: var(--primary-hover);
  color: var(--on-primary);
  transform: translateY(-1px);
}

.btn-iodah:active {
  transform: translateY(0);
}

/* Secondario: trasparente, bordo 1px --border */
.btn-iodah-outline {
  background: transparent;
  color: var(--text);
  border-color: var(--border);
}

.btn-iodah-outline:hover {
  background: var(--surface-hover);
  border-color: var(--border-strong);
  color: var(--text);
}

.btn-iodah-sm {
  padding: 0.5rem 1rem;
  font-size: var(--fs-sm);
  border-radius: var(--radius-sm);
}

.btn-iodah:disabled,
.btn-iodah-outline:disabled,
.btn-iodah[aria-disabled='true'],
.btn-iodah-outline[aria-disabled='true'] {
  opacity: 0.45;
  cursor: not-allowed;
  transform: none;
  box-shadow: none;
}

/* `pointer-events: none` solo sui link: su un <button disabled> il browser
   blocca già il click, e sopprimerebbe anche cursore e tooltip — cioè proprio
   i due segnali che spiegano all'utente perché non succede nulla. */
a.btn-iodah[aria-disabled='true'],
a.btn-iodah-outline[aria-disabled='true'] {
  pointer-events: none;
}

/* ── Pill — §5: bordo 1px, radius 999px, icona + testo ──────────────────── */

.pill {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: 0.375rem 0.875rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
  background: transparent;
  color: var(--text-muted);
  font-size: var(--fs-label);
  line-height: 1.4;
  white-space: nowrap;
}

.pill i,
.pill svg {
  color: var(--primary);
  font-size: 1em;
}

.pill-accent {
  background: var(--primary-soft);
  border-color: rgba(var(--primary-rgb), 0.28);
  color: var(--primary);
}

.pill-accent i,
.pill-accent svg {
  color: inherit;
}

/* ── Stato / esito ──────────────────────────────────────────────────────── */

.badge-stato {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: 0.125rem 0.625rem;
  border-radius: var(--radius-pill);
  font-size: var(--fs-xs);
  font-weight: 600;
  background: var(--primary-soft);
  color: var(--primary);
}

.badge-stato::before {
  content: '';
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: currentColor;
}

.badge-stato-off {
  background: rgba(var(--danger-rgb), 0.12);
  color: var(--danger);
}


/* ── Avvisi ─────────────────────────────────────────────────────────────── */

.avviso {
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  background: var(--surface-sunken);
  color: var(--text-muted);
  font-size: var(--fs-sm);
  line-height: 1.5;
}

.avviso-successo {
  border-color: rgba(var(--primary-rgb), 0.35);
  background: var(--primary-soft);
  color: var(--primary);
}

.avviso-errore {
  border-color: rgba(var(--danger-rgb), 0.35);
  background: rgba(var(--danger-rgb), 0.1);
  color: var(--danger);
}

.avviso-avviso {
  border-color: rgba(240, 178, 60, 0.35);
  background: rgba(240, 178, 60, 0.1);
  color: var(--warning);
}

.avviso-info {
  border-color: var(--border-strong);
}

/* ── Campi di modulo ────────────────────────────────────────────────────── */

.label-ui + .form-control,
.label-ui + .form-select {
  margin-top: var(--space-2);
}

.campo-aiuto {
  margin: var(--space-2) 0 0;
  font-size: var(--fs-xs);
  line-height: 1.5;
  color: var(--text-dim);
}

.testo-ok { color: var(--primary); }
.testo-errore { color: var(--danger); }

/* ── Presa d'atto: casella di spunta con testo accanto ──────────────────── */

.presa-atto {
  padding: var(--space-4);
  background: var(--surface-sunken);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
}

.spunta {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  font-size: var(--fs-sm);
  line-height: 1.55;
  color: var(--text-muted);
  cursor: pointer;
}

/* Area di tocco adeguata anche su schermo piccolo, e nessun ridimensionamento
   quando il testo va a capo. Anche i radio, da E4: la visibilità di una
   dashboard è una scelta binaria fra due opzioni che si escludono. */
.spunta input[type='checkbox'],
.spunta input[type='radio'] {
  flex: 0 0 auto;
  width: 20px;
  height: 20px;
  margin-top: 1px;
  accent-color: var(--primary);
  cursor: pointer;
}

/* ── Testo lungo: informativa e pagine di sola lettura ──────────────────── */

/* Doppia classe: `.section-inner` è dichiarata più avanti nel foglio e a parità
   di specificità vincerebbe, riportando il testo a tutta larghezza. */
.testo-lungo,
.section-inner.testo-lungo {
  max-width: 74ch;
}

.testo-lungo h2 {
  margin-top: var(--space-7);
}

.testo-lungo ul {
  margin: 0 0 var(--space-4);
  padding-left: 1.25rem;
  color: var(--text-muted);
}

.testo-lungo li {
  margin-bottom: var(--space-2);
  line-height: var(--lh-body);
}

/* Ciò che attende il testo definitivo, visibilmente distinto da ciò che è
   già scritto: nessuno deve poterlo confondere con contenuto valido. */
.segnaposto {
  padding: var(--space-3) var(--space-4);
  border-left: 3px solid var(--warning);
  background: rgba(240, 178, 60, 0.07);
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
  color: var(--text-dim);
  font-style: italic;
}

/* ── Indicatore di robustezza della password ────────────────────────────── */

.meter {
  margin-top: var(--space-3);
}

.meter-barra {
  height: 6px;
  border-radius: var(--radius-pill);
  background: var(--surface-sunken);
  border: 1px solid var(--border);
  overflow: hidden;
}

.meter-barra > span {
  display: block;
  height: 100%;
  width: 0;
  border-radius: var(--radius-pill);
  transition: width var(--t) var(--ease), background-color var(--t) var(--ease);
}

.meter-1 { background: var(--danger); }
.meter-2 { background: var(--warning); }
.meter-3 { background: var(--info); }
.meter-4 { background: var(--primary); }
.meter-errore { background: var(--danger); }

.meter-testo {
  margin: var(--space-2) 0 0;
  font-size: var(--fs-xs);
  color: var(--text-muted);
}


/* ═══ 7. Layout ════════════════════════════════════════════════════════════ */

/* ── Pagine di autenticazione ───────────────────────────────────────────── */

.auth-main {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-8) var(--space-4);
}

.auth-card {
  width: 100%;
  max-width: 440px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: var(--space-6);
}

.auth-card h1 {
  margin-bottom: var(--space-2);
}

.auth-card .lead {
  margin-bottom: var(--space-5);
  font-size: var(--fs-body);
}

.auth-card .avviso {
  margin-bottom: var(--space-4);
}

.auth-card-centrata {
  text-align: center;
}

.auth-card-centrata .icon-tile {
  margin-bottom: var(--space-4);
}

.auth-footer {
  margin: var(--space-5) 0 0;
  padding-top: var(--space-4);
  border-top: 1px solid var(--border);
  font-size: var(--fs-sm);
  text-align: center;
}

/* ── Utente nella barra ─────────────────────────────────────────────────── */

.utente-nome {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--fs-label);
  color: var(--text-muted);
  white-space: nowrap;
}

.utente-nome i {
  color: var(--primary);
  font-size: 1.1em;
}

/*
 * Una voce di collegamento nella barra, accanto al nome dell'utente. Solo
 * token: un colore scritto a mano qui funzionerebbe in un tema solo, e nessun
 * errore lo segnalerebbe (§5).
 */
.iodah-nav-voce {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--border);
  border-radius: 999px;
  font-size: var(--fs-label);
  color: var(--text-muted);
  text-decoration: none;
  white-space: nowrap;
  transition: color .15s ease, border-color .15s ease;
}

.iodah-nav-voce i { color: var(--primary); }

.iodah-nav-voce:hover,
.iodah-nav-voce:focus-visible {
  color: var(--text);
  border-color: var(--primary);
}

/* Sotto i 860px resta la sola icona: il nome dell'utente e il pulsante Esci
   hanno la precedenza, e un'etichetta in piu' manderebbe la barra a capo. */
@media (max-width: 860px) {
  .iodah-nav-voce span { display: none; }
}


/* ── Barra di navigazione pubblica ──────────────────────────────────────── */

.iodah-navbar {
  position: sticky;
  top: 0;
  z-index: var(--z-topbar);
  background: var(--bg-blur);
  backdrop-filter: blur(12px);
  border-bottom: 1px solid var(--border);
}

/* I collegamenti alle sezioni, presenti solo dove la pagina li fornisce.
   Sotto gli 860px spariscono: starebbero stretti accanto al marchio e al
   pulsante, e la pagina si scorre comunque. */
.iodah-nav-ancore {
  display: flex;
  align-items: center;
  gap: var(--space-5);
  font-size: 0.9375rem;
}

.iodah-nav-ancore a {
  color: var(--text-muted);
  text-decoration: none;
}

.iodah-nav-ancore a:hover { color: var(--text); }

@media (max-width: 860px) {
  .iodah-nav-ancore { display: none; }
}

.iodah-navbar-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  max-width: var(--content-max);
  margin: 0 auto;
  padding: var(--space-3) var(--space-5);
}

.iodah-brand {
  display: inline-flex;
  align-items: center;
  gap: var(--space-3);
  color: var(--text);
  text-decoration: none;
}

.iodah-brand:hover {
  color: var(--text);
}

/* Icona IODAH nella barra. `flex: 0 0 auto` perché in un contenitore flex
   un'immagine si lascia comprimere quando lo spazio manca, e un marchio
   schiacciato è peggio di un marchio assente. */
.iodah-brand-logo {
  flex: 0 0 auto;
  display: block;
  width: 34px;
  height: 34px;
}

/* Logo con la scritta, nel piede. */
.iodah-footer-logo {
  display: inline-block;
  line-height: 0;
  opacity: 0.9;
  transition: opacity var(--t) var(--ease);
}

.iodah-footer-logo:hover {
  opacity: 1;
}

.iodah-footer-logo img {
  display: block;
  height: 26px;
  width: auto;
}

.iodah-brand-name {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: 0.9375rem;
  letter-spacing: var(--ls-display);
  text-transform: uppercase;
  line-height: 1.3;
}

.iodah-brand-sub {
  display: block;
  font-size: 0.625rem;
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  /* `--text-muted` e non `--text-dim`: a 10px quest'ultimo stava a 3,5:1, sotto
     la soglia AA, ed è la riga che accompagna il marchio su ogni pagina —
     landing pubblica compresa. */
  color: var(--text-muted);
  line-height: 1.2;
}

/* ── Sezioni ────────────────────────────────────────────────────────────── */

.section {
  padding: var(--space-9) var(--space-5);
}

.section-alt {
  background: var(--bg-alt);
}

.section-inner {
  max-width: var(--content-max);
  margin: 0 auto;
}

/* ── Hero ───────────────────────────────────────────────────────────────── */

.hero {
  position: relative;
  padding: clamp(3.5rem, 2rem + 9vw, 8rem) var(--space-5) clamp(3rem, 2rem + 6vw, 6rem);
  overflow: hidden;
}

/* Alone verde molto tenue dietro il titolo: unico uso "a superficie" del
   primario, con opacità bassissima. */
.hero::before {
  content: '';
  position: absolute;
  top: -30%;
  left: 50%;
  width: min(900px, 120%);
  aspect-ratio: 1;
  transform: translateX(-50%);
  background: radial-gradient(circle, rgba(var(--primary-rgb), 0.09) 0%, transparent 65%);
  pointer-events: none;
}

.hero-inner {
  position: relative;
  max-width: 820px;
  margin: 0 auto;
  text-align: center;
}

.hero p.lead {
  max-width: 62ch;
  margin-inline: auto;
}

.hero-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  justify-content: center;
  margin-top: var(--space-6);
}

/* ── Footer ─────────────────────────────────────────────────────────────── */

.iodah-footer {
  border-top: 1px solid var(--border);
  background: var(--bg-alt);
  padding: var(--space-6) var(--space-5);
}

.iodah-footer-inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  max-width: var(--content-max);
  margin: 0 auto;
  font-size: var(--fs-label);
  /* `--text-muted` e non `--text-dim`: su `--bg-alt` quest'ultimo si ferma a
     3,35:1, sotto la soglia AA. Il footer è parte della landing pubblica. */
  color: var(--text-muted);
}

/* `.text-meta` porta con sé `--text-dim` e vincerebbe sull'ereditarietà: qui
   dentro va riportato sopra la soglia, come tutto il resto del footer. */
.iodah-footer-inner .text-meta {
  color: var(--text-muted);
}

/* Dati societari — art. 2250 c.c. Sottotono rispetto al resto, ma leggibile:
   `--text-muted` e non `--text-dim`, che su questo fondo si ferma a 3,35:1 e
   non passa il contrasto AA. Un obbligo di legge scritto in un grigio che non
   si legge è un obbligo assolto solo sulla carta. Vale anche per la riga del
   copyright qui sopra, che è sullo stesso fondo. */
.iodah-footer-legale {
  max-width: var(--content-max);
  margin: var(--space-4) auto 0;
  padding-top: var(--space-4);
  border-top: 1px solid var(--border);
  font-size: var(--fs-xs);
  line-height: 1.6;
  color: var(--text-muted);
}

.iodah-footer-legale p {
  margin: 0;
  color: inherit;
}


/* ── Landing pubblica — E6 ──────────────────────────────────────────────────
   Solo **layout**: nessuna nuova variante di card o di pulsante, perché quelle
   che servono ci sono già (.iodah-card, .icon-tile, .btn-iodah). Qui si decide
   dove vanno le cose, non che aspetto hanno. */

.intestazione-landing {
  max-width: 62ch;
  margin-inline: auto;
  text-align: center;
}

.intestazione-landing .lead {
  margin-bottom: 0;
}

/* Le sei tipologie sono raggruppate per famiglia, come nel menu del portale:
   chi guarda la landing e poi entra ritrova la stessa struttura. */
.famiglia-dashboard + .famiglia-dashboard {
  margin-top: var(--space-7);
}

.titolo-famiglia {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin-bottom: var(--space-4);
  font-size: var(--fs-h3);
  color: var(--text-muted);
}

.titolo-famiglia i {
  color: var(--primary);
}

/* L'unica riga sulla provenienza dei dati. Riquadro discreto e non un avviso:
   risponde a una domanda, non segnala un problema. */
.nota-metodo {
  display: flex;
  gap: var(--space-3);
  align-items: flex-start;
  max-width: 78ch;
  margin-inline: auto;
  padding: var(--space-4);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--surface);
  font-size: var(--fs-sm);
}

.nota-metodo i {
  color: var(--primary);
  font-size: 1.1rem;
  line-height: 1.4;
}

.chiusura-landing {
  max-width: 68ch;
  margin-inline: auto;
  text-align: center;
}

/* `.campo-aiuto` nasce per l'aiuto sotto un campo di modulo, dove `--text-dim`
   va bene perché accompagna un'etichetta. Qui è testo che qualcuno legge da
   solo, e a quel grigio starebbe a 3,5:1: sotto la soglia AA. */
.chiusura-landing .campo-aiuto {
  margin-top: var(--space-5);
  color: var(--text-muted);
}


/* ── Pagina di errore ───────────────────────────────────────────────────── */

.error-page {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: calc(100vh - 220px);
  padding: var(--space-8) var(--space-5);
  text-align: center;
}

.error-code {
  font-family: var(--font-heading);
  font-size: clamp(3.5rem, 2rem + 8vw, 6rem);
  font-weight: 700;
  line-height: 1;
  color: var(--primary);
  margin-bottom: var(--space-4);
}

.error-detail {
  margin-top: var(--space-6);
  padding: var(--space-4);
  background: var(--surface-sunken);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--text-muted);
  text-align: left;
  white-space: pre-wrap;
  overflow-x: auto;
}


/* ── Back-office ────────────────────────────────────────────────────────────
   Tutto ciò che segue vive solo sotto /admin. Riusa i token e i componenti
   già definiti: nessun colore nuovo, nessun raggio nuovo.
   ───────────────────────────────────────────────────────────────────────── */

.admin-nav {
  background: var(--bg-alt);
  border-bottom: 1px solid var(--border);
}

.admin-nav-inner {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-2);
  max-width: var(--content-max);
  margin: 0 auto;
  padding: var(--space-2) var(--space-5);
}

.admin-nav-titolo {
  color: var(--text-dim);
  margin-right: var(--space-3);
}

.admin-nav-voce {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-sm);
  color: var(--text-muted);
  font-size: var(--fs-sm);
  font-weight: 500;
  text-decoration: none;
  transition: background-color var(--t) var(--ease), color var(--t) var(--ease);
}

.admin-nav-voce:hover {
  background: var(--surface-hover);
  color: var(--text);
}

.admin-nav-voce.attiva {
  background: var(--primary-soft);
  color: var(--primary);
}

/* Le sezioni non ancora costruite si dichiarano, invece di far cercare
   all'amministratore qualcosa che non c'è ancora. */
.admin-nav-futuro {
  margin-left: auto;
  font-size: var(--fs-xs);
  color: var(--text-dim);
}

.section-admin {
  padding-top: var(--space-6);
  padding-bottom: var(--space-8);
}

.section-inner-modulo {
  max-width: 900px;
}

.intestazione-sezione {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-4);
}

.intestazione-sezione h1 {
  margin-bottom: var(--space-2);
}

.ritorno {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--fs-sm);
  color: var(--text-muted);
  margin-bottom: var(--space-3);
}

.ritorno:hover {
  color: var(--primary);
}

/* ── Briciole di pane ───────────────────────────────────────────────────────
   Dicono dove si è, cosa che il «Torna a…» non fa: quello dice da dove si può
   uscire. Con quattro sezioni e due livelli sotto ogni cliente serviva.

   Il separatore è un `::before` e non un carattere nel markup: scritto fra le
   voci, uno screen reader lo leggerebbe a ogni passaggio. */
.briciole {
  margin-bottom: var(--space-3);
  font-size: var(--fs-sm);
  line-height: 1.5;
}

/* `list-style: none` **e** `list-style-type: none` sul `li`: Bootstrap non mette
   marcatori, ma la lista numerata è il default del browser, e su una `ol` un
   foglio di stile non ancora arrivato la fa comparire. È già successo. */
.briciole ol {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
  margin: 0;
  padding: 0;
  list-style: none;
}

.briciole li {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  min-width: 0;
  list-style-type: none;
}

/* La freccia dice il verso — dalla sezione alla pagina — che una barra non dice.
   Sta nel CSS e non nel markup: scritta fra le voci, uno screen reader la
   leggerebbe a ogni passaggio. */
.briciole li + li::before {
  content: '\2192';
  color: var(--text-dim);
  opacity: 0.7;
}

.briciole a {
  color: var(--text-muted);
  text-decoration: none;
}

.briciole a:hover,
.briciole a:focus-visible {
  color: var(--primary);
  text-decoration: underline;
}

/* La pagina corrente: si legge come parte del percorso, non come un titolo.
   `max-width` più ellissi perché una ragione sociale lunga non deve mandare la
   riga a capo tre volte su un telefono. */
.briciole [aria-current='page'] {
  color: var(--text);
  font-weight: 500;
  max-width: 32ch;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ── Filtri ─────────────────────────────────────────────────────────────── */

.barra-filtri {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  align-items: flex-end;
  padding: var(--space-4);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
}

.campo-filtro {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  min-width: 150px;
}

.campo-filtro-larga {
  flex: 1 1 240px;
}

.campo-filtro-azioni {
  flex-direction: row;
  align-items: center;
  gap: var(--space-2);
  min-width: 0;
}

/* ── Tabelle ────────────────────────────────────────────────────────────── */

/* Il contenitore scorre da sé: una tabella larga non deve far scorrere
   l'intera pagina in orizzontale. */
.tabella-contenitore {
  overflow-x: auto;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--surface);
}

.tabella-dati {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--fs-sm);
}

.tabella-dati th {
  text-align: left;
  padding: var(--space-3) var(--space-4);
  font-size: var(--fs-xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: var(--ls-label);
  color: var(--text-dim);
  border-bottom: 1px solid var(--border);
  white-space: nowrap;
}

.tabella-dati td {
  padding: var(--space-3) var(--space-4);
  border-bottom: 1px solid var(--border);
  color: var(--text-muted);
  vertical-align: middle;
}

.tabella-dati tbody tr:last-child td {
  border-bottom: 0;
}

.tabella-dati tbody tr:hover {
  background: var(--surface-hover);
}

.riga-principale {
  display: block;
  color: var(--text);
  font-weight: 500;
}

/**
 * Un nome che apre una scheda deve sembrare un collegamento.
 *
 * La sottolineatura c'è sempre ma è trasparente, e diventa visibile al
 * passaggio del mouse: così la riga non è rumorosa a riposo, ma il testo non
 * si sposta di un pixel quando la sottolineatura compare — cosa che accadrebbe
 * aggiungendo `text-decoration` solo su :hover.
 */
.riga-link {
  color: var(--primary);
  text-decoration: underline;
  text-decoration-color: transparent;
  text-underline-offset: 3px;
  transition: text-decoration-color var(--t) var(--ease), color var(--t) var(--ease);
}

.riga-link:hover,
.riga-link:focus-visible {
  color: var(--primary-hover);
  text-decoration-color: currentColor;
}

.riga-principale:hover {
  color: var(--primary);
}

/* Testo per i soli lettori di schermo: intestazioni di colonna senza etichetta
   visibile, che altrimenti resterebbero mute. */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

.riga-secondaria {
  display: block;
  font-size: var(--fs-xs);
  color: var(--text-dim);
  margin-top: 2px;
}

/* Il rimedio, sulla riga di un'assegnazione che non si vede — EF.
   Si distingue dalla diagnosi che ha appena sopra: quella dice cos'è successo,
   questa dice cosa si può fare, e vanno lette come due cose diverse. */
.riga-rimedio {
  margin-top: var(--space-2);
  color: var(--text-muted);
}

.riga-rimedio .bi {
  color: var(--primary);
  margin-right: 2px;
}

.colonna-azioni {
  text-align: right;
  white-space: nowrap;
}

.codice {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--text-dim);
}

.form-control-compatta {
  padding: 0.375rem 0.625rem;
  font-size: var(--fs-sm);
  min-width: 140px;
}

.cluster-strette {
  gap: var(--space-2);
}

/* Uno stato che si commuta con un clic: sembra un'etichetta, si comporta da
   pulsante. Senza `border: 0` e `background: none` il browser gli disegna
   attorno la sua cornice. */
.pulsante-stato {
  border: 0;
  background: none;
  padding: 0;
  cursor: pointer;
}

.btn-pericolo {
  color: var(--danger);
  border-color: rgba(var(--danger-rgb), 0.35);
}

.btn-pericolo:hover {
  background: rgba(var(--danger-rgb), 0.12);
  border-color: var(--danger);
  color: var(--danger);
}

/* ── Toni degli stati ───────────────────────────────────────────────────── */

.badge-stato-ok { background: var(--primary-soft); color: var(--primary); }

.badge-stato-avviso {
  background: rgba(240, 178, 60, 0.12);
  color: var(--warning);
}

.badge-stato-spento,
.badge-stato-off {
  background: rgba(147, 164, 179, 0.12);
  color: var(--text-muted);
}

.pill-spenta {
  color: var(--text-dim);
  border-style: dashed;
}

/* ── Stato vuoto ────────────────────────────────────────────────────────── */

.stato-vuoto {
  text-align: center;
  padding: var(--space-8) var(--space-6);
}

.stato-vuoto .icon-tile {
  margin: 0 auto var(--space-4);
}

.stato-vuoto .lead {
  max-width: 56ch;
  margin-inline: auto;
}

/* ── Paginazione ────────────────────────────────────────────────────────── */

.paginazione {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-4);
}

.paginazione-stato {
  font-size: var(--fs-sm);
  color: var(--text-muted);
}

/* ── Moduli ─────────────────────────────────────────────────────────────── */

.griglia-campi {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: var(--space-4);
}

.campo {
  display: flex;
  flex-direction: column;
}

/* `1 / -1` occupa tutte le colonne qualunque sia il loro numero, che con
   auto-fit dipende dalla larghezza disponibile. */
.campo-larga {
  grid-column: 1 / -1;
}

.campo-cresce {
  flex: 1 1 220px;
}

.obbligatorio {
  color: var(--danger);
}

.griglia-spunte {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  gap: var(--space-2);
}

.spunta-compatta {
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  font-size: var(--fs-sm);
  transition: border-color var(--t) var(--ease), background-color var(--t) var(--ease);
}

.spunta-compatta:hover {
  border-color: var(--border-strong);
  background: var(--surface-hover);
}

.spunta-inattiva {
  border-style: dashed;
}

.avviso ul {
  margin: var(--space-2) 0 0;
  padding-left: 1.1rem;
}

/* ── Scheda cliente ─────────────────────────────────────────────────────── */

.griglia-schede {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
  gap: var(--space-4);
  align-items: start;
}

/* ── Card uniformi (22 settembre 2026) ─────────────────────────────────────
   Nelle schede del back-office le card di una riga erano alte quanto il loro
   testo e i pulsanti finivano dove finiva il testo. Con questa variante le
   card di una riga sono alte uguali, e la barra delle azioni
   (`.scheda-azioni`) sta in fondo a ognuna: i pulsanti di card affiancate
   stanno sulla stessa linea. `.riempi` è per un modulo che contiene la barra:
   deve allungarsi lui perché la barra arrivi in fondo. */
.griglia-schede-uniforme {
  align-items: stretch;
}
.griglia-schede-uniforme > .iodah-card {
  display: flex;
  flex-direction: column;
}
.griglia-schede-uniforme > .iodah-card > .riempi {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
}
.griglia-schede-uniforme .scheda-azioni {
  margin-top: auto;
  padding-top: var(--space-4);
}
/* Due colonne larghe invece di tre: per le card che hanno un elenco dentro. */
.griglia-schede-due {
  grid-template-columns: repeat(auto-fit, minmax(360px, 1fr));
}
.scheda-larga {
  grid-column: 1 / -1;
}

/* I pulsanti di una card: stessa misura, celle uguali che riempiono la riga;
   il principale (`.azione-principale`) prende una riga intera. */
.scheda-azioni {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}
.scheda-azioni > * {
  flex: 1 1 180px;
  min-width: 0;
}
.scheda-azioni > .azione-principale {
  flex-basis: 100%;
}

.logo-cliente {
  width: 48px;
  height: 48px;
  object-fit: contain;
  border-radius: var(--radius);
  background: var(--surface-sunken);
  padding: 4px;
}

.elenco-dati {
  display: grid;
  grid-template-columns: minmax(120px, auto) 1fr;
  gap: var(--space-2) var(--space-4);
  margin: 0;
  font-size: var(--fs-sm);
}

.elenco-dati dt {
  color: var(--text-dim);
  font-size: var(--fs-xs);
  text-transform: uppercase;
  letter-spacing: var(--ls-label);
  padding-top: 2px;
}

.elenco-dati dd {
  margin: 0;
  color: var(--text);
  min-width: 0;
  overflow-wrap: anywhere;
}

.sezione-futura {
  border-style: dashed;
}

.testo-preformattato {
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  color: var(--text-muted);
  margin: 0;
}

/* ── Storico modifiche ──────────────────────────────────────────────────── */

/* ── La card dello storico si apre e si chiude (22 settembre 2026) ─────────
   Un <details> con il titolo nel <summary>. Il marcatore del browser è tolto
   e al suo posto c'è la freccia a destra, che ruota da aperta. */
.sezione-storico > summary {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
  cursor: pointer;
  list-style: none;
}
.sezione-storico > summary::-webkit-details-marker {
  display: none;
}
.sezione-storico > summary > h2,
.sezione-storico > summary > .text-meta {
  margin: 0;
}
.sezione-storico > summary:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 4px;
  border-radius: var(--radius-sm);
}
.sezione-storico-freccia {
  margin-left: auto;
  color: var(--text-muted);
  transition: transform var(--t) var(--ease);
}
.sezione-storico[open] > summary .sezione-storico-freccia {
  transform: rotate(180deg);
}
.sezione-storico-corpo {
  padding-top: var(--space-4);
}

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

.storico-voce {
  padding: var(--space-3) 0;
  border-bottom: 1px solid var(--border);
}

.storico-voce:last-child {
  border-bottom: 0;
  padding-bottom: 0;
}

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

.storico-azione {
  font-size: var(--fs-xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: var(--ls-label);
  padding: 0.125rem 0.5rem;
  border-radius: var(--radius-pill);
  background: rgba(147, 164, 179, 0.12);
  color: var(--text-muted);
}

.storico-azione-creazione { background: var(--primary-soft); color: var(--primary); }
.storico-azione-modifica { background: rgba(94, 170, 216, 0.14); color: var(--info); }
.storico-azione-archiviazione { background: rgba(var(--danger-rgb), 0.12); color: var(--danger); }
.storico-azione-riattivazione { background: var(--primary-soft); color: var(--primary); }
.storico-azione-seed { background: rgba(240, 178, 60, 0.12); color: var(--warning); }

/* A2 — i gruppi. `sospensione` prende il tono dell'avviso e non quello del
   pericolo: è una decisione reversibile, e colorarla come un'archiviazione
   direbbe a chi legge lo storico una cosa più grave di quella accaduta.
   Le azioni senza una regola propria ricadono sul badge neutro. */
.storico-azione-sospensione { background: rgba(240, 178, 60, 0.12); color: var(--warning); }
.storico-azione-membri { background: rgba(94, 170, 216, 0.14); color: var(--info); }

/* Nome dell'entità nello storico di un cliente, dove eventi sull'anagrafica ed
   eventi sui suoi utenti convivono e va detto a chi si riferiscono. */
.storico-entita {
  font-size: var(--fs-sm);
  color: var(--text);
  font-weight: 500;
}

/* Elenco compatto: utenti nella scheda cliente, senza il peso di una tabella. */
.elenco-compatto {
  list-style: none;
  margin: 0;
  padding: 0;
  font-size: var(--fs-sm);
}

.elenco-compatto li {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--space-2);
  padding: var(--space-2) 0;
  border-bottom: 1px solid var(--border);
}

.elenco-compatto li:last-child {
  border-bottom: 0;
}

.elenco-compatto .riga-secondaria {
  flex: 1 1 100%;
}

/* Descrizioni dei ruoli sotto il modulo di invito. */
.elenco-ruoli p {
  margin: 0 0 var(--space-1);
}

/* In attesa: un invito emesso e non ancora usato non è né buono né cattivo. */
.badge-stato-attesa {
  background: rgba(94, 170, 216, 0.14);
  color: var(--info);
}

.storico-modifiche {
  list-style: none;
  margin: var(--space-2) 0 0;
  padding: 0;
  font-size: var(--fs-sm);
}

.storico-modifiche li {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--space-2);
  padding: 2px 0;
  color: var(--text-muted);
}

.valore-da {
  color: var(--text-dim);
  text-decoration: line-through;
  overflow-wrap: anywhere;
}

.valore-a {
  color: var(--text);
  overflow-wrap: anywhere;
}


/* ── Assegnazioni di un cliente — E4 ────────────────────────────────────────

   Ordinamento con due pulsanti invece del trascinamento: il drag and drop
   richiederebbe una libreria, e il §2 di CLAUDE.md non ne ammette. In cambio
   funziona da tastiera senza fare niente di speciale. */

.colonna-ordine {
  width: 1%;
  white-space: nowrap;
  vertical-align: middle;
}

.pulsanti-ordine {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.btn-ordine {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 24px;
  padding: 0;
  color: var(--text-muted);
  background: none;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  cursor: pointer;
  transition: border-color var(--t) var(--ease), color var(--t) var(--ease);
}

.btn-ordine:hover:not(:disabled) {
  color: var(--text);
  border-color: var(--border-strong);
}

/* I due passi, a blocchi: la riga di perimetro apre il blocco, le consegne
   stanno rientrate sotto di lei su un fondo diverso. Un blocco senza perimetro
   ha il bordo del pericolo: le sue consegne non valgono. */
.riga-perimetro td { border-top: 2px solid var(--border-strong); }
.tabella-dati tbody tr.riga-perimetro:first-child td { border-top: 0; }
.riga-orfana td { border-top: 2px solid var(--danger); }
.riga-consegna td { background: var(--bg-alt); }
.riga-consegna td:nth-child(2) { padding-left: var(--space-6); }
.consegna-freccia { color: var(--text-dim); margin-right: var(--space-2); }

/* Ai bordi dell'elenco il pulsante è disabilitato invece che nascosto: una
   colonna che cambia larghezza sulla prima e sull'ultima riga si legge peggio
   di un pulsante spento. */
.btn-ordine:disabled {
  opacity: 0.3;
  cursor: default;
}

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

.elenco-assegnabili li {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-3) 0;
  border-bottom: 1px solid var(--border);
}

/* La casella davanti a ogni voce assegnabile (scheda del Team, 21 settembre
   2026): prende lo spazio che il blocco del titolo prendeva prima. */
.elenco-assegnabili .spunta-riga {
  flex: 1 1 auto;
  min-width: 0;
  margin: 0;
}
.elenco-assegnabili .spunta-riga > span {
  min-width: 0;
}
.barra-selezione {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
}
/* Nell'elenco dei Team: i titoli di ciò che ogni team riceve, uno per riga. */
.elenco-titoli {
  list-style: none;
  margin: 0;
  padding: 0;
  font-size: var(--fs-sm);
}
.elenco-titoli li + li {
  margin-top: var(--space-1);
}
.elenco-assegnabili li:last-child {
  border-bottom: 0;
  padding-bottom: 0;
}

.gruppo-spunte {
  margin: 0;
  padding: 0;
  border: 0;
}

.gruppo-spunte legend {
  float: none;
  width: auto;
  margin-bottom: var(--space-2);
  padding: 0;
  font-size: inherit;
}


/* ═══ Portale cliente — E5 ═════════════════════════════════════════════════

   La shell del §6: topbar 48px, sidebar 220px collassabile a 56px, e tutto il
   resto al report. I token li ha dichiarati E0 (`--topbar-h`, `--sidebar-w`,
   `--sidebar-w-collapsed`) proprio in attesa di questo momento.

   Griglia e non flex annidati: la topbar attraversa entrambe le colonne, la
   sidebar e il contenuto stanno sulla riga sotto. Con `100dvh` e `min-height:0`
   sulle righe interne, l'area del report riceve un'altezza **definita** — che è
   ciò di cui il componente del report ha bisogno per riempirla davvero. */

/* ┌── NESSUNA TRANSIZIONE SULLA COLONNA ─────────────────────────────────────┐
   │ `transition: grid-template-columns` sembra la rifinitura ovvia e non       │
   │ funziona: il browser avvia una transizione che **non avanza**, e la        │
   │ larghezza resta bloccata sul valore di partenza — la sidebar si svuotava   │
   │ del testo ma non si restringeva. Misurato.                                 │
   │                                                                          │
   │ Toglierla è anche la scelta giusta nel merito: animare la colonna          │
   │ significa ridimensionare l'iframe di Power BI a ogni fotogramma, e         │
   │ costringere il suo visualizzatore a ricalcolare il layout del report       │
   │ sessanta volte al secondo per un effetto di due decimi di secondo.         │
   └──────────────────────────────────────────────────────────────────────────┘ */
.portale-shell {
  display: grid;
  grid-template-columns: var(--sidebar-w) 1fr;
  grid-template-rows: var(--topbar-h) 1fr;
  height: 100dvh;
  overflow: hidden;
}

.portale-shell.sidebar-chiusa {
  grid-template-columns: var(--sidebar-w-collapsed) 1fr;
}

/* ── Topbar ─────────────────────────────────────────────────────────────── */

.portale-topbar {
  grid-column: 1 / -1;
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding-inline: var(--space-3);
  background: var(--bg-alt);
  border-bottom: 1px solid var(--border);
  min-width: 0;
}

.portale-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  padding: 0;
  color: var(--text-muted);
  background: none;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  font-size: 1.1rem;
  cursor: pointer;
}

.portale-toggle:hover {
  color: var(--text);
  border-color: var(--border);
}

.portale-marchio {
  display: inline-flex;
  align-items: center;
  flex: 0 0 auto;
}

.portale-cliente {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  min-width: 0;
  /* Il nome del cliente cede spazio prima di tutto il resto: è l'unica cosa
     della topbar che può essere lunga a piacere. */
  flex: 1 1 auto;
  overflow: hidden;
}

.portale-logo-cliente {
  max-height: 26px;
  max-width: 120px;
  object-fit: contain;
}

.portale-nome-cliente {
  font-weight: 600;
  font-size: var(--fs-sm);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.portale-utente-bottone {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-1) var(--space-2);
  color: var(--text-muted);
  background: none;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  font-size: var(--fs-sm);
  cursor: pointer;
}

.portale-utente-bottone:hover {
  color: var(--text);
  border-color: var(--border);
}

.portale-utente-freccia { font-size: 0.7rem; }

.portale-utente-email {
  font-size: var(--fs-sm);
  color: var(--text-dim);
}

/* ── Sidebar ────────────────────────────────────────────────────────────── */

.portale-sidebar {
  grid-row: 2;
  grid-column: 1;
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
  padding: var(--space-3) var(--space-2);
  background: var(--bg-alt);
  border-right: 1px solid var(--border);
}

.portale-gruppo + .portale-gruppo { margin-top: var(--space-4); }

.portale-gruppo-titolo {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin: 0 0 var(--space-2);
  padding-inline: var(--space-2);
  font-size: 0.6875rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--text-dim);
  white-space: nowrap;
}

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

.portale-voce {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-2) var(--space-2);
  border-radius: var(--radius-sm);
  color: var(--text-muted);
  text-decoration: none;
  font-size: var(--fs-sm);
  white-space: nowrap;
}

.portale-voce:hover {
  background: var(--surface-hover);
  color: var(--text);
}

.portale-voce.attiva {
  background: var(--primary-soft);
  color: var(--primary);
}

.portale-voce i { flex: 0 0 auto; font-size: 1rem; }

.portale-voce-testo {
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Collassata: restano le icone. Il testo si nasconde con una tecnica che lo
   lascia agli screen reader — `display: none` lo toglierebbe anche a loro, che
   della larghezza della finestra non sanno niente. */
.sidebar-chiusa .portale-voce-testo,
.sidebar-chiusa .portale-sidebar-vuota {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.sidebar-chiusa .portale-voce { justify-content: center; }
.sidebar-chiusa .portale-gruppo-titolo { justify-content: center; padding-inline: 0; }

.portale-sidebar-vuota {
  padding-inline: var(--space-2);
  font-size: var(--fs-sm);
  color: var(--text-dim);
}

/* L'organizzazione da cui arrivano le voci che seguono (C2): compare solo a
   chi vede i report di più organizzazioni, e solo quando cambia. */
.portale-organizzazione {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin: var(--space-5) 0 var(--space-3);
  padding: var(--space-3) var(--space-2) 0;
  border-top: 1px solid var(--border);
  font-size: 0.6875rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--primary);
  white-space: nowrap;
}

.portale-sidebar > .portale-gruppo:first-child .portale-organizzazione {
  margin-top: 0;
  padding-top: 0;
  border-top: 0;
}

.sidebar-chiusa .portale-organizzazione { justify-content: center; padding-inline: 0; }

/* ── Contenuto ──────────────────────────────────────────────────────────── */

.portale-contenuto {
  grid-row: 2;
  grid-column: 2;
  min-width: 0;
  min-height: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding: var(--space-2);
}

/* La home scorre; il viewer no, perché il report riempie e non deborda. */
.portale-contenuto-scorrevole { overflow-y: auto; }

.portale-barra-report {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  min-width: 0;
}

.portale-titolo-report {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.portale-data-report { white-space: nowrap; }

/* ── Home a schede ──────────────────────────────────────────────────────── */

.portale-home { max-width: var(--content-max); }
.portale-home-testa { margin-bottom: var(--space-5); }
.portale-home-gruppo + .portale-home-gruppo { margin-top: var(--space-6); }

/* L'organizzazione, nella home a schede (C2): stesso significato della
   sidebar, con il peso di un titolo di sezione. */
.portale-home-organizzazione {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin: var(--space-7, 3rem) 0 var(--space-4);
  padding-bottom: var(--space-2);
  border-bottom: 1px solid var(--border);
  color: var(--primary);
}

.portale-home-testa + .portale-home-organizzazione { margin-top: 0; }

.portale-home-gruppo-titolo {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin-bottom: var(--space-3);
  color: var(--text-dim);
}

.portale-scheda {
  display: flex;
  align-items: flex-start;
  gap: var(--space-4);
}

.portale-scheda-corpo {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  min-width: 0;
}

.portale-scheda-descrizione { margin: 0; }

.portale-scheda-data {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font-size: 0.8125rem;
  color: var(--text-dim);
}

.portale-stato-vuoto {
  display: grid;
  place-items: center;
  min-height: 100%;
  padding: var(--space-5);
}

/* ── Avviso per gli schermi stretti ─────────────────────────────────────────
   Nascosto per default e mostrato solo sotto la soglia: un report Power BI ha
   un canvas a dimensione fissa e sotto i 768px si legge male. Non impedisce
   niente — è un avviso, e il report si apre lo stesso. */

.avviso-schermo-piccolo { display: none; }

@media (max-width: 767.98px) {
  .avviso-schermo-piccolo {
    display: flex;
    align-items: flex-start;
    gap: var(--space-2);
    margin: 0;
  }

  /* Su schermo stretto la sidebar aperta mangerebbe metà larghezza: nasce
     collassata, e chi vuole l'elenco la riapre. */
  .portale-shell { grid-template-columns: var(--sidebar-w-collapsed) 1fr; }
  .portale-nome-cliente { display: none; }
  .portale-utente-nome { display: none; }
}


/* ── Report Power BI: componente condiviso — E4, riusato a E5 ───────────────

   Il vestito di `views/partials/report-powerbi.ejs`. Sta qui e non dentro il
   foglio di una pagina perché il componente è uno: l'anteprima del back-office
   e il viewer del cliente devono rendere il report allo stesso modo, e due
   copie del CSS divergerebbero al primo ritocco.

   `.report-spazio` è lo spazio che il chiamante gli concede; `.report-cornice`
   se lo prende tutto. Il chiamante decide **quanto** spazio (una pagina intera
   nell'anteprima, l'area a destra della sidebar a E5); il componente decide
   **come** riempirlo.

   ┌── LA CORNICE NON HA UN RAPPORTO DI FORMA. SI PRENDE TUTTO. ─────────────┐
   │ Prima versione: la cornice veniva vincolata al rapporto delle dimensioni  │
   │ native dello snippet, per non lasciare bande vuote ai lati. Sbagliato, e  │
   │ misurato: **le dimensioni dello snippet non sono la forma della pagina    │
   │ del report**. Per «Demo Sirmione» lo snippet dichiara 1024×804 — rapporto │
   │ 1,27 — ma il contenuto della pagina è circa 16:9, e sotto resta bianco.   │
   │ Vincolando la cornice a 1,27 la si rende troppo stretta, e Power BI       │
   │ riduce il report al 74%; la stessa pagina su Power BI Online, con tutta   │
   │ la larghezza a disposizione, sta al 104%. Toltolo, alla stessa finestra   │
   │ di 1280×720 la cornice è passata da 736×578 a 1264×622.                   │
   │                                                                          │
   │ Il visualizzatore di Power BI **adatta già da sé** il report dentro il    │
   │ riquadro che gli si dà. Quindi il riquadro più grande possibile è sempre  │
   │ almeno buono quanto qualunque riquadro vincolato: si riempie lo spazio e  │
   │ si lascia fare a lui.                                                     │
   │                                                                          │
   │ Le dimensioni native restano salvate — sono ciò che Power BI dichiara, e  │
   │ servono a diagnosticare — ma non governano il layout.                     │
   └──────────────────────────────────────────────────────────────────────────┘

   Nessun angolo arrotondato e nessun margine laterale: la cornice deve sparire
   e lasciare tutto lo spazio al report. */

.report-spazio {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
}

.report-cornice {
  position: relative;
  flex: 1 1 auto;
  min-width: 0;
  background: var(--surface);
  border: 1px solid var(--border);
  overflow: hidden;
}

/* In posizione assoluta e non `height: 100%`: l'altezza percentuale di un
   iframe richiede che il genitore abbia un'altezza **definita**, e quando non si
   risolve l'iframe ricade sui suoi 150px predefiniti — è già successo. `inset: 0`
   non ha quel problema, qualunque cosa dia l'altezza al genitore. */
.report-iframe {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
}

/* Indicatore di caricamento: lo inserisce public/js/portale.js e lo toglie
   sull'evento `load`. L'app su Hostinger viene sospesa dopo circa un'ora di
   inattività, quindi il primo report della giornata può metterci qualche
   secondo — e senza questo velo quel tempo è un rettangolo scuro che sembra un
   guasto. */
.report-caricamento {
  position: absolute;
  inset: 0;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-3);
  background: var(--surface);
  color: var(--text-muted);
  font-size: var(--fs-sm);
}

.report-caricamento-rotella {
  width: 28px;
  height: 28px;
  border: 2px solid var(--border-strong);
  border-top-color: var(--primary);
  border-radius: 50%;
  animation: report-gira 0.9s linear infinite;
}

@keyframes report-gira {
  to { transform: rotate(360deg); }
}

/* `prefers-reduced-motion` ha già una regola globale che azzera le animazioni:
   la rotella diventa un cerchio fermo, e il testo continua a dire cosa succede. */


/* ── L'anteprima dentro il modulo — EF ──────────────────────────────────────
   Il chiamante concede lo spazio, il componente lo riempie: qui lo spazio è una
   striscia dentro la card del modulo.

   `height` e non `min-height`, e con un valore vero: `.report-spazio` è un
   flex-item che si prende quello che riceve, e da un contenitore senza altezza
   definita riceve zero — l'iframe ricadrebbe sui suoi 150px predefiniti. È la
   stessa trappola del §10 di Architettura.md, vista da un'altra angolazione.

   60vh è la misura che lascia il campo dell'indirizzo e i pulsanti visibili
   insieme al report su un portatile: il report va guardato, ma questa non è la
   pagina in cui lo si legge. */
.modulo-anteprima {
  display: flex;
  height: min(60vh, 520px);
  min-height: 260px;
}

/* Sotto i 900px di finestra la striscia si prende di più: su uno schermo basso
   360px di report sono una fessura in cui non si riconosce niente. */
@media (max-height: 900px) {
  .modulo-anteprima { height: 55vh; }
}


/* ── Anteprima di una dashboard — E4 ────────────────────────────────────────
   Il contorno attorno al componente condiviso: pagina a sé, senza la
   navigazione del back-office, perché si sta valutando se un report carica e
   ogni elemento in più è spazio tolto proprio a quello. */

.anteprima-shell {
  /* `height` e non `min-height`: serve un'altezza definita perché
     `.report-spazio` sappia quanto spazio ha davvero da dare al report. */
  height: 100dvh;
  display: flex;
  flex-direction: column;
  padding: var(--space-2);
  gap: var(--space-2);
}

.anteprima-barra {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  min-height: var(--topbar-h);
}

.anteprima-vuota {
  flex: 1 1 auto;
  display: grid;
  place-items: center;
}

.anteprima-nota {
  flex: 0 0 auto;
  margin: 0;
  color: var(--text-dim);
  font-size: 0.8125rem;
  line-height: 1.4;
}


/* ═══ 8. Utility ═══════════════════════════════════════════════════════════ */

/* Indirizzi e frammenti tecnici: spezzabili ovunque, perché un URL di Power BI
   supera i 200 caratteri e altrimenti allargherebbe la card. */
.testo-monospazio,
.campo-monospazio {
  font-family: var(--font-mono);
  font-size: 0.8125rem;
}

.testo-spezzabile {
  display: inline-block;
  max-width: 100%;
  overflow-wrap: anywhere;
}

/* Non è un errore ma non è nemmeno normale: una dashboard senza destinazioni,
   dimensioni native mancanti. */
.testo-attenzione { color: var(--warning); }

/* ── `hidden` deve vincere — EF ─────────────────────────────────────────────
   L'attributo `hidden` del browser vale `display: block`, quindi qualunque
   regola che imposti `display: grid` o `display: flex` sull'elemento lo
   sopraffà e l'elemento resta visibile. Serve una regola esplicita.

   Non è un dettaglio estetico: `hidden` è il **solo** modo di nascondere
   qualcosa dal JavaScript senza scrivere uno stile in linea, che la CSP
   scarterebbe in silenzio (§10 di Architettura.md). Lo usa il blocco delle
   destinazioni nel modulo di una dashboard, e lo userà chiunque altro. */
[hidden] { display: none !important; }


.stack > * + * { margin-top: var(--space-4); }
.stack-sm > * + * { margin-top: var(--space-2); }
.stack-lg > * + * { margin-top: var(--space-6); }

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

/* Allinea in alto invece che al centro: serve quando un elemento del gruppo è
   molto più alto degli altri, come una tile icona accanto a un titolo su due
   righe. È una classe e non uno `style=` perché la CSP blocca gli stili in
   linea (`style-src 'self'` senza `'unsafe-inline'`). */
.cluster-alto { align-items: flex-start; }
.cluster-a-destra { justify-content: flex-end; }

.text-muted-iodah { color: var(--text-muted); }
.text-dim { color: var(--text-dim); }
.surface { background: var(--surface); }
.bordered { border: 1px solid var(--border); }
.rounded-iodah { border-radius: var(--radius-lg); }
.full-bleed { width: 100%; }


/* ═══ 9. Responsive e preferenze di sistema ════════════════════════════════ */

@media (max-width: 575.98px) {
  .section {
    padding: var(--space-8) var(--space-4);
  }

  .hero {
    padding-inline: var(--space-4);
  }

  .iodah-navbar-inner {
    padding: var(--space-3) var(--space-4);
  }

  .iodah-card {
    padding: var(--space-5);
  }

  .btn-iodah,
  .btn-iodah-outline {
    width: 100%;
  }

  .iodah-footer-inner {
    justify-content: center;
    text-align: center;
  }

  .auth-main {
    padding: var(--space-5) var(--space-4);
  }

  .auth-card {
    padding: var(--space-5) var(--space-4);
  }

  /* Nella barra il nome dell'utente cede il posto al pulsante di uscita. */
  .utente-nome {
    max-width: 40vw;
    overflow: hidden;
    text-overflow: ellipsis;
  }

  /* Back-office su schermo piccolo. */
  .admin-nav-inner {
    padding: var(--space-2) var(--space-4);
  }

  .admin-nav-futuro {
    display: none;
  }

  .barra-filtri {
    padding: var(--space-3);
  }

  .campo-filtro {
    min-width: 100%;
  }

  .campo-filtro-azioni {
    justify-content: stretch;
  }

  .campo-filtro-azioni .btn-iodah,
  .campo-filtro-azioni .btn-iodah-outline {
    flex: 1;
  }

  .intestazione-sezione {
    flex-direction: column;
  }

  /* Le etichette dell'elenco dati vanno sopra il valore: due colonne su 360px
     lasciano al valore uno spazio in cui non sta niente. */
  .elenco-dati {
    grid-template-columns: 1fr;
    gap: var(--space-1) 0;
  }

  .elenco-dati dd {
    margin-bottom: var(--space-3);
  }
}

/* Fino a 360px, requisito del §5: niente deve traboccare. */
@media (max-width: 360px) {
  .iodah-brand-sub {
    display: none;
  }

  .iodah-card {
    padding: var(--space-4);
  }
}

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }

  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }

  .btn-iodah:hover {
    transform: none;
  }
}

/* Utenti che chiedono più contrasto: bordi pieni invece che translucidi. */
@media (prefers-contrast: more) {
  :root {
    --border: rgba(255, 255, 255, 0.24);
    --border-strong: rgba(255, 255, 255, 0.4);
    --text-muted: #B6C4D0;
    --text-dim: #8496A6;
  }

  /* Il tema chiaro ha bisogno del rinforzo opposto: bordi e testi **più
     scuri**, non più chiari. Senza questo blocco, chi chiede più contrasto e
     usa il tema chiaro si ritroverebbe bordi bianchi su fondo bianco, cioè il
     contrario di quello che ha chiesto. */
  [data-tema='chiaro'] {
    --border: rgba(0, 0, 0, 0.24);
    --border-strong: rgba(0, 0, 0, 0.45);
    --text-muted: #33414D;
    --text-dim: #43515E;
  }
}


/* ── Interruttore del tema ──────────────────────────────────────────────────
   Un pulsante di sola icona, della stessa altezza dei pulsanti piccoli che gli
   stanno accanto nella barra. Nasce `hidden` e lo mostra public/js/app.js: il
   perché sta nel partial. */

.interruttore-tema {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  padding: 0;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: transparent;
  color: var(--text-muted);
  font-size: 1rem;
  cursor: pointer;
  transition: color var(--t) var(--ease), border-color var(--t) var(--ease),
              background var(--t) var(--ease);
}

.interruttore-tema:hover {
  color: var(--primary);
  border-color: var(--border-strong);
  background: var(--surface-hover);
}

/* Nella topbar del portale lo spazio verticale è 48px in tutto: il pulsante si
   stringe, come tutto il resto lì dentro. */
.portale-topbar .interruttore-tema {
  width: 30px;
  height: 30px;
  font-size: 0.9375rem;
}


/* Passaggio fra le due versioni della home. Discreto: è uno strumento di
   lavoro dentro una pagina che parla ai visitatori. */
.scambio-home {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  color: var(--text-muted);
  text-decoration: underline;
  text-underline-offset: 3px;
}

.scambio-home:hover { color: var(--primary); }

/* ── Statistiche — E7b ──────────────────────────────────────────────────── */

/*
 * Tutto con i token, nessun colore scritto a mano: un valore fisso qui
 * funzionerebbe in un tema solo, e nessun errore lo segnalerebbe (§5).
 */

.stat-nav {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

.stat-nav-voce {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-4);
  border: 1px solid var(--border);
  border-radius: 999px;
  font-size: var(--fs-label);
  color: var(--text-muted);
  text-decoration: none;
  white-space: nowrap;
  transition: color .15s ease, border-color .15s ease, background-color .15s ease;
}

.stat-nav-voce:hover,
.stat-nav-voce:focus-visible {
  color: var(--text);
  border-color: var(--primary);
}

.stat-nav-voce.attiva {
  color: var(--primary);
  border-color: var(--primary);
  background: var(--primary-soft);
}

.stat-filtri {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: var(--space-4);
}

.stat-filtri .campo-filtro { flex: 1 1 12rem; }

.stat-filtri-azioni {
  display: flex;
  gap: var(--space-2);
}

/* ── I numeri in cima ───────────────────────────────────────────────────── */

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

.kpi {
  display: flex;
  align-items: flex-start;
  gap: var(--space-4);
}

.kpi-valore {
  margin: 0;
  font-size: 1.75rem;
  font-weight: 700;
  line-height: 1.1;
  color: var(--text);
}

.kpi-etichetta { margin: 0; color: var(--text-muted); }
.kpi-nota { margin: 0; font-size: var(--fs-xs); }

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

/* ── I grafici ──────────────────────────────────────────────────────────── */

/*
 * Il canvas ha bisogno di un'altezza dal contenitore: `maintainAspectRatio`
 * e' spento, o su schermi larghi un grafico si mangerebbe mezza pagina.
 */
.stat-tela {
  position: relative;
  height: 18rem;
}

.stat-tabella > summary {
  cursor: pointer;
  font-size: var(--fs-label);
  color: var(--text-muted);
  padding: var(--space-2) 0;
}

.stat-tabella > summary:hover { color: var(--text); }

.tabella-scorrevole {
  overflow-x: auto;
  max-width: 100%;
}

/* ── La heatmap ─────────────────────────────────────────────────────────── */

/*
 * L'intensita' NON puo' essere uno `style=`: la CSP li blocca senza dare
 * errore (§10). Sono dieci classi, e il server sceglie quale.
 */
.heatmap {
  border-collapse: separate;
  border-spacing: 2px;
  font-size: var(--fs-xs);
}

.heatmap-ora {
  color: var(--text-muted);
  font-weight: 400;
  text-align: center;
  padding: 0 0 var(--space-2);
}

.heatmap-giorno {
  color: var(--text-muted);
  font-weight: 500;
  text-align: right;
  padding-right: var(--space-3);
  white-space: nowrap;
}

.heatmap-cella {
  display: inline-block;
  width: 1.1rem;
  height: 1.1rem;
  border-radius: 3px;
  background: var(--surface-sunken);
}

/*
 * Dieci gradini dallo spento al primario. `color-mix` e' sostenuto da tutti i
 * browser correnti; dove non lo fosse, la cella resta del colore di fondo e la
 * tabella si legge lo stesso.
 */
.heat-0 { background: var(--surface-sunken); }
.heat-1 { background: color-mix(in srgb, var(--primary) 12%, var(--surface-sunken)); }
.heat-2 { background: color-mix(in srgb, var(--primary) 22%, var(--surface-sunken)); }
.heat-3 { background: color-mix(in srgb, var(--primary) 32%, var(--surface-sunken)); }
.heat-4 { background: color-mix(in srgb, var(--primary) 42%, var(--surface-sunken)); }
.heat-5 { background: color-mix(in srgb, var(--primary) 54%, var(--surface-sunken)); }
.heat-6 { background: color-mix(in srgb, var(--primary) 66%, var(--surface-sunken)); }
.heat-7 { background: color-mix(in srgb, var(--primary) 78%, var(--surface-sunken)); }
.heat-8 { background: color-mix(in srgb, var(--primary) 89%, var(--surface-sunken)); }
.heat-9 { background: var(--primary); }

.heatmap-legenda {
  display: flex;
  align-items: center;
  gap: var(--space-1, 0.25rem);
}

.heatmap-legenda .text-meta { margin: 0 var(--space-2); }

@media (max-width: 720px) {
  .stat-tela { height: 14rem; }
  .heatmap-cella { width: 0.85rem; height: 0.85rem; }
}

/* ── La ricerca dentro un elenco — A6 ───────────────────────────────────── */

.cerca-elenco {
  margin-bottom: var(--space-4);
}

.cerca-elenco .campo-aiuto {
  margin-top: var(--space-2);
}

.cerca-elenco-crea {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-3);
  margin-top: var(--space-3);
  padding: var(--space-3);
  border: 1px dashed var(--border);
  border-radius: 12px;
}

/* ── Il logo caricato del cliente ───────────────────────────────────────── */

/*
 * Piu' grande di quello in intestazione: qui serve a guardarlo, non a
 * riconoscerlo di sfuggita. `object-fit: contain` perche' un logo puo' essere
 * largo o alto, e ritagliarlo sarebbe peggio che lasciarlo piccolo.
 */
.logo-cliente-grande {
  width: 96px;
  height: 96px;
}

.logo-anteprima {
  display: flex;
  align-items: flex-start;
  flex-wrap: wrap;
  gap: var(--space-4);
}

/* ── Il numero di versione ──────────────────────────────────────────────── */

/*
 * Piccolo e discreto: serve a chi segnala un difetto, non a chi legge la
 * pagina. Colore dai token, come tutto il resto.
 */
.iodah-versione {
  margin: var(--space-2) 0 0;
  font-size: var(--fs-xs);
  color: var(--text-muted);
  opacity: 0.7;
  letter-spacing: 0.04em;
}

/* Nel menu utente del portale sta in fondo, sotto l'indirizzo. */
.dropdown-item-text.iodah-versione {
  margin: 0;
  padding-top: 0;
}

/* ── La barra laterale del front-end dell'amministratore ────────────────── */

/*
 * Il titolo di un gruppo diventa cliccabile quando il gruppo porta da qualche
 * parte: nel portale del cliente sono etichette, qui sono le Collections.
 * Solo token, come tutto il resto (§5).
 */
.portale-gruppo-link {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  width: 100%;
  padding: var(--space-2) var(--space-3);
  border-radius: 10px;
  color: var(--text-muted);
  text-decoration: none;
  transition: color .15s ease, background-color .15s ease;
}

.portale-gruppo-link:hover,
.portale-gruppo-link:focus-visible {
  color: var(--text);
  background: var(--surface-hover);
}

.portale-gruppo-link.aperto {
  color: var(--primary);
  background: var(--primary-soft);
}

/* Quanti report ci sono dentro, in coda e discreto. */
.portale-gruppo-quante {
  margin-left: auto;
  font-size: var(--fs-xs);
  opacity: 0.7;
}

/* Da collassata restano le sole icone: il conteggio non ci starebbe. */
.sidebar-chiusa .portale-gruppo-quante { display: none; }
