/* =====================================================================
   ZENTRO DESIGN SYSTEM — Apple-inspired UI primitives
   ---------------------------------------------------------------------
   Drop-in stylesheet. Framework-agnostic (works with plain HTML, React,
   Vue, Next.js, etc.). Uses only CSS custom properties + utility classes.
   No Tailwind required — but 100% compatible with it.
   ===================================================================== */

/* ---------- 1. DESIGN TOKENS (customize here) ---------- */
:root {
  /* Palette */
  --zx-ink:       #0B0B0F;
  --zx-muted:     #6E6E73;
  --zx-stroke:    #E8E8ED;
  --zx-paper:     #FBFBFD;
  --zx-cloud:     #F5F5F7;
  --zx-surface:   #FFFFFF;
  --zx-brand:     #2563EB;
  --zx-brand-ink: #ffffff;

  /* Chat dell'assistente: fondo della bolla di chi scrive E dell'avatar (stesso colore, sono la
     stessa "voce"), piu' il colore del testo che ci sta sopra.
     ⚠️ Servono token propri: usando ink/paper crudi, in veste scura la bolla diventava un
     rettangolo bianco (ink si schiarisce, brand-ink resta bianco → testo bianco su chiaro). */
  --zx-chat-accent:    #0B0B0F;
  --zx-chat-on-accent: #FFFFFF;

  /* Radius scale */
  --zx-radius-sm: 10px;
  --zx-radius-md: 14px;
  --zx-radius-lg: 18px;
  --zx-radius-xl: 22px;   /* signature card radius */
  --zx-radius-2xl: 28px;

  /* Borders */
  --zx-border-hairline: 1px solid rgba(0, 0, 0, 0.05);
  --zx-border-hover:    1px solid rgba(0, 0, 0, 0.08);
  /* Solo il COLORE del bordo: `--zx-border-hover` e' uno shorthand e dato a `border-color`
     produce una dichiarazione invalida, che il browser scarta in silenzio. */
  --zx-border-hover-color: rgba(0, 0, 0, 0.08);

  /* Shadows — layered for depth (Apple product-tile feel) */
  --zx-shadow-rest:
    0 1px 2px rgba(16, 24, 40, 0.04),
    0 8px 24px rgba(16, 24, 40, 0.06);
  --zx-shadow-hover:
    0 2px 4px rgba(16, 24, 40, 0.05),
    0 20px 40px rgba(16, 24, 40, 0.10);
  --zx-shadow-brand:
    0 6px 20px rgba(37, 99, 235, 0.25);

  /* Motion */
  --zx-ease:       cubic-bezier(0.22, 1, 0.36, 1);
  --zx-dur-fast:   .3s;
  --zx-dur-base:   .6s;
  --zx-dur-slow:   .9s;

  /* Typography — Inter Tight/Inter via next/font (CSS variable definite in app/layout.tsx). */
  --zx-font-sans: var(--font-inter-tight), var(--font-inter), ui-sans-serif, system-ui, -apple-system, "SF Pro Text", sans-serif;
}

/* ---------- 1b. THEME COLOR VARIABLES (Tailwind palette mapping) ----------
   Palette neutre Tailwind (gray, slate, zinc, neutral, stone) mappate a CSS variables
   che cambiano valore quando [data-theme="dark"] e' attivo. Combinato con la
   configurazione tailwind.config.js (themeAwareScale), tutte le classi tipo
   `text-gray-700`, `bg-slate-100`, `border-zinc-200` ecc. cambiano automaticamente
   colore in dark mode senza modifiche al JSX.

   Le variabili memorizzano i valori RGB come triplette space-separated (formato
   richiesto dalla sintassi `rgb(var(--c-X) / <alpha-value>)` di Tailwind).
   In dark mode la scala e' invertita: 50 ↔ 900, 100 ↔ 800, ecc., cosi' tutti
   gli sfondi chiari diventano scuri e tutti i testi scuri diventano chiari. */

:root {
  /* Gray (Tailwind default) */
  --c-gray-50:  249 250 251;
  --c-gray-100: 243 244 246;
  --c-gray-200: 229 231 235;
  --c-gray-300: 209 213 219;
  --c-gray-400: 156 163 175;
  --c-gray-500: 107 114 128;
  --c-gray-600:  75  85  99;
  --c-gray-700:  55  65  81;
  --c-gray-800:  31  41  55;
  --c-gray-900:  17  24  39;
  --c-gray-950:   3   7  18;

  /* Slate (Tailwind default) */
  --c-slate-50:  248 250 252;
  --c-slate-100: 241 245 249;
  --c-slate-200: 226 232 240;
  --c-slate-300: 203 213 225;
  --c-slate-400: 148 163 184;
  --c-slate-500: 100 116 139;
  --c-slate-600:  71  85 105;
  --c-slate-700:  51  65  85;
  --c-slate-800:  30  41  59;
  --c-slate-900:  15  23  42;
  --c-slate-950:   2   6  23;

  /* Zinc (Tailwind default) */
  --c-zinc-50:  250 250 250;
  --c-zinc-100: 244 244 245;
  --c-zinc-200: 228 228 231;
  --c-zinc-300: 212 212 216;
  --c-zinc-400: 161 161 170;
  --c-zinc-500: 113 113 122;
  --c-zinc-600:  82  82  91;
  --c-zinc-700:  63  63  70;
  --c-zinc-800:  39  39  42;
  --c-zinc-900:  24  24  27;
  --c-zinc-950:   9   9  11;

  /* Neutral (Tailwind default) */
  --c-neutral-50:  250 250 250;
  --c-neutral-100: 245 245 245;
  --c-neutral-200: 229 229 229;
  --c-neutral-300: 212 212 212;
  --c-neutral-400: 163 163 163;
  --c-neutral-500: 115 115 115;
  --c-neutral-600:  82  82  82;
  --c-neutral-700:  64  64  64;
  --c-neutral-800:  38  38  38;
  --c-neutral-900:  23  23  23;
  --c-neutral-950:  10  10  10;

  /* Stone (Tailwind default) */
  --c-stone-50:  250 250 249;
  --c-stone-100: 245 245 244;
  --c-stone-200: 231 229 228;
  --c-stone-300: 214 211 209;
  --c-stone-400: 168 162 158;
  --c-stone-500: 120 113 108;
  --c-stone-600:  87  83  78;
  --c-stone-700:  68  64  60;
  --c-stone-800:  41  37  36;
  --c-stone-900:  28  25  23;
  --c-stone-950:  12  10  9;
}

/* Dark theme override — add data-theme="dark" to <html> to activate */
[data-theme="dark"] {
  --zx-ink:     #F5F5F7;
  --zx-muted:   #A1A1A6;
  --zx-stroke:  #2C2C2E;
  --zx-paper:   #0B0B0F;
  --zx-cloud:   #1C1C1E;
  --zx-surface: #161618;
  /* Su fondo scuro la bolla non puo' essere nera (sparirebbe): grigio schiarito, testo chiaro. */
  --zx-chat-accent:    #2C2C2E;
  --zx-chat-on-accent: #F5F5F7;
  --zx-border-hairline: 1px solid rgba(255, 255, 255, 0.08);
  --zx-border-hover:    1px solid rgba(255, 255, 255, 0.14);
  --zx-shadow-rest:
    0 1px 2px rgba(0,0,0,0.4),
    0 8px 24px rgba(0,0,0,0.35);
  --zx-shadow-hover:
    0 2px 4px rgba(0,0,0,0.5),
    0 20px 40px rgba(0,0,0,0.5);

  /* Palette neutre invertite: 50 ↔ 900, 100 ↔ 800, ecc.
     Cosi' tutti gli sfondi chiari diventano scuri e i testi scuri diventano chiari. */
  --c-gray-50:    17  24  39;
  --c-gray-100:   31  41  55;
  --c-gray-200:   55  65  81;
  --c-gray-300:   75  85  99;
  --c-gray-400:  107 114 128;
  --c-gray-500:  156 163 175;
  --c-gray-600:  209 213 219;
  --c-gray-700:  229 231 235;
  --c-gray-800:  243 244 246;
  --c-gray-900:  249 250 251;
  --c-gray-950:  253 254 255;

  --c-slate-50:    15  23  42;
  --c-slate-100:   30  41  59;
  --c-slate-200:   51  65  85;
  --c-slate-300:   71  85 105;
  --c-slate-400:  100 116 139;
  --c-slate-500:  148 163 184;
  --c-slate-600:  203 213 225;
  --c-slate-700:  226 232 240;
  --c-slate-800:  241 245 249;
  --c-slate-900:  248 250 252;
  --c-slate-950:  253 254 255;

  --c-zinc-50:    24  24  27;
  --c-zinc-100:   39  39  42;
  --c-zinc-200:   63  63  70;
  --c-zinc-300:   82  82  91;
  --c-zinc-400:  113 113 122;
  --c-zinc-500:  161 161 170;
  --c-zinc-600:  212 212 216;
  --c-zinc-700:  228 228 231;
  --c-zinc-800:  244 244 245;
  --c-zinc-900:  250 250 250;
  --c-zinc-950:  253 253 253;

  --c-neutral-50:    23  23  23;
  --c-neutral-100:   38  38  38;
  --c-neutral-200:   64  64  64;
  --c-neutral-300:   82  82  82;
  --c-neutral-400:  115 115 115;
  --c-neutral-500:  163 163 163;
  --c-neutral-600:  212 212 212;
  --c-neutral-700:  229 229 229;
  --c-neutral-800:  245 245 245;
  --c-neutral-900:  250 250 250;
  --c-neutral-950:  253 253 253;

  --c-stone-50:    28  25  23;
  --c-stone-100:   41  37  36;
  --c-stone-200:   68  64  60;
  --c-stone-300:   87  83  78;
  --c-stone-400:  120 113 108;
  --c-stone-500:  168 162 158;
  --c-stone-600:  214 211 209;
  --c-stone-700:  231 229 228;
  --c-stone-800:  245 245 244;
  --c-stone-900:  250 250 249;
  --c-stone-950:  253 253 252;
}

/* ---------- 2. CARD ---------- */
.zx-card {
  background: var(--zx-surface);
  border: var(--zx-border-hairline);
  border-radius: var(--zx-radius-xl);
  box-shadow: var(--zx-shadow-rest);
  transition:
    transform var(--zx-dur-base) var(--zx-ease),
    box-shadow var(--zx-dur-base) var(--zx-ease),
    border-color var(--zx-dur-fast) ease;
  will-change: transform;
  position: relative;
}
.zx-card:not(.zx-card-static):hover {
  transform: translateY(-4px);
  box-shadow: var(--zx-shadow-hover);
  border: var(--zx-border-hover);
}

/* Modificatore: card statica senza lift/shadow/border-hover.
   Usare per wrapper di tabelle e calendari dove l'hover deve apparire SOLO
   sui singoli item (riga, day-cell), non sull'intera card. */
.zx-card.zx-card-static {
  will-change: auto;
}

/* Optional subtle noise overlay for premium feel */
.zx-card.zx-noise { overflow: hidden; }
.zx-card.zx-noise::before {
  content: "";
  position: absolute; inset: 0;
  pointer-events: none;
  border-radius: inherit;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='200' height='200'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='2'/><feColorMatrix values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.03 0'/></filter><rect width='100%25' height='100%25' filter='url(%23n)'/></svg>");
  mix-blend-mode: multiply;
}

/* ---------- 2b. TABLE SHELL (cornice tabella arrotondata, app-wide) ----------
   Cornice riutilizzabile per le tabelle desktop: bordo hairline + angoli
   arrotondati + clip del contenuto in scroll orizzontale. Uniforma l'aspetto
   di TUTTE le tabelle a video.
   Uso: avvolgere il SOLO container con overflow-x (la mirror-scrollbar sticky
   deve restare FUORI, sibling sotto la shell, per ancorarsi al <main>).
   overflow:hidden qui clippa gli angoli senza alterare lo sticky dell'header
   (che resta ancorato al container overflow-x interno). */
.zx-table-shell {
  border: 1px solid var(--zx-stroke);
  /* Solo angoli superiori arrotondati: il bordo inferiore resta dritto perche'
     sotto la tabella vivono mirror-scrollbar / paginazione / scroll infinito. */
  border-radius: var(--zx-radius-lg) var(--zx-radius-lg) 0 0;
  overflow: hidden;
  background: var(--zx-surface);
}

/* ---------- 2.9 LINK NEL TESTO ---------- */
/* Una parola linkata dentro una frase (avvisi, riquadri, note) e' SEMPRE nel blu del marchio
   `--zx-brand` e sottolineata: nera si confonde col testo e non si capisce che si puo' cliccare
   (2026-09-14, decisione dell'utente). Vale per <a> e per i <button> che fanno da link.
   Prima erano ~12 ricette in linea con lo stesso colore piu' una nera: il colore sta SOLO qui.
   ⛔ Non e' per i bottoni (.zx-btn) ne' per le voci di navigazione: solo per il testo. */
.zx-link {
  color: var(--zx-brand);
  text-decoration: underline;
  text-underline-offset: 2px;
  font-weight: 600;
  cursor: pointer;
  transition: opacity .15s ease;
}
.zx-link:hover { opacity: .8; }
.zx-link:disabled { opacity: .5; cursor: not-allowed; }

/* ---------- 3. BUTTONS ---------- */
/* Shared base
   ⚠️ I BOTTONI SONO TONDI (2026-08-22, decisione dell'utente): i lati corti sono semicerchi,
   e la regola vale per TUTTI i bottoni d'azione, di qualunque misura. Il raggio sta SOLO qui:
   un bottone che si scrive il proprio `rounded-*` in Tailwind non segue questa regola ed e' da
   riportare su .zx-btn, non da aggiustare sul posto.
   Perche' 9999px e non un valore in pixel: con un raggio fisso il bottone cambia forma al
   cambiare dell'altezza (44, 36, 28px), mentre cosi' resta una pillola a ogni misura. */
.zx-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .5rem;
  padding: 0 1rem;
  height: 44px;
  /* ⚠️ 14px, NON tondo. Cambiato il 2026-08-24 su richiesta dell'utente: il riferimento e'
     la pillola dei filtri, e bottoni tondi accanto a pillole a 14px erano due linguaggi
     diversi sulla stessa riga. (Dal 22/08 al 24/08 qui c'era `9999px`.) Il raggio vive SOLO
     qui: le varianti di misura non lo riscrivono. */
  border-radius: var(--zx-radius-md);
  font-family: var(--zx-font-sans);
  font-weight: 500;
  font-size: .95rem;
  line-height: 1;
  letter-spacing: -0.005em;
  cursor: pointer;
  border: 1px solid transparent;
  transition:
    transform var(--zx-dur-fast) var(--zx-ease),
    box-shadow var(--zx-dur-fast) var(--zx-ease),
    background-color var(--zx-dur-fast) ease,
    border-color var(--zx-dur-fast) ease,
    color var(--zx-dur-fast) ease;
  user-select: none;
  text-decoration: none;
  white-space: nowrap;
}
/* Active (pressione) solo quando il bottone e' abilitato. */
.zx-btn:not(:disabled):not([aria-disabled="true"]):active { transform: translateY(0) scale(0.98); }
.zx-btn:focus-visible {
  outline: 2px solid var(--zx-ink);
  outline-offset: 2px;
}

/* Disabled — NESSUN hover, non cliccabile, cursore not-allowed.
   Gli hover/active sono neutralizzati a monte: i selettori :hover/:active sotto sono tutti
   scopati con :not(:disabled):not([aria-disabled]) → un bottone disabilitato non riceve MAI
   l'animazione di hover. Il click e' gia' bloccato dall'attributo `disabled` sui <button>;
   per gli elementi non-button marcati aria-disabled aggiungiamo pointer-events:none. */
.zx-btn:disabled,
.zx-btn[aria-disabled="true"] {
  cursor: not-allowed;
  opacity: .5;
  transform: none;
  box-shadow: none;
}
.zx-btn[aria-disabled="true"] {
  pointer-events: none;
}

/* Hover animazione (lift) per TUTTI i bottoni cliccabili, inclusi quelli "nudi" senza variante
   (es. bottoni distruttivi rossi dei modal). Escluso ghost (hover solo di sfondo). I disabilitati
   non entrano mai qui grazie a :not(:disabled). */
.zx-btn:not(.zx-btn-ghost):not(:disabled):not([aria-disabled="true"]):hover {
  transform: translateY(-2px);
  box-shadow: var(--zx-shadow-hover);
}

/* Primary — fill scuro (ink), testo chiaro (paper). In dark mode i token si invertono.
   Hover con ombra neutra. */
.zx-btn-primary {
  background: var(--zx-ink);
  color: var(--zx-paper);
}
.zx-btn-primary:not(:disabled):not([aria-disabled="true"]):hover {
  transform: translateY(-2px);
  box-shadow: var(--zx-shadow-hover);
}

/* Secondary — white surface, hairline border, icon-button style */
.zx-btn-secondary {
  background: var(--zx-surface);
  color: var(--zx-ink);
  border-color: var(--zx-stroke);
}
.zx-btn-secondary:not(:disabled):not([aria-disabled="true"]):hover {
  transform: translateY(-2px);
  box-shadow: var(--zx-shadow-rest);
  border-color: var(--zx-border-hover-color);
}

/* Ghost — flat, for nav links or low-emphasis actions */
.zx-btn-ghost {
  background: transparent;
  color: var(--zx-ink);
}
.zx-btn-ghost:not(:disabled):not([aria-disabled="true"]):hover { background: var(--zx-cloud); }

/* Danger — azione distruttiva (rosso), es. bottoni "Elimina"/"Annulla etichetta" dei modal.
   Hover: rosso piu' scuro + lift. */
.zx-btn-danger {
  background: #B91C1C;
  color: #fff;
}
.zx-btn-danger:not(:disabled):not([aria-disabled="true"]):hover {
  background: #7F1D1D;
  transform: translateY(-2px);
  box-shadow: var(--zx-shadow-hover);
}

/* Warning — azione sensibile non distruttiva (arancio), es. "Disattiva". Hover: arancio scuro + lift. */
.zx-btn-warning {
  background: #D97706;
  color: #fff;
}
.zx-btn-warning:not(:disabled):not([aria-disabled="true"]):hover {
  background: #B45309;
  transform: translateY(-2px);
  box-shadow: var(--zx-shadow-hover);
}

/* Icon-only — square */
.zx-btn-icon {
  width: 44px;
  height: 44px;
  padding: 0;
}

/* Small size variant */
/* Le misure NON riscrivono il raggio: la pillola di .zx-btn si adatta da sola all'altezza. */
.zx-btn-sm { height: 36px; padding: 0 .75rem; font-size: .875rem; }

/* Extra-small size variant — densita' compatta (es. action bar pagina Ordini) */
.zx-btn-xs { height: 28px; padding: 0 .5rem; font-size: .75rem; gap: .3125rem; }
/* Icon-only in versione sm: quadrato 36px (sovrascrive il 44px di .zx-btn-icon) */
.zx-btn-icon.zx-btn-sm { width: 36px; height: 36px; padding: 0; }
/* Icon-only in versione xs: quadrato 28px (sovrascrive il 44px di .zx-btn-icon) */
.zx-btn-icon.zx-btn-xs { width: 28px; height: 28px; padding: 0; }

/* ---------- 4. CHIP (icon badge inside cards) ---------- */
.zx-chip {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border-radius: var(--zx-radius-md);
  background: var(--zx-cloud);
  transition: transform var(--zx-dur-base) var(--zx-ease);
}
.zx-card:hover .zx-chip { transform: translateY(-2px) scale(1.05); }

/* Tinted chip variants */
.zx-chip-blue    { background: #EEF4FF; color: #2563EB; }
.zx-chip-green   { background: #E7F7EE; color: #059669; }
.zx-chip-purple  { background: #F7EEFB; color: #9333EA; }
.zx-chip-amber   { background: #FDF1E3; color: #D97706; }
.zx-chip-pink    { background: #FCE7F3; color: #DB2777; }

/* Dark mode: chip diventano scuri (rgba 8% del colore brand) mantenendo l'icona
   nel colore originale acceso. Niente piu' "rettangolo chiaro" attorno all'icona. */
[data-theme="dark"] .zx-chip-blue    { background: rgba(37, 99, 235, 0.18); color: #60A5FA; }
[data-theme="dark"] .zx-chip-green   { background: rgba(5, 150, 105, 0.18); color: #34D399; }
[data-theme="dark"] .zx-chip-purple  { background: rgba(147, 51, 234, 0.18); color: #C084FC; }
[data-theme="dark"] .zx-chip-amber   { background: rgba(217, 119, 6, 0.18); color: #FBBF24; }
[data-theme="dark"] .zx-chip-pink    { background: rgba(219, 39, 119, 0.18); color: #F472B6; }

/* ---------- 5. BADGE (status pills) ---------- */
.zx-badge {
  display: inline-flex;
  align-items: center;
  padding: 4px 8px;
  border-radius: var(--zx-radius-sm);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: -0.005em;
}
.zx-badge-valid  { background: #D1FAE5; color: #047857; }
.zx-badge-risky  { background: #FEF3C7; color: #B45309; }
.zx-badge-error  { background: #FEE2E2; color: #B91C1C; }

/* ---------- 6. INPUT ---------- */
.zx-input {
  height: 44px;
  padding: 0 1rem;
  border-radius: var(--zx-radius-md);
  background: var(--zx-surface);
  border: 1px solid var(--zx-stroke);
  font-family: var(--zx-font-sans);
  font-size: .9rem;
  color: var(--zx-ink);
  transition: border-color var(--zx-dur-fast) ease;
  width: 100%;
}
.zx-input::placeholder { color: var(--zx-muted); }
/* Messa a fuoco: cambia il BORDO, da grigio a nero, e basta.
   ⛔ Niente alone: fino al 2026-09-07 c'era un anello di 4px al 10% di nero attorno al campo, che
   a schermo si legge come uno spazio vuoto fra il campo e cio' che ha intorno — sembra un secondo
   riquadro, non un segnale.
   ⚠️ Il cambio di bordo NON e' decorativo e non va tolto: con `outline: none` e' l'unica cosa che
   dice a chi si muove con la tastiera dove si trova. Grigio → nero e' una differenza netta, quindi
   il campo attivo resta riconoscibile senza l'anello. */
.zx-input:focus {
  outline: none;
  border-color: var(--zx-ink);
}

/* ---------- 6.1 CAMPO IN SOLA LETTURA ----------
   Funzionalita': disegna un valore che l'utente NON puo' modificare (email di accesso,
                  indirizzo del connettore, store di una scatola, codice appena letto...)
                  con le STESSE misure del campo modificabile .zx-input: altezza 44px,
                  imbottitura 1rem, testo .9rem, raggio --zx-radius-lg, bordo --zx-stroke.
   Obiettivo: avere UNA ricetta sola per tutti i campi non modificabili dell'applicazione.
              La differenza rispetto a .zx-input e' UNA e sempre la stessa: lo sfondo
              --zx-cloud al posto di --zx-surface (piu' nessun alone di messa a fuoco,
              nessun cursore di scrittura). Niente altri segni: no opacita' ridotta,
              no raggi diversi, no palette grigie estranee ai token.
   Uso: si mette DA SOLA, mai insieme a .zx-input (che porterebbe lo sfondo bianco).
        Funziona sia su <input readonly>/<textarea readonly> sia su <div>/<p>/<span>
        usati come riquadro-valore: per questi ultimi il contenuto viene centrato
        verticalmente e l'altezza diventa un minimo, cosi' un valore lungo va a capo.
   ⚠️ Le misure sono ricopiate da .zx-input di proposito (non si tocca quella regola,
      e' montata ovunque): se cambiano li', vanno cambiate anche qui.
   ⚠️ Un campo spento SOLO durante il salvataggio non e' "in sola lettura": quello
      resta .zx-input con il suo attributo disabled.
*/
.zx-input-readonly {
  height: 44px;
  padding: 0 1rem;
  border-radius: var(--zx-radius-md);
  background: var(--zx-cloud);
  border: 1px solid var(--zx-stroke);
  font-family: var(--zx-font-sans);
  font-size: .9rem;
  color: var(--zx-ink);
  width: 100%;
  cursor: default;
}
/* Sui riquadri non-form l'altezza e' un minimo e il valore sta al centro in verticale */
div.zx-input-readonly,
p.zx-input-readonly,
span.zx-input-readonly {
  display: flex;
  align-items: center;
  height: auto;
  min-height: 44px;
}
/* Nessun alone di messa a fuoco: il campo si puo' selezionare/copiare, non scrivere */
.zx-input-readonly:focus {
  outline: none;
  border-color: var(--zx-stroke);
  box-shadow: none;
}
/* Un <input>/<textarea> in sola lettura non deve sembrare spento: il segno e' lo sfondo */
.zx-input-readonly:disabled {
  opacity: 1;
  -webkit-text-fill-color: var(--zx-ink);
}

/* ---------- 7. NAV LINK (sidebar item) ---------- */
.zx-nav-link {
  display: flex;
  align-items: center;
  gap: .75rem;
  padding: .625rem .75rem;
  border-radius: var(--zx-radius-md);
  color: var(--zx-ink);
  text-decoration: none;
  font-size: .95rem;
  transition: background-color var(--zx-dur-fast) ease, box-shadow var(--zx-dur-fast) ease;
}
.zx-nav-link:hover { background: var(--zx-cloud); }
.zx-nav-link.is-active {
  background: var(--zx-surface);
  box-shadow: var(--zx-shadow-rest);
}

/* ---------- 7b. NAV ICON HOVER ANIMATIONS ----------
   Animazioni applicate alle icone (Lucide o custom) nelle voci di navigazione.
   Ogni icona riceve un data-nav-icon derivato dal label (lowercase, kebab-case).
   Animazione attiva solo su hover/focus della voce.

   overflow:visible permette ai sotto-elementi (flap, lid, ecc.) di uscire dal
   viewBox quando sono trasformati (rotazioni grandi, scale > 1) senza essere clippati. */
.zx-nav-icon {
  transition: transform var(--zx-dur-fast) ease, color var(--zx-dur-fast) ease;
  transform-origin: center;
  will-change: transform;
  overflow: visible;
}

/* ---------- Ordini — la scatola apre i flap su hover ----------
   I due flap sono drawn come rettangoli ~9x2 sopra il bordo superiore del corpo.
   A riposo giacciono piatti, formando un coperchio chiuso con una giuntura
   visibile al centro a x=12 (l'edge condivisa fra i due path).
   In hover ruotano verso l'esterno attorno al proprio cardine (angolo basso-esterno),
   con un easing back-out che da' la sensazione di "molla". */
.zx-nav-icon .zx-box-flap {
  transform-box: fill-box;
  transition: transform 380ms cubic-bezier(0.34, 1.56, 0.64, 1);
}
.zx-nav-icon .zx-box-flap-left {
  /* cardine = angolo basso-sinistro del bounding box del path = (3, 10) in coord SVG */
  transform-origin: 0% 100%;
}
.zx-nav-icon .zx-box-flap-right {
  /* cardine = angolo basso-destro del bounding box del path = (21, 10) in coord SVG */
  transform-origin: 100% 100%;
}
.zx-nav-link:hover .zx-nav-icon[data-nav-icon="ordini"] .zx-box-flap-left,
.zx-nav-link:focus-visible .zx-nav-icon[data-nav-icon="ordini"] .zx-box-flap-left {
  transform: rotate(-100deg);
}
.zx-nav-link:hover .zx-nav-icon[data-nav-icon="ordini"] .zx-box-flap-right,
.zx-nav-link:focus-visible .zx-nav-icon[data-nav-icon="ordini"] .zx-box-flap-right {
  transform: rotate(100deg);
}

/* ---------- Stock — il cancello del magazzino apre le due ante ----------
   Le due ante a riposo si toccano al centro a x=12 formando un cancello chiuso.
   In hover scorrono lateralmente verso l'esterno (translateX 100% = piena larghezza
   dell'anta) e sfumano opacita', come se rientrassero nelle pareti del magazzino. */
.zx-nav-icon .zx-gate-panel {
  transform-box: fill-box;
  transform-origin: center;
  transition:
    transform 420ms cubic-bezier(0.65, 0.05, 0.36, 1),
    opacity 360ms ease;
}
.zx-nav-link:hover .zx-nav-icon[data-nav-icon="stock"] .zx-gate-panel-left,
.zx-nav-link:focus-visible .zx-nav-icon[data-nav-icon="stock"] .zx-gate-panel-left {
  transform: translateX(-100%);
  opacity: 0.15;
}
.zx-nav-link:hover .zx-nav-icon[data-nav-icon="stock"] .zx-gate-panel-right,
.zx-nav-link:focus-visible .zx-nav-icon[data-nav-icon="stock"] .zx-gate-panel-right {
  transform: translateX(100%);
  opacity: 0.15;
}

/* ---------- Spedizioni — il camion guida sul posto ----------
   Le due ruote ruotano in continuo (loop infinito) attorno al loro centro.
   Il corpo (cassone + cabina) sobbalza verticalmente di 1px per simulare il motore acceso.
   transform-box: fill-box assicura che la rotazione del cerchio avvenga attorno al
   centro geometrico del path, non attorno all'origine 0,0 dell'SVG. */
.zx-nav-icon .zx-truck-wheel {
  transform-box: fill-box;
  transform-origin: center;
}
.zx-nav-link:hover .zx-nav-icon[data-nav-icon="spedizioni"] .zx-truck-wheel,
.zx-nav-link:focus-visible .zx-nav-icon[data-nav-icon="spedizioni"] .zx-truck-wheel {
  animation: zx-icon-wheel-spin 700ms linear infinite;
}
.zx-nav-link:hover .zx-nav-icon[data-nav-icon="spedizioni"] .zx-truck-body,
.zx-nav-link:focus-visible .zx-nav-icon[data-nav-icon="spedizioni"] .zx-truck-body {
  animation: zx-icon-truck-bump 360ms ease-in-out infinite;
}
@keyframes zx-icon-wheel-spin {
  from { transform: rotate(0deg); }
  to   { transform: rotate(360deg); }
}
@keyframes zx-icon-truck-bump {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-0.6px); }
}

/* ---------- Tracking — il radar emette onde concentriche ----------
   Tre cerchi a raggio 2 partono dal centro (12,12) invisibili (opacity 0).
   In hover si materializzano e si scalano fino a 3.5x (raggio effettivo ~7,
   appena dentro l'anello esterno statico a r=8) sfumando opacita' a 0.
   I delay scaglionati (0/500/1000ms) su loop 1500ms creano un sweep continuo. */
.zx-nav-icon .zx-radar-wave {
  transform-box: fill-box;
  transform-origin: center;
  opacity: 0;
}
.zx-nav-link:hover .zx-nav-icon[data-nav-icon="tracking"] .zx-radar-wave,
.zx-nav-link:focus-visible .zx-nav-icon[data-nav-icon="tracking"] .zx-radar-wave {
  animation: zx-icon-radar-pulse 1500ms ease-out infinite;
}
.zx-nav-link:hover .zx-nav-icon[data-nav-icon="tracking"] .zx-radar-wave-2,
.zx-nav-link:focus-visible .zx-nav-icon[data-nav-icon="tracking"] .zx-radar-wave-2 {
  animation-delay: 500ms;
}
.zx-nav-link:hover .zx-nav-icon[data-nav-icon="tracking"] .zx-radar-wave-3,
.zx-nav-link:focus-visible .zx-nav-icon[data-nav-icon="tracking"] .zx-radar-wave-3 {
  animation-delay: 1000ms;
}
@keyframes zx-icon-radar-pulse {
  0%   { transform: scale(0.4); opacity: 0.9; }
  100% { transform: scale(3.5); opacity: 0; }
}

/* ---------- Brand — la maglietta ondeggia come un capo appeso ----------
   La t-shirt oscilla a pendolo attorno al colletto (transform-origin in alto al
   centro), simulando un capo appeso che dondola. Loop continuo solo su hover/focus. */
.zx-nav-link:hover .zx-nav-icon[data-nav-icon="brand"],
.zx-nav-link:focus-visible .zx-nav-icon[data-nav-icon="brand"] {
  transform-box: fill-box;
  transform-origin: 50% 12%;
  animation: zx-icon-shirt-sway 1400ms cubic-bezier(0.45, 0, 0.55, 1) infinite;
}
@keyframes zx-icon-shirt-sway {
  0%, 100% { transform: rotate(0deg); }
  25%      { transform: rotate(-6deg); }
  75%      { transform: rotate(6deg); }
}

/* ---------- Impostazioni — l'ingranaggio ruota lentamente in continuo ----------
   Lucide Settings e' gia' un ingranaggio simmetrico: bastano 4s di rotazione lineare
   sull'intero SVG per avere l'effetto meccanico desiderato. transform-origin: center
   e' gia' definito sulla classe base .zx-nav-icon, quindi la rotazione e' centrata. */
.zx-nav-link:hover .zx-nav-icon[data-nav-icon="impostazioni"],
.zx-nav-link:focus-visible .zx-nav-icon[data-nav-icon="impostazioni"] {
  animation: zx-icon-gear-spin 4s linear infinite;
}
@keyframes zx-icon-gear-spin {
  from { transform: rotate(0deg); }
  to   { transform: rotate(360deg); }
}

/* ---------- Pick & Pack — operatore che cammina spingendo il carrello ----------
   La ruota del carrello gira in continuo (700ms/giro, lineare) attorno al suo centro.
   In contemporanea l'intero SVG fa un piccolo bob verticale (0.6px ogni 600ms),
   sincronizzato col passo dell'operatore. Le due animazioni non confliggono perche'
   transform e' applicato per-elemento nello stack SVG (il padre trasla, il figlio ruota). */
.zx-nav-icon .zx-cart-wheel {
  transform-box: fill-box;
  transform-origin: center;
}
.zx-nav-link:hover .zx-nav-icon[data-nav-icon="pick-and-pack"] .zx-cart-wheel,
.zx-nav-link:focus-visible .zx-nav-icon[data-nav-icon="pick-and-pack"] .zx-cart-wheel {
  animation: zx-icon-cart-wheel-spin 700ms linear infinite;
}
.zx-nav-link:hover .zx-nav-icon[data-nav-icon="pick-and-pack"],
.zx-nav-link:focus-visible .zx-nav-icon[data-nav-icon="pick-and-pack"] {
  animation: zx-icon-cart-walk 600ms ease-in-out infinite;
}
@keyframes zx-icon-cart-wheel-spin {
  from { transform: rotate(0deg); }
  to   { transform: rotate(360deg); }
}
@keyframes zx-icon-cart-walk {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-0.6px); }
}

/* ---------- Documenti — l'angolo della pagina si arriccia (page peel) ----------
   Il triangolino dell'angolo ruota di -25deg attorno al suo punto di piegatura
   (angolo basso-sinistro del triangolo = punto 14,8 in coord SVG = bottom-left del bbox).
   In contemporanea l'intero documento si inclina lievissimamente per dare profondita'. */
.zx-nav-icon .zx-doc-corner {
  transform-box: fill-box;
  transform-origin: 0% 100%;
  transition: transform 380ms cubic-bezier(0.34, 1.56, 0.64, 1);
}
.zx-nav-link:hover .zx-nav-icon[data-nav-icon="documenti"] .zx-doc-corner,
.zx-nav-link:focus-visible .zx-nav-icon[data-nav-icon="documenti"] .zx-doc-corner {
  transform: rotate(-30deg) translateY(-1px);
}
.zx-nav-link:hover .zx-nav-icon[data-nav-icon="documenti"],
.zx-nav-link:focus-visible .zx-nav-icon[data-nav-icon="documenti"] {
  transform: rotate(-2deg);
}

/* ---------- Note — la penna oscilla come se stesse scrivendo (scribble) ----------
   La penna ruota leggermente avanti/indietro attorno alla sua punta (basso-sinistra)
   con un movimento veloce ripetuto, dando l'effetto "sta scribacchiando un appunto". */
.zx-nav-icon .zx-pen-body {
  transform-box: fill-box;
  transform-origin: 0% 100%;
}
.zx-nav-link:hover .zx-nav-icon[data-nav-icon="note"] .zx-pen-body,
.zx-nav-link:focus-visible .zx-nav-icon[data-nav-icon="note"] .zx-pen-body {
  animation: zx-icon-pen-scribble 520ms ease-in-out infinite;
}
@keyframes zx-icon-pen-scribble {
  0%, 100% { transform: rotate(0deg) translateX(0); }
  25%      { transform: rotate(-6deg) translateX(-0.5px); }
  50%      { transform: rotate(0deg) translateX(0); }
  75%      { transform: rotate(6deg) translateX(0.5px); }
}

/* ---------- Integrazioni — la spina vibra, elettricita' che scorre nei pin ----------
   I due pin oscillano lateralmente di mezzo pixel a velocita' alta (180ms),
   con direzioni opposte per simulare il "buzz" elettrico. */
.zx-nav-icon .zx-plug-prong {
  transform-box: fill-box;
  transform-origin: center;
}
.zx-nav-link:hover .zx-nav-icon[data-nav-icon="integrazioni"] .zx-plug-prong-left,
.zx-nav-link:focus-visible .zx-nav-icon[data-nav-icon="integrazioni"] .zx-plug-prong-left {
  animation: zx-icon-plug-buzz-left 180ms ease-in-out infinite;
}
.zx-nav-link:hover .zx-nav-icon[data-nav-icon="integrazioni"] .zx-plug-prong-right,
.zx-nav-link:focus-visible .zx-nav-icon[data-nav-icon="integrazioni"] .zx-plug-prong-right {
  animation: zx-icon-plug-buzz-right 180ms ease-in-out infinite;
}
@keyframes zx-icon-plug-buzz-left {
  0%, 100% { transform: translateX(0); }
  50%      { transform: translateX(-0.5px); }
}
@keyframes zx-icon-plug-buzz-right {
  0%, 100% { transform: translateX(0); }
  50%      { transform: translateX(0.5px); }
}

/* ---------- Smartphone ("Network" / Social) — vibrazione notifica ----------
   Il corpo del telefono ruota +/-5deg con origine al bottom (telefono tenuto in mano)
   per simulare la vibrazione di una notifica in arrivo. */
.zx-nav-icon .zx-phone-body {
  transform-box: fill-box;
  transform-origin: 50% 100%;
}
.zx-nav-link:hover .zx-nav-icon[data-nav-icon="network"] .zx-phone-body,
.zx-nav-link:focus-visible .zx-nav-icon[data-nav-icon="network"] .zx-phone-body {
  animation: zx-icon-phone-vibrate 350ms ease-in-out infinite;
}
@keyframes zx-icon-phone-vibrate {
  0%, 100% { transform: rotate(0deg); }
  20%      { transform: rotate(-5deg); }
  40%      { transform: rotate(4deg); }
  60%      { transform: rotate(-3deg); }
  80%      { transform: rotate(2deg); }
}

/* ---------- Dashboard — il globo terrestre gira su hover ----------
   GlobeIcon (custom) ha 3 meridiani (.zx-globe-meridian) sovrapposti a riposo (= un solo
   meridiano centrale, globo canonico). In hover ognuno anima scaleX dalla linea centrale alla
   silhouette con delay scaglionati a terzi del periodo: i meridiani spazzano in sequenza,
   dando la sensazione della Terra che ruota attorno al proprio asse. */
.zx-nav-link:hover .zx-nav-icon[data-nav-icon="dashboard"] .zx-globe-meridian,
.zx-nav-link:focus-visible .zx-nav-icon[data-nav-icon="dashboard"] .zx-globe-meridian {
  animation: zx-globe-spin 2.4s ease-in-out infinite;
  transform-box: fill-box;
  transform-origin: center;
}
.zx-nav-link:hover .zx-nav-icon[data-nav-icon="dashboard"] .zx-globe-meridian[data-m="2"],
.zx-nav-link:focus-visible .zx-nav-icon[data-nav-icon="dashboard"] .zx-globe-meridian[data-m="2"] {
  animation-delay: -0.8s;
}
.zx-nav-link:hover .zx-nav-icon[data-nav-icon="dashboard"] .zx-globe-meridian[data-m="3"],
.zx-nav-link:focus-visible .zx-nav-icon[data-nav-icon="dashboard"] .zx-globe-meridian[data-m="3"] {
  animation-delay: -1.6s;
}
/* scaleX 0.05 (linea centrale, meridiano visto di taglio) -> 1.95 (silhouette) -> 0.05.
   rx base 4.6: 4.6*0.05≈0.23 (linea sottile), 4.6*1.95≈9.0 (bordo del globo). */
@keyframes zx-globe-spin {
  0%   { transform: scaleX(0.05); }
  50%  { transform: scaleX(1.95); }
  100% { transform: scaleX(0.05); }
}
/* Accessibilita': niente rotazione per chi ha richiesto meno movimento. */
@media (prefers-reduced-motion: reduce) {
  .zx-nav-icon[data-nav-icon="dashboard"] .zx-globe-meridian {
    animation: none !important;
  }
}

/* ---------- Analytics — le barre del grafico crescono a scaletta ----------
   Le tre barre poggiano sulla base del grafico (y=20) e a riposo sono alla loro altezza piena.
   In hover ripartono schiacciate e si allungano verso l'alto, sfalsate di 80 ms: si legge come
   un grafico che si compila da sinistra a destra.
   ⚠️ transform-origin in UNITA' SVG (8px/13px/18px = la x della barra, 20px = la base) e NON
   `transform-box: fill-box`: una <line> verticale ha un riquadro largo zero, e su un riquadro di
   area nulla l'origine percentuale non e' affidabile. */
.zx-nav-icon .zx-chart-bar-1 { transform-origin: 8px 20px; }
.zx-nav-icon .zx-chart-bar-2 { transform-origin: 13px 20px; animation-delay: 80ms; }
.zx-nav-icon .zx-chart-bar-3 { transform-origin: 18px 20px; animation-delay: 160ms; }
.zx-nav-link:hover .zx-nav-icon[data-nav-icon="analytics"] .zx-chart-bar,
.zx-nav-link:focus-visible .zx-nav-icon[data-nav-icon="analytics"] .zx-chart-bar {
  animation: zx-icon-bars-climb 1.6s ease-out infinite;
}
/* La salita si ripete finche' il mouse resta sopra: cresce, scavalca di poco il traguardo, si
   assesta e resta ferma per un terzo del giro prima di ripartire — senza quella pausa sembrerebbe
   un tremolio invece di una salita.
   ⚠️ Nome diverso da `zx-icon-bar-grow`, che e' gia' preso dall'icona Admin Dashboard piu' sotto:
   a parita' di nome vince l'ultima dichiarazione del file, per TUTTI quelli che la usano. */
@keyframes zx-icon-bars-climb {
  0%        { transform: scaleY(0.08); }
  40%       { transform: scaleY(1.06); }
  55%, 100% { transform: scaleY(1); }
}
/* Accessibilita': niente crescita per chi ha chiesto meno movimento — le barre restano intere. */
@media (prefers-reduced-motion: reduce) {
  .zx-nav-icon[data-nav-icon="analytics"] .zx-chart-bar {
    animation: none !important;
  }
}

/* ---------- Operatori — pulse leggera del gruppo utenti ----------
   Lucide Users e' indivisibile in modo pulito: facciamo un breath sull'intero icona
   con scale 1 ↔ 1.06 lento. */
.zx-nav-link:hover .zx-nav-icon[data-nav-icon="operatori"],
.zx-nav-link:focus-visible .zx-nav-icon[data-nav-icon="operatori"] {
  animation: zx-icon-users-breath 1.4s ease-in-out infinite;
}
@keyframes zx-icon-users-breath {
  0%, 100% { transform: scale(1); }
  50%      { transform: scale(1.08); }
}

/* ---------- Chat — il messaggio che arriva ----------
   La voce Chat mostra il logo WhatsApp, che e' un glifo PIENO e indivisibile: non si possono
   animare parti sue (i tre puntini della scrittura, per dire, li' dentro non ci sono). Si anima
   quindi la bolla intera con il gesto di una notifica che entra: uno scatto verso l'alto, un
   rimbalzo appena piu' piccolo e un accenno di inclinazione, come una bolla che si posa.
   ⚠️ L'aggancio e' `data-nav-icon="chat"`, che WhatsAppLogo riceve da NavIcon: senza quello
   questa regola non troverebbe nessun elemento (era il motivo per cui la voce restava ferma).
   L'origine e' il basso: la bolla "sale" da dove poggia. */
.zx-nav-link:hover .zx-nav-icon[data-nav-icon="chat"],
.zx-nav-link:focus-visible .zx-nav-icon[data-nav-icon="chat"] {
  transform-box: fill-box;
  transform-origin: 50% 100%;
  animation: zx-icon-bubble-pop 1.1s cubic-bezier(0.34, 1.56, 0.64, 1) infinite;
}
@keyframes zx-icon-bubble-pop {
  0%       { transform: translateY(0) scale(1) rotate(0deg); }
  22%      { transform: translateY(-2px) scale(1.14) rotate(-6deg); }
  44%      { transform: translateY(0) scale(0.96) rotate(4deg); }
  62%      { transform: translateY(-0.8px) scale(1.04) rotate(-2deg); }
  78%, 100% { transform: translateY(0) scale(1) rotate(0deg); }
}
/* Accessibilita': chi ha chiesto meno movimento vede la bolla ferma. */
@media (prefers-reduced-motion: reduce) {
  .zx-nav-icon[data-nav-icon="chat"] {
    animation: none !important;
  }
}

/* ---------- Tickets — il braccio del microfono oscilla come se si stesse parlando ----------
   Il braccio mic e' incernierato al cuscinetto destro, punto SVG (21, 19).
   Bounding box del path L-shape: da (14, 19) a (21, 21) — angolo top-right del bbox = (21, 19),
   quindi transform-origin: 100% 0% (con transform-box: fill-box) corrisponde al cardine.
   Oscillazione ±4deg, ease-in-out, ciclo 1s — naturale, non robotica. */
.zx-nav-icon .zx-mic-boom {
  transform-box: fill-box;
  transform-origin: 100% 0%;
}
.zx-nav-link:hover .zx-nav-icon[data-nav-icon="tickets"] .zx-mic-boom,
.zx-nav-link:focus-visible .zx-nav-icon[data-nav-icon="tickets"] .zx-mic-boom {
  animation: zx-icon-mic-talk 0.8s ease-in-out infinite;
}
@keyframes zx-icon-mic-talk {
  0%, 100% { transform: rotate(-12deg); }
  50%      { transform: rotate(15deg); }
}

/* ---------- Abbonamento — la carta di credito viene "swippata" lateralmente ----------
   translateX oscillante lento per simulare lo swipe POS. */
.zx-nav-link:hover .zx-nav-icon[data-nav-icon="abbonamento"],
.zx-nav-link:focus-visible .zx-nav-icon[data-nav-icon="abbonamento"] {
  animation: zx-icon-card-swipe 1.2s ease-in-out infinite;
}
@keyframes zx-icon-card-swipe {
  0%, 100% { transform: translateX(0); }
  25%      { transform: translateX(-1.5px); }
  75%      { transform: translateX(1.5px); }
}

/* ---------- Admin Dashboard — le barre del grafico crescono in sequenza ----------
   Lucide BarChart3 ha 4 path: il primo e' l'asse, gli altri 3 sono le barre.
   Targettiamo le barre (nth-child 2,3,4) facendole scalare verticalmente
   dall'origine in basso (transform-origin: 50% 100%) con stagger. */
.zx-nav-link:hover .zx-nav-icon[data-nav-icon="admin-dashboard"] > *:nth-child(n+2),
.zx-nav-link:focus-visible .zx-nav-icon[data-nav-icon="admin-dashboard"] > *:nth-child(n+2) {
  animation: zx-icon-bar-grow 1.4s ease-in-out infinite;
  transform-box: fill-box;
  transform-origin: 50% 100%;
}
.zx-nav-link:hover .zx-nav-icon[data-nav-icon="admin-dashboard"] > *:nth-child(3),
.zx-nav-link:focus-visible .zx-nav-icon[data-nav-icon="admin-dashboard"] > *:nth-child(3) {
  animation-delay: 150ms;
}
.zx-nav-link:hover .zx-nav-icon[data-nav-icon="admin-dashboard"] > *:nth-child(4),
.zx-nav-link:focus-visible .zx-nav-icon[data-nav-icon="admin-dashboard"] > *:nth-child(4) {
  animation-delay: 300ms;
}
@keyframes zx-icon-bar-grow {
  0%, 100% { transform: scaleY(1); }
  50%      { transform: scaleY(0.55); }
}

/* ---------- Audit Log — la pergamena/scroll si srotola con ondulazione verticale ----------
   Sutile movimento up-down che evoca lo scroll del log. */
.zx-nav-link:hover .zx-nav-icon[data-nav-icon="audit-log"],
.zx-nav-link:focus-visible .zx-nav-icon[data-nav-icon="audit-log"] {
  animation: zx-icon-scroll-bounce 1.1s ease-in-out infinite;
}
@keyframes zx-icon-scroll-bounce {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-1.2px); }
}

/* ---------- Affiliazione — il regalo si scarta ----------
   `.zx-gift-lid` e' il gruppo coperchio + fiocco di GiftIcon. Si solleva di 3px inclinandosi
   appena, poi ricade sulla scatola e resta giu' per un pezzo del giro: senza quella pausa
   sembrerebbe un tremolio invece di un coperchio che si apre e si richiude.
   transform-origin al bordo basso del gruppo: il coperchio si stacca da dove poggia. */
.zx-nav-icon .zx-gift-lid {
  transform-box: fill-box;
  transform-origin: 50% 100%;
}
.zx-nav-link:hover .zx-nav-icon[data-nav-icon="affiliazione"] .zx-gift-lid,
.zx-nav-link:focus-visible .zx-nav-icon[data-nav-icon="affiliazione"] .zx-gift-lid {
  animation: zx-icon-gift-open 1.5s ease-in-out infinite;
}
@keyframes zx-icon-gift-open {
  0%        { transform: translateY(0) rotate(0deg); }
  30%       { transform: translateY(-3px) rotate(-7deg); }
  50%       { transform: translateY(-2.4px) rotate(-5deg); }
  68%, 100% { transform: translateY(0) rotate(0deg); }
}
/* Accessibilita': coperchio fermo per chi ha chiesto meno movimento. */
@media (prefers-reduced-motion: reduce) {
  .zx-nav-icon[data-nav-icon="affiliazione"] .zx-gift-lid {
    animation: none !important;
  }
}

/* ---------- Generazione Lead — la calamita attira ----------
   I tre trattini sotto la bocca del magnete sono INVISIBILI a riposo (opacity 0): l'icona ferma
   e' una calamita e basta, coerente con le sorelle Lucide. In hover compaiono uno dopo l'altro
   dal basso e salgono verso i poli sfumando — si legge come qualcosa che viene attirato dentro.
   Lo sfalsamento e' un terzo del giro per ciascuno, cosi' la scia non ha mai buchi. */
.zx-nav-icon .zx-magnet-scia {
  transform-box: fill-box;
  transform-origin: center;
  opacity: 0;
}
.zx-nav-link:hover .zx-nav-icon[data-nav-icon="generazione-lead"] .zx-magnet-scia,
.zx-nav-link:focus-visible .zx-nav-icon[data-nav-icon="generazione-lead"] .zx-magnet-scia {
  animation: zx-icon-magnet-attract 1.2s ease-out infinite;
}
.zx-nav-link:hover .zx-nav-icon[data-nav-icon="generazione-lead"] .zx-magnet-scia-2,
.zx-nav-link:focus-visible .zx-nav-icon[data-nav-icon="generazione-lead"] .zx-magnet-scia-2 {
  animation-delay: -0.4s;
}
.zx-nav-link:hover .zx-nav-icon[data-nav-icon="generazione-lead"] .zx-magnet-scia-3,
.zx-nav-link:focus-visible .zx-nav-icon[data-nav-icon="generazione-lead"] .zx-magnet-scia-3 {
  animation-delay: -0.8s;
}
@keyframes zx-icon-magnet-attract {
  0%   { transform: translateY(2.5px) scaleX(0.6); opacity: 0; }
  30%  { opacity: 0.9; }
  100% { transform: translateY(-4px) scaleX(1.1); opacity: 0; }
}
/* Accessibilita': niente scia per chi ha chiesto meno movimento — resta la sola calamita. */
@media (prefers-reduced-motion: reduce) {
  .zx-nav-icon[data-nav-icon="generazione-lead"] .zx-magnet-scia {
    animation: none !important;
  }
}

/* ---------- Costi operativi — la ricevuta si stacca ----------
   ⚠️ Resta l'icona Lucide `Receipt`, quella di sempre: qui NON si cambia il disegno, si anima
   l'SVG intero. E' la seconda riga della tabella "quando custom vs Lucide" — un'icona i cui path
   non hanno parti che ha senso muovere separatamente si anima tutta insieme.
   La ricevuta si inclina e sale di poco, come un foglietto che si stacca dal blocchetto. Un giro
   solo per volta: e' un movimento breve, in loop diventerebbe un tic. */
.zx-nav-icon[data-nav-icon="costi-operativi"] {
  transform-box: fill-box;
  transform-origin: center bottom;
  transition: transform 260ms cubic-bezier(0.34, 1.4, 0.64, 1);
}
.zx-nav-link:hover .zx-nav-icon[data-nav-icon="costi-operativi"],
.zx-nav-link:focus-visible .zx-nav-icon[data-nav-icon="costi-operativi"] {
  transform: translateY(-1.5px) rotate(-6deg);
}
/* Accessibilita': ferma per chi ha chiesto meno movimento. */
@media (prefers-reduced-motion: reduce) {
  .zx-nav-icon[data-nav-icon="costi-operativi"] {
    transition: none;
  }
  .zx-nav-link:hover .zx-nav-icon[data-nav-icon="costi-operativi"],
  .zx-nav-link:focus-visible .zx-nav-icon[data-nav-icon="costi-operativi"] {
    transform: none;
  }
}

/* ---------- 8. DIVIDER ---------- */
.zx-divider { height: 1px; background: var(--zx-stroke); border: 0; }

/* ---------- 9. ANIMATIONS (hook classes) ---------- */

/* Reveal on scroll — add .zx-reveal to any element,
   then the JS adds .is-visible when it enters viewport */
.zx-reveal {
  opacity: 0;
  transform: translateY(24px);
  transition:
    opacity var(--zx-dur-slow) var(--zx-ease),
    transform var(--zx-dur-slow) var(--zx-ease);
}
.zx-reveal.is-visible {
  opacity: 1;
  transform: none;
}

/* Staggered children — wrap siblings with .zx-stagger + .zx-reveal */
.zx-stagger > * {
  opacity: 0;
  transform: translateY(18px);
  transition:
    opacity var(--zx-dur-base) var(--zx-ease),
    transform var(--zx-dur-base) var(--zx-ease);
}
.zx-stagger.is-visible > *:nth-child(1) { transition-delay: .05s; opacity: 1; transform: none; }
.zx-stagger.is-visible > *:nth-child(2) { transition-delay: .15s; opacity: 1; transform: none; }
.zx-stagger.is-visible > *:nth-child(3) { transition-delay: .25s; opacity: 1; transform: none; }
.zx-stagger.is-visible > *:nth-child(4) { transition-delay: .35s; opacity: 1; transform: none; }
.zx-stagger.is-visible > *:nth-child(5) { transition-delay: .45s; opacity: 1; transform: none; }
.zx-stagger.is-visible > *:nth-child(6) { transition-delay: .55s; opacity: 1; transform: none; }

/* SVG line draw (charts) — add .zx-draw to a <path> */
.zx-draw {
  stroke-dasharray: 2000;
  stroke-dashoffset: 2000;
  animation: zx-draw 2.2s var(--zx-ease) forwards .3s;
}
.zx-draw-delay-1 { animation-delay: .6s; }
.zx-draw-delay-2 { animation-delay: .9s; }
@keyframes zx-draw { to { stroke-dashoffset: 0; } }

/* Progress bar fill — wrap inside .zx-reveal and set --w: 0..1 */
.zx-bar-fill {
  transform-origin: left;
  transform: scaleX(0);
  transition: transform 1.4s var(--zx-ease);
}
.zx-reveal.is-visible .zx-bar-fill { transform: scaleX(var(--w, 1)); }

/* ---------- 10. TYPOGRAPHY UTILITIES ---------- */
.zx-type-display {
  font-family: var(--zx-font-sans);
  font-size: clamp(2.25rem, 4vw, 3.75rem);
  font-weight: 600;
  letter-spacing: -0.025em;
  line-height: 1;
}
.zx-type-metric {
  font-feature-settings: "tnum", "lnum";
  letter-spacing: -0.02em;
  font-weight: 600;
}
.zx-text-muted { color: var(--zx-muted); }

/* ---------- 11. BARRA DI SCORRIMENTO ---------- */
/* Ricetta UNICA e GLOBALE: grigia, senza le frecce agli estremi.

   ⚠️⚠️ LA TRAPPOLA, verificata a schermo il 2026-08-24: se si impostano `scrollbar-width`
   o `scrollbar-color` su un elemento, Chromium SMETTE di applicargli i
   `::-webkit-scrollbar-*` e disegna la barra nativa di Windows — che ha le frecce, e prende
   il colore da `scrollbar-color`. Le due proprieta' standard, messe per Firefox,
   disattivavano quindi proprio la regola che toglie le frecce, e schiarivano il pollice.
   Per questo stanno DENTRO un blocco che vale solo dove i `::-webkit-scrollbar-*` non
   esistono, cioe' Firefox. Non tirarle fuori di li'.

   Si applica a TUTTO (`*`) e non a una classe, di proposito: su 227 contenitori che
   scorrono nel progetto, circa 125 non portavano alcuna classe e mostravano la barra di
   sistema. `.zx-scroll` e `.custom-scrollbar` restano validi ma non servono piu' a niente.

   ⚠️ `.no-scrollbar` continua a funzionare e la barra resta nascosta dov'e' voluto: un
   selettore di classe batte `*` per specificita', a prescindere dall'ordine dei fogli. */

*::-webkit-scrollbar { width: 10px; height: 10px; }

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

/* Grigio pieno e leggibile. ⚠️ NON `--zx-stroke` (#E8E8ED): e' il colore dei bordi, su fondo
   bianco quasi non si vede e il pollice sembrava spento. */
*::-webkit-scrollbar-thumb {
  background: #A1A1A6;
  border-radius: 10px;
  border: 2px solid transparent;
  background-clip: padding-box;
}
*::-webkit-scrollbar-thumb:hover {
  background: #8E8E93;
  background-clip: padding-box;
}

/* Le due frecce agli estremi. Spente in tutte le forme: il solo
   `::-webkit-scrollbar-button` non basta ovunque, perche' alcune versioni disegnano
   separatamente l'inizio e la fine di ciascuna direzione. */
*::-webkit-scrollbar-button,
*::-webkit-scrollbar-button:start:decrement,
*::-webkit-scrollbar-button:end:increment,
*::-webkit-scrollbar-button:start:increment,
*::-webkit-scrollbar-button:end:decrement {
  display: none;
  width: 0;
  height: 0;
}

/* L'angolo in basso a destra dove le due barre si incontrano. */
*::-webkit-scrollbar-corner { background: transparent; }

/* Firefox soltanto: non conosce i `::-webkit-scrollbar-*`, quindi senza queste due righe
   resterebbe con la barra di sistema. Le frecce li' non esistono di suo. */
@supports not selector(::-webkit-scrollbar) {
  * {
    scrollbar-width: thin;
    scrollbar-color: #A1A1A6 transparent;
  }
}

/* ---------- 12. REDUCED MOTION ---------- */
@media (prefers-reduced-motion: reduce) {
  .zx-card,
  .zx-chip,
  .zx-btn,
  .zx-reveal,
  .zx-stagger > *,
  .zx-bar-fill,
  .zx-draw {
    transition: none !important;
    animation: none !important;
    transform: none !important;
    opacity: 1 !important;
    stroke-dashoffset: 0 !important;
  }
  /* Tutorial pulse: spegniamo il pulsare ma teniamo l'outline statico cosi' l'utente
     vede comunque dove cliccare. */
  .zx-tutorial-pulse {
    animation: none !important;
    box-shadow: 0 0 0 4px #FFB800, 0 0 16px 2px rgba(255, 184, 0, 0.5) !important;
  }
}

/* ---------- 13. TUTORIAL ONBOARDING ---------- */
/* .zx-tutorial-pulse: bordo giallo pulsante intorno all'elemento target del tutorial.
   Applicato via JS (SpotlightPulse) sull'elemento corrispondente a [data-tour="<key>"]
   della task corrente. Colore warning #FFB800 per attirare lo sguardo (piu' visibile del
   brand blu, che si confonde con bottoni gia' presenti nella pagina). Solo box-shadow
   = GPU-friendly, niente reflow. L'animazione pulsa per tutta la durata (max 15s, vedi
   SpotlightManager PULSE_AUTO_REMOVE_MS) o finche' l'utente clicca l'elemento. */
.zx-tutorial-pulse {
  position: relative;
  z-index: 1; /* poco sopra il flow normale, ma sotto modal (1000) */
  border-radius: var(--zx-radius-md, 12px);
  animation: zxTutorialPulse 1.6s cubic-bezier(0.4, 0, 0.2, 1) infinite;
}
@keyframes zxTutorialPulse {
  0%, 100% {
    /* Glow esterno + outline solid giallo: il bordo e' sempre visibile, il glow respira. */
    box-shadow:
      0 0 0 0 rgba(255, 184, 0, 0.7),
      0 0 0 4px #FFB800,
      0 0 16px 2px rgba(255, 184, 0, 0.4);
  }
  50% {
    /* Glow espande verso fuori fino a ~16px diventando trasparente: effetto "ping" radar. */
    box-shadow:
      0 0 0 16px rgba(255, 184, 0, 0),
      0 0 0 4px #FFB800,
      0 0 24px 4px rgba(255, 184, 0, 0.6);
  }
}

/* .zx-fab-tutorial: positioning del FAB "Riapri tutorial".
   Mobile (< 768px): bottom-right, sopra la MobileQuickActionBar (110px + safe-area iOS).
   Desktop (>= 768px): top-right, appena sotto l'Header (~80px dal top).
   Non collide con AssistantFab (desktop bottom-center) ne con NotificationCenter (top-right
   nell'Header, ma il FAB sta SOTTO l'Header quindi non sovrappone). */
.zx-fab-tutorial {
  position: fixed;
  bottom: calc(env(safe-area-inset-bottom, 0px) + 110px);
  right: 16px;
  z-index: 9000;
}
@media (min-width: 768px) {
  .zx-fab-tutorial {
    top: 80px;
    bottom: auto;
    right: 24px;
  }
}

/* ---------- FAB Home mobile — alone dorato pulsante ----------
   Il FAB Home (giallo-oro) della MobileQuickActionBar emette un alone dorato che
   si espande e svanisce in loop, per attirare l'occhio sul tasto di navigazione.
   I primi due layer di box-shadow (anello charcoal + drop shadow) restano fissi;
   solo il terzo layer (alone oro) pulsa. L'animazione sovrascrive il boxShadow inline. */
.zx-fab-home-pulse {
  animation: zx-fab-gold-pulse 1800ms ease-out infinite;
}
@keyframes zx-fab-gold-pulse {
  0% {
    box-shadow:
      0 0 0 4px var(--zx-ink),
      0 8px 22px -4px rgba(11, 11, 15, 0.45),
      0 0 0 0 rgba(244, 196, 48, 0.6);
  }
  70% {
    box-shadow:
      0 0 0 4px var(--zx-ink),
      0 8px 22px -4px rgba(11, 11, 15, 0.45),
      0 0 0 12px rgba(244, 196, 48, 0);
  }
  100% {
    box-shadow:
      0 0 0 4px var(--zx-ink),
      0 8px 22px -4px rgba(11, 11, 15, 0.45),
      0 0 0 0 rgba(244, 196, 48, 0);
  }
}
@media (prefers-reduced-motion: reduce) {
  .zx-fab-home-pulse {
    animation: none;
  }
}

/* =========================================================================
   CHAT DELL'ASSISTENTE — entrata e uscita
   Una sola animazione per TUTTE le chat dell'assistente: quella sul globo e il
   pannello delle altre pagine. Prima ognuna aveva la sua (il globo scivolava da
   destra, il pannello faceva un salto in scala sul computer e saliva dal basso
   sul telefono) e soprattutto NESSUNA aveva l'uscita: entravano con garbo e
   sparivano di scatto.
   L'uscita e' l'entrata riletta al contrario, cosi' aprire e chiudere sono lo
   stesso gesto nei due versi. La durata combacia con DURATA_USCITA_MS
   dell'hook useChiusuraAnimata: cambiando una, cambiare l'altra.
   ========================================================================= */
.zx-chat-anim {
  animation: zx-chat-in 280ms cubic-bezier(0.22, 1, 0.36, 1);
}
/* `forwards` tiene il pannello all'ultimo fotogramma finche' non viene tolto
   davvero: senza, riapparirebbe intero per un istante prima di sparire. */
.zx-chat-anim[data-uscita='true'] {
  animation: zx-chat-out 220ms cubic-bezier(0.22, 1, 0.36, 1) forwards;
  pointer-events: none;
}
@keyframes zx-chat-in {
  from {
    opacity: 0;
    transform: translateX(18px) scale(0.98);
  }
  to {
    opacity: 1;
    transform: none;
  }
}
@keyframes zx-chat-out {
  from {
    opacity: 1;
    transform: none;
  }
  to {
    opacity: 0;
    transform: translateX(18px) scale(0.98);
  }
}
@media (prefers-reduced-motion: reduce) {
  .zx-chat-anim,
  .zx-chat-anim[data-uscita='true'] {
    animation: none;
  }
}
