﻿/* theme.css — design system "Industry" del CRM OTG, condiviso da tutte le pagine di Buyweb10.
   Token (superfici, accento per deployment, tipografia) + fondamentali (form, bottoni, modali,
   tabelle, badge, card, KPI, toast). I componenti aggiungono solo il proprio layout. */
:root {
  /* superfici e linee */
  --bg:#f2f2f3;--bg2:#ffffff;--bg3:#f5f5f8;--bg4:#e7e7ea;
  --border:#e7e7ea;--border2:#d4d4d7;
  --text:#1d1f20;--text2:#5d5d60;--text3:#98989b;
  /* Accento per deployment (App.AccentColor): dal colore del cliente si prende SOLO la
     tonalità, più un fattore di saturazione già clampato dal server. La lightness resta
     quella del design system, identica in entrambi i temi — è ciò che garantisce il
     contrasto del testo bianco sui pieni, e un hex arbitrario del cliente non lo
     garantirebbe. Chiave vuota o non valida ⇒ questi due default, cioè l'accento di serie.
     Li sovrascrive useBranding.js su <html> al boot. */
  --accent-h:248;--accent-c:1;

  --accent:oklch(0.586 calc(0.073 * var(--accent-c)) var(--accent-h));
  --accent2:oklch(0.481 calc(0.063 * var(--accent-c)) var(--accent-h));
  --accent-glow:color-mix(in srgb, var(--accent) 12%, transparent);

  /* alias con il vocabolario dell'handoff */
  --surface:var(--bg2);--line:var(--border);

  /* rampe tonali (OKLCH, stessa scala di lightness per ogni ruolo) */
  --neutral-100:#f5f5f8;--neutral-200:#e7e7ea;--neutral-300:#d4d4d7;
  --neutral-400:#b7b7ba;--neutral-500:#98989b;--neutral-600:#7a7a7d;
  --neutral-700:#5d5d60;--neutral-800:#424244;--neutral-900:#2b2b2d;
  /* stessa rampa di prima, riscritta in OKLCH: la lightness e la chroma sono quelle dei
     nove hex originali, la tonalità è una sola (i valori storici oscillavano fra 246 e 251,
     una deriva involontaria) ed è quella configurabile */
  --accent-100:oklch(0.970 calc(0.015 * var(--accent-c)) var(--accent-h));
  --accent-200:oklch(0.931 calc(0.035 * var(--accent-c)) var(--accent-h));
  --accent-300:oklch(0.871 calc(0.063 * var(--accent-c)) var(--accent-h));
  --accent-400:oklch(0.780 calc(0.071 * var(--accent-c)) var(--accent-h));
  --accent-500:oklch(0.681 calc(0.073 * var(--accent-c)) var(--accent-h));
  --accent-600:oklch(0.580 calc(0.071 * var(--accent-c)) var(--accent-h));
  --accent-700:oklch(0.481 calc(0.063 * var(--accent-c)) var(--accent-h));
  --accent-800:oklch(0.381 calc(0.052 * var(--accent-c)) var(--accent-h));
  --accent-900:oklch(0.291 calc(0.036 * var(--accent-c)) var(--accent-h));

  /* semantiche: non esistono in Industry, derivate sulla stessa lightness
     percepita della scala di fase perché nessuno stato "urli" più degli altri */
  --green:oklch(0.50 0.12 152);--green-bg:oklch(0.94 0.04 152);
  /* Tinte piene dei riquadri KPI: sono le uniche superfici colorate con testo bianco sopra, quindi
     hanno un valore proprio e NON seguono il tema — un verde chiaro come quello del tema scuro,
     sotto testo bianco, non si legge. Stessa lightness percepita per tutte e quattro: il colore
     dice quale conteggio e', non quanto e' grave. */
  --kpi-blu:oklch(0.55 0.13 238); --kpi-verde:oklch(0.55 0.12 152);
  --kpi-ambra:oklch(0.62 0.14 74); --kpi-rosso:oklch(0.55 0.16 25);
  --amber:oklch(0.55 0.13 74); --amber-bg:oklch(0.94 0.05 74);
  --red:oklch(0.52 0.16 25);   --red-bg:oklch(0.94 0.05 25);
  --blue-bg:oklch(0.94 0.03 250);--gray-bg:oklch(0.95 0 0);

  /* scala di fase dell'opportunità — DEFINITA, non ancora applicata ai badge:
     l'aggancio ai dati reali è lavoro funzionale (vedi spec §6).
     --fN fondo · --fNt testo sul fondo · --fNs pieno */
  --f1:oklch(0.90 0.055 278);--f1t:oklch(0.42 0.13 278);--f1s:oklch(0.56 0.14 278);
  --f2:oklch(0.90 0.055 238);--f2t:oklch(0.40 0.12 238);--f2s:oklch(0.55 0.13 238);
  --f3:oklch(0.90 0.058 196);--f3t:oklch(0.40 0.10 196);--f3s:oklch(0.55 0.11 196);
  --f4:oklch(0.90 0.080 74); --f4t:oklch(0.43 0.12 74); --f4s:oklch(0.62 0.14 74);
  --f5:oklch(0.90 0.070 152);--f5t:oklch(0.40 0.11 152);--f5s:oklch(0.55 0.12 152);
  /* Fuori scala: colonne che NON sono una fase dell'avanzamento (persa, sospesa). Due grigi
     medi identici nei due temi — il fondo cambia, il testo sopra resta bianco, e un grigio
     preso dal ramp neutro si ribalterebbe di lightness passando al tema scuro. */
  --fneutra:#5f6266;--fneutra2:#7c7f85;

  /* velo delle modali e dei pannelli: token proprio e non una rampa, perché le
     rampe si ribaltano nel tema scuro mentre il velo resta sempre scuro */
  --overlay:color-mix(in srgb, #2b2b2d 50%, transparent);

  /* forma */
  --radius:10px;--radius-lg:12px;--radius-sm:8px;--radius-pill:999px;
  --shadow-sm:0 1px 2px color-mix(in srgb, #2b2b2d 14%, transparent);
  --shadow-md:0 3px 10px color-mix(in srgb, #2b2b2d 16%, transparent);
  --shadow-lg:0 12px 32px color-mix(in srgb, #2b2b2d 22%, transparent);

  /* spazio (scala Industry) */
  --space-1:3.4px;--space-2:6.8px;--space-3:10.2px;
  --space-4:13.6px;--space-6:20.4px;--space-8:27.2px;

  /* altezze dei controlli: 30px nelle righe dense, 40px nei form */
  --h-control:30px;--h-field:40px;

  /* tipografia */
  --font:'Barlow',system-ui,sans-serif;
  --font-body:var(--font);
  --font-heading:'Barlow Condensed',system-ui,sans-serif;
  --font-mono:'DM Mono',monospace;

  --sidebar-w:220px;--header-h:56px;
}
[data-theme="dark"] {
  --bg:#1c1e21;--bg2:#24272a;--bg3:#2d3033;--bg4:#383b40;
  --border:rgba(255,255,255,0.10);--border2:rgba(255,255,255,0.18);
  --text:#ecedef;--text2:#b2b4b8;--text3:#86888d;
  /* --accent-h / --accent-c non si ridichiarano: sono per deployment, non per tema, e
     :root li ha già messi sullo stesso <html>. Qui cambia solo la lightness (accento
     schiarito sul fondo scuro, regola della spec). */
  --accent:oklch(0.746 calc(0.055 * var(--accent-c)) var(--accent-h));
  --accent2:oklch(0.827 calc(0.040 * var(--accent-c)) var(--accent-h));
  --accent-glow:color-mix(in srgb, var(--accent) 16%, transparent);

  /* le rampe si ribaltano: il "100" resta il capo tenue, ma sul fondo scuro
     tenue significa scuro — così tag e badge restano leggibili senza cambiare
     classe nei componenti */
  --neutral-100:#2d3033;--neutral-200:#383b40;--neutral-300:#4a4d52;
  --neutral-400:#63666b;--neutral-500:#86888d;--neutral-600:#a2a4a8;
  --neutral-700:#c2c4c7;--neutral-800:#dcdde0;--neutral-900:#f1f2f3;
  --accent-100:oklch(0.315 calc(0.028 * var(--accent-c)) var(--accent-h));
  --accent-200:oklch(0.378 calc(0.042 * var(--accent-c)) var(--accent-h));
  --accent-300:oklch(0.448 calc(0.051 * var(--accent-c)) var(--accent-h));
  --accent-400:oklch(0.528 calc(0.060 * var(--accent-c)) var(--accent-h));
  --accent-500:oklch(0.614 calc(0.064 * var(--accent-c)) var(--accent-h));
  --accent-600:oklch(0.693 calc(0.063 * var(--accent-c)) var(--accent-h));
  --accent-700:oklch(0.746 calc(0.055 * var(--accent-c)) var(--accent-h));
  --accent-800:oklch(0.827 calc(0.040 * var(--accent-c)) var(--accent-h));
  --accent-900:oklch(0.913 calc(0.024 * var(--accent-c)) var(--accent-h));

  --green:oklch(0.72 0.13 152);--green-bg:oklch(0.32 0.06 152);
  --amber:oklch(0.78 0.13 74); --amber-bg:oklch(0.32 0.06 74);
  --red:oklch(0.70 0.16 25);   --red-bg:oklch(0.32 0.07 25);
  --blue-bg:oklch(0.32 0.05 250);--gray-bg:rgba(255,255,255,0.06);

  --f1:oklch(0.32 0.055 278);--f1t:oklch(0.85 0.07 278);--f1s:oklch(0.60 0.14 278);
  --f2:oklch(0.32 0.055 238);--f2t:oklch(0.85 0.07 238);--f2s:oklch(0.60 0.13 238);
  --f3:oklch(0.32 0.058 196);--f3t:oklch(0.85 0.07 196);--f3s:oklch(0.60 0.11 196);
  --f4:oklch(0.32 0.080 74); --f4t:oklch(0.85 0.09 74); --f4s:oklch(0.66 0.14 74);
  --f5:oklch(0.32 0.070 152);--f5t:oklch(0.85 0.08 152);--f5s:oklch(0.60 0.12 152);
  /* Fuori scala: colonne che NON sono una fase dell'avanzamento (persa, sospesa). Due grigi
     medi identici nei due temi — il fondo cambia, il testo sopra resta bianco, e un grigio
     preso dal ramp neutro si ribalterebbe di lightness passando al tema scuro. */
  --fneutra:#5f6266;--fneutra2:#7c7f85;

  --overlay:rgba(0,0,0,0.62);

  --shadow-sm:0 1px 2px rgba(0,0,0,0.45);
  --shadow-md:0 3px 10px rgba(0,0,0,0.50);
  --shadow-lg:0 12px 32px rgba(0,0,0,0.60);
}
*{box-sizing:border-box;margin:0;padding:0;}
html,body,#app{height:100%;height:100dvh;overflow:hidden;}
body{font-family:var(--font);background:var(--bg);color:var(--text);font-size:14px;line-height:1.5;}

/* ── Loading splash ────────────────────────────────────────────────────── */
#app-loading {
  position:fixed;inset:0;background:var(--bg);
  display:flex;flex-direction:column;align-items:center;justify-content:center;gap:16px;
  z-index:9999;
}
#app-loading .logo-mark {
  width:48px;height:48px;border-radius:var(--radius-lg);background:var(--accent);
  display:flex;align-items:center;justify-content:center;
  font-family:var(--font-heading);font-size:24px;font-weight:600;color:#fff;
}
/* Con un logo square il quadrato colorato sparisce: resta la sola immagine */
#app-loading .logo-mark.has-logo { background:none;border-radius:0; }
#app-loading .logo-mark img { width:48px;height:48px;object-fit:contain; }
#app-loading .loading-text { font-size:13px;color:var(--text3); }
#app-loading .loading-bar {
  width:160px;height:3px;background:var(--bg3);border-radius:999px;overflow:hidden;
}
#app-loading .loading-bar-inner {
  height:100%;background:var(--accent);border-radius:999px;
  animation:loadbar 1.2s ease-in-out infinite;
}
@keyframes loadbar {
  0%{width:0%;margin-left:0%}
  50%{width:60%;margin-left:20%}
  100%{width:0%;margin-left:100%}
}


/* ── Layout base ─────────────────────────────────────────────────────────── */
.app-root { height: 100vh; height: 100dvh; overflow: hidden; display: flex; flex-direction: column; }

/* ── Fondamentali del design system ──────────────────────────────────────────
   Le tre regole trasversali dell'handoff Industry: titoli e numeri in
   Barlow Condensed, cifre tabulari ovunque compaia un valore (le colonne di
   importi devono allinearsi), anello di focus in accento — mai quello di
   default del browser, perché le liste dense si usano a tastiera. */
h1, h2, h3, h4, h5, h6 {
  font-family: var(--font-heading); font-weight: 600; letter-spacing: -.01em;
}
.kpi-val, .kpi-delta, td, th, .detail-value, .badge, input, .form-input, .form-select {
  font-variant-numeric: tabular-nums;
}
:focus-visible {
  outline: 2px solid var(--accent); outline-offset: 2px;
}
/* Il disabilitato si legge dall'opacità, non da un grigio dedicato. */
:disabled { opacity: .45; }

/* ── Login ───────────────────────────────────────────────────────────────── */
.login-wrap {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 20px;
  align-items: center;
  justify-content: center;
  background: var(--bg);
  padding: 24px;
}
.login-card {
  background: var(--bg2);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-md);
  padding: 32px;
  width: 100%;
  max-width: 360px;
  display: flex;
  flex-direction: column;
  gap: 16px;
}
.login-logo { display: flex; align-items: center; gap: 14px; margin-bottom: 8px; }
/* Col logo il lockup è la sola immagine: centrata. Il fallback testuale resta allineato a sinistra. */
.login-logo.has-logo { justify-content: center; }
.login-logo-img { height: 44px; max-width: 100%; object-fit: contain; }
.login-footer {
  display: flex; align-items: center; gap: 8px;
  font-size: 11px; color: var(--text3); opacity: .8;
}
.login-footer a { display: flex; transition: opacity .15s; }
.login-footer a:hover { opacity: .7; }
.login-footer img { height: 20px; width: auto; object-fit: contain; }
.login-version {
  font-family: var(--font-mono); font-size: 10px; color: var(--text3); opacity: .7;
}
.logo-mark {
  width: 40px; height: 40px; border-radius: var(--radius);
  background: var(--accent); display: flex;
  align-items: center; justify-content: center;
  font-family: var(--font-heading); font-size: 20px; font-weight: 600; color: #fff;
}
.logo-name { font-family: var(--font-heading); font-size: 19px; font-weight: 600; }
[data-theme="dark"] .logo-mark { color: var(--bg); }
/* Marchio Buyweb 10 (branding/bw10.png): il quadrato blu è già nell'immagine. */
.logo-mark.logo-bw { background: none; border-radius: 0; object-fit: contain; }
#app-loading .logo-mark.logo-bw { background: none; border-radius: 0; }
.logo-sub  { font-size: 12px; color: var(--text3); margin-top: 2px; }
.login-error {
  background: var(--red-bg); color: var(--red);
  padding: 10px 14px; border-radius: var(--radius);
  font-size: 13px;
}
.login-warn {
  background: var(--amber-bg, var(--bg3)); color: var(--text);
  border: 1px solid var(--amber, var(--border2)); border-left-width: 4px;
  padding: 10px 14px; border-radius: var(--radius);
  font-size: 12px; line-height: 1.45;
}
.login-warn p { margin: 6px 0 0; }
.login-warn ul { margin: 6px 0 0; padding-left: 18px; }
.login-warn code { font-family: var(--font-mono); font-size: 11px; }

/* ── Form elements ───────────────────────────────────────────────────────── */
.form-group { display: flex; flex-direction: column; gap: 6px; }
.form-label { font-size: 12px; font-weight: 500; color: var(--text2); }
.form-input, .form-select {
  background: var(--bg2); border: 1px solid var(--border2);
  border-radius: var(--radius-sm); padding: 8px 12px; min-height: var(--h-field);
  color: var(--text); font-size: 13px; font-family: var(--font);
  outline: none; width: 100%; transition: border-color .15s;
}
.form-input:hover:not(:disabled), .form-select:hover:not(:disabled) { border-color: var(--neutral-400); }
.form-input:focus, .form-select:focus { border-color: var(--accent); }
.form-row { display: flex; gap: 12px; }
.form-row .form-group { flex: 1; }
.form-hint { font-size: 12px; color: var(--text3); margin-top: 4px; }
.check-row {
  display: flex; align-items: center; gap: 8px;
  padding: 8px 4px; font-size: 13px; cursor: pointer; border-bottom: 1px solid var(--border);
}
.check-row:last-of-type { border-bottom: none; }

/* ── Tendine di menù ─────────────────────────────────────────────────────────
   Vestono due componenti — RowMenu (tendina ancorata a un bottone di riga) e
   MenuContestuale (tasto destro / long-press, ancorato a un punto) — e stanno
   qui per la stessa ragione delle modali, che è anche il modo in cui il
   problema si è presentato: erano nello <style> di RowMenu.vue, e siccome gli
   SFC sono caricati pigri, aprendo il menù contestuale in un pannello dove
   nessun RowMenu era montato il CSS non esisteva affatto. Il pannello finiva in
   <body> senza position:fixed, cioè un blocco larghezza schermo in fondo alla
   pagina. Un componente non può dipendere dal caso che un ALTRO componente sia
   stato caricato: le classi condivise da due componenti stanno nel foglio
   globale, e App.vue è l'unico sempre montato.

   position:fixed + Teleport su body: i menù nascono dentro .table-wrap, che
   dichiara overflow-x:auto, e per specifica CSS un overflow-y:visible in
   presenza di un overflow-x non-visible computa ad auto — quindi .table-wrap
   ritaglia, e nessuno z-index fa uscire un figlio da un antenato che ritaglia.
   z-index 250: sopra il pannello di dettaglio (201), sotto le modali (300). */
.row-menu { position: relative; display: inline-block; }
.row-menu-dd {
  position: fixed;
  background: var(--bg2); border: 1px solid var(--border2);
  border-radius: var(--radius-lg); min-width: 190px;
  box-shadow: 0 8px 32px rgba(0,0,0,.3); z-index: 250; overflow: hidden;
  text-align: left;
}
.row-menu-item {
  display: flex; align-items: center; gap: 8px;
  padding: 10px 14px; font-size: 13px; cursor: pointer; transition: background .15s;
}
.row-menu-item:hover  { background: var(--bg3); }
.row-menu-item.danger { color: var(--red); }
.row-menu-sep         { height: 1px; background: var(--border); margin: 2px 0; }

/* Il menù contestuale si ancora a un punto, quindi si posiziona con left e non
   col right di RowMenu. z-index 270 e non 250: si apre su righe che possono
   essere avvolte da un InfoTooltip (260), e col valore di RowMenu il tooltip
   della riga premuta coprirebbe il menù che quella riga ha appena aperto.
   Resta sotto le modali. */
.menu-contestuale { left: 0; right: auto; z-index: 270; }

/* Va su ogni riga che porta il menù contestuale (`v-on="menuRiga(…)"`), ed è la differenza fra una
   funzione e un fastidio su tablet: senza la prima riga iOS apre il proprio menù di sistema sul
   testo, con la lente d'ingrandimento, e il nostro non si vede mai; senza la seconda la pressione
   prolungata seleziona il testo della riga e l'utente si ritrova un blocco evidenziato. Sta sulla
   riga e non su un antenato perché il resto della pagina è testo che si deve poter selezionare e
   copiare — un numero di telefono, una mail, un codice articolo.

   Attenzione se un domani la colonna identificativa diventa un `<a href="#pagina?id=…">` per avere
   il menù nativo del browser: `-webkit-touch-callout:none` spegne anche il long-press nativo del
   link, quindi questa classe deve restare sulla riga e non finire mai sull'ancora. */
.riga-menu { -webkit-touch-callout: none; user-select: none; }

/* ── Modali ──────────────────────────────────────────────────────────────────
   Vivono qui e non nella pagina che per prima le ha usate: quasi ogni vista ha
   una modale e con gli SFC caricati pigri "definita in Dashboard.vue" significa
   "invisibile finché non passi dalla dashboard" — la modale finiva in <body> ma
   senza position:fixed, quindi fuori schermo. */
.modal-overlay {
  position: fixed; inset: 0;
  background: var(--overlay);
  z-index: 300; display: flex; align-items: center; justify-content: center;
  padding: 20px;
}
.modal-card {
  background: var(--bg2); border: 1px solid var(--border);
  border-radius: var(--radius-lg); width: 100%; max-width: 560px;
  max-height: 90vh; display: flex; flex-direction: column;
  box-shadow: var(--shadow-lg);
}
.modal-header {
  display: flex; align-items: center; justify-content: space-between;
  padding: 16px 20px; border-bottom: 1px solid var(--border); flex-shrink: 0;
}
.modal-title { font-size: 15px; font-weight: 600; }
.modal-body  { flex: 1; overflow-y: auto; padding: 20px; }

/* ── Buttons ─────────────────────────────────────────────────────────────── */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  padding: 7px 14px; min-height: var(--h-control); border-radius: var(--radius-sm);
  font-family: var(--font-heading); font-size: 14px; font-weight: 600;
  letter-spacing: .01em; line-height: 1.2; cursor: pointer;
  transition: background .15s, color .15s, border-color .15s; border: 1px solid transparent;
}
.btn:disabled { opacity: .45; cursor: not-allowed; }
.btn-primary  { background: var(--accent); color: #fff; border-color: var(--accent); }
.btn-primary:hover:not(:disabled) { background: var(--accent-700); border-color: var(--accent-700); }
/* Nel tema scuro l'accento è schiarito per il contrasto sul fondo: un pieno così chiaro
   vuole testo scuro, non bianco. */
[data-theme="dark"] .btn-primary { color: var(--bg); }
[data-theme="dark"] .btn-primary:hover:not(:disabled) { background: var(--accent2); border-color: var(--accent2); }
.btn-ghost    { background: var(--bg2); color: var(--text2); border-color: var(--border); }
.btn-ghost:hover:not(:disabled)  { background: var(--bg3); color: var(--text); }
.btn-sm       { padding: 4px 10px; min-height: 26px; font-size: 13px; }
.btn-danger   { background: var(--red-bg); color: var(--red); }
/* Le due varianti servono alle azioni distruttive che devono *sembrare* tali a colpo d'occhio
   (svuotamento cache, sync completo): pieno per la più invasiva, contornato per l'altra.
   .btn azzera il bordo, quindi la variante contornata lo ridichiara. */
.btn-danger-solid { background: var(--red); color: #fff; }
.btn-danger-solid:hover:not(:disabled) { filter: brightness(1.1); }
.btn-danger-outline { background: transparent; color: var(--red); border: 1px solid var(--red); }
.btn-danger-outline:hover:not(:disabled) { background: var(--red-bg); }

/* Dialogo di conferma: dissolvenza breve. Niente scorrimento laterale come i toast — la modale
   prende il centro dello schermo e un'entrata da un lato la fa leggere come una notifica. */
.confirm-enter-active, .confirm-leave-active { transition: opacity .12s ease; }
.confirm-enter-from, .confirm-leave-to { opacity: 0; }

/* ── Toast ───────────────────────────────────────────────────────────────── */
.toast-container {
  position: fixed; bottom: 24px; right: 24px;
  display: flex; flex-direction: column; gap: 8px;
  z-index: 9000; pointer-events: none;
}
.toast {
  padding: 12px 18px; border-radius: var(--radius);
  font-size: 13px; font-weight: 500;
  background: var(--bg2); border: 1px solid var(--border);
  color: var(--text); cursor: pointer; pointer-events: auto;
  box-shadow: var(--shadow-md);
}
.toast-success { border-left: 3px solid var(--green); }
.toast-error   { border-left: 3px solid var(--red);   }
.toast-info    { border-left: 3px solid var(--accent); }
.toast-warning { border-left: 3px solid var(--amber);  }
.toast-enter-active, .toast-leave-active { transition: all .25s ease; }
.toast-enter-from { opacity:0; transform: translateX(40px); }
.toast-leave-to   { opacity:0; transform: translateX(40px); }

/* ── Page loading ────────────────────────────────────────────────────────── */
.page-loading {
  flex: 1; display: flex; align-items: center; justify-content: center;
  height: 100%;
}
.loading-spinner {
  width: 28px; height: 28px; border: 3px solid var(--border2);
  border-top-color: var(--accent); border-radius: 50%;
  animation: spin .7s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* ── KPI Cards ───────────────────────────────────────────────────────────── */
.kpi-row { display: grid; grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); gap: 12px; margin-bottom: 16px; }
.kpi-card {
  background: var(--bg2); border: 1px solid var(--border);
  border-radius: var(--radius); padding: 16px; box-shadow: var(--shadow-sm);
}
.kpi-val  {
  font-family: var(--font-heading); font-size: 30px; font-weight: 600;
  line-height: 1.1; margin-bottom: 4px;
}
.kpi-label{ font-size: 11px; color: var(--text3); text-transform: uppercase; letter-spacing: .06em; }
/* Riquadro cliccabile: è un <button>, non un div con @click — così ci si arriva col tab e lo
   screen reader lo annuncia come azione. Da qui in giù solo il ripristino dell'aspetto che il
   browser toglie ai bottoni, più lo stato "nulla da vedere" quando il conteggio è zero. */
.kpi-card-link {
  font: inherit; text-align: left; width: 100%; cursor: pointer;
  transition: border-color .12s, background .12s;
}
.kpi-card-link:hover:not(:disabled) { border-color: var(--accent); background: var(--bg3, var(--bg2)); }
.kpi-card-link:disabled { cursor: default; opacity: .55; }
/* Nel pannello di dettaglio lo spazio è la metà: due colonne fisse e numeri più piccoli, altrimenti
   cinque riquadri da 160px diventano cinque righe. */
/* Variante compatta dei riquadri: viveva nel pannello di dettaglio largo 400px, dove due colonne
   fisse erano l'unica disposizione possibile. Ora la usano le schede a schermo intero, e due colonne
   fisse lasciavano cinque riquadri disposti 2+2+1, con l'ultimo largo mezza pagina. */
.kpi-row-compatta { grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 8px; margin-bottom: 16px; }
.kpi-row-compatta .kpi-card { padding: 10px 12px; }
.kpi-row-compatta .kpi-val  { font-size: 20px; margin-bottom: 2px; }
.kpi-row-compatta .kpi-label{ font-size: 10px; }
.kpi-delta{ font-size: 11px; margin-top: 4px; }
/* Riquadro a tinta piena: la tinta arriva da --kpi-fill, impostata sul singolo riquadro. Il
   committente ha confermato piatto e non a gradiente — non reintrodurre gradienti. */
.kpi-card-solid {
  background: var(--kpi-fill, var(--kpi-blu)); border-color: transparent; color: #fff;
}
.kpi-card-solid .kpi-val   { color: #fff; }
.kpi-card-solid .kpi-label { color: #fff; opacity: .88; }

/* Riquadro KPI che sta filtrando la lista: una spunta nell'angolo. La tinta del riquadro non puo'
   dirlo — dice QUALE conteggio e', e deve restare la stessa acceso o spento — e un anello intorno
   a una card a tinta piena diventa una seconda cornice. Il dischetto e' sempre bianco con inchiostro
   scuro: sta sopra tinte diverse (blu, rosso, verde, ambra) e in entrambi i temi.
   Vive qui e non nelle viste perche' la usano sia l'agenda sia le offerte. */
.kpi-spunta {
  position: absolute; top: 8px; right: 8px;
  width: 18px; height: 18px; border-radius: 50%;
  display: grid; place-items: center;
  background: #fff; color: #1d1f20;
}

/* ── Controllo segmentato ─────────────────────────────────────────────────
   Un gruppo di radio che si legge come un solo comando: lo usano le viste dell'agenda
   (Lista/Settimana/Mese) e la granularita' del periodo. Al posto di N bottoni pill accostati,
   che a fianco di un altro gruppo di bottoni non dicono piu' quali stanno insieme. */
.seg {
  display: inline-flex; background: var(--bg2);
  border: 1px solid var(--border); border-radius: var(--radius-sm); overflow: hidden;
}
.seg-opt {
  display: inline-flex; align-items: center; gap: 6px; white-space: nowrap;
  padding: 0 12px; height: var(--h-control); font-size: 13px;
  color: var(--text2); cursor: pointer; user-select: none;
}
.seg-opt + .seg-opt { border-left: 1px solid var(--border); }
/* La radio vera resta nel DOM — e' lei che porta tastiera e screen reader — ma non si vede. */
.seg-opt input { position: absolute; opacity: 0; width: 0; height: 0; pointer-events: none; }
.seg-opt:has(input:checked) { background: var(--accent); color: #fff; }
.seg-opt:not(:has(input:checked)):hover { background: var(--bg3); color: var(--text); }
.seg-opt:has(input:focus-visible) { outline: 2px solid var(--accent); outline-offset: -2px; }

/* ── Cards ────────────────────────────────────────────────────────────────── */
.card {
  background: var(--bg2); border: 1px solid var(--border);
  border-radius: var(--radius-lg); box-shadow: var(--shadow-sm);
}
.card-header { padding: 14px 16px; border-bottom: 1px solid var(--border); display: flex; align-items: center; justify-content: space-between; }
.card-title  { font-family: var(--font-heading); font-size: 16px; font-weight: 600; letter-spacing: .01em; }
.card-body   { padding: 16px; }

/* ── Badge ────────────────────────────────────────────────────────────────── */
.badge {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 2px 10px; border-radius: var(--radius-pill);
  font-size: 11px; font-weight: 600; letter-spacing: .02em;
}
.badge-green  { background: var(--green-bg);  color: var(--green);  }
.badge-red    { background: var(--red-bg);    color: var(--red);    }
.badge-amber  { background: var(--amber-bg);  color: var(--amber);  }
.badge-blue   { background: var(--blue-bg);   color: var(--accent); }
.badge-gray   { background: var(--gray-bg);   color: var(--text3);  }

/* ── Table ────────────────────────────────────────────────────────────────── */
.table-wrap { overflow-x: auto; }
/* Ricarica di una lista già popolata: la griglia RESTA montata (smontarla porterebbe via anche i
   filtri inline e il focus di chi sta scrivendo, vedi useResource.primoCaricamento) e segnala
   l'attesa sbiadendo. Non-interattiva finché la risposta non arriva, così un clic su una riga
   che sta per essere sostituita non apre la scheda sbagliata. */
.table-wrap.in-aggiornamento tbody { opacity: .55; pointer-events: none; }
table { width: 100%; border-collapse: collapse; font-size: 13px; }
th { padding: 8px 12px; text-align: left; font-size: 11px; font-weight: 600; color: var(--text3); text-transform: uppercase; letter-spacing: .07em; border-bottom: 1px solid var(--border); white-space: nowrap; }
td { padding: 10px 12px; border-bottom: 1px solid var(--border); }
/* L'hover di riga si dichiara appena: le righe cliccabili devono farsi riconoscere
   senza che la lista diventi a righe alternate. */
tr:hover td { background: color-mix(in srgb, var(--text) 4%, transparent); }
tr:last-child td { border-bottom: none; }

/* ── Riga di filtri inline ────────────────────────────────────────────────────
   Un controllo per colonna, dentro il <thead>, sotto la propria intestazione. Controlli a 30px
   (altezza delle righe dense) e fondo appena tinto: la riga si legge come parte dell'intestazione
   e non come la prima riga di dati. --h-field è la variabile che .form-input/.form-select usano
   per min-height, quindi ribassarla qui rimpicciolisce anche i controlli dei componenti figli
   (EntityPicker) senza selettori che ne perforino gli stili.
   Sta QUI e non in ogni vista: la riga è la stessa in tutte le liste, e sei copie scoped erano sei
   posti dove poteva divergere. Le righe di filtri non si sbiadiscono con .in-aggiornamento (è il
   <tbody> a sbiadire), così si continua a filtrare mentre la risposta arriva. */
.filtri { --h-field: 30px; background: var(--bg3); }
.filtri td { padding: 6px 8px; border-bottom: 1px solid var(--border); vertical-align: middle; }
.filtri .form-input, .filtri .form-select { padding: 4px 8px; font-size: 12px; }

/* ── Toolbar di vista ─────────────────────────────────────────────────────────
   I comandi che valgono SOLO per una vista (Colonne, Nuovo …) stanno sopra la griglia, dentro la
   pagina. Nella barra superiore resta ciò che vale per tutte: titolo, ricerca universale, utente. */
.vista-toolbar { display: flex; align-items: center; gap: 8px; margin-bottom: 12px; flex-wrap: wrap; }
.vista-toolbar-spacer { flex: 1 1 auto; }

/* ── Detail panel ─────────────────────────────────────────────────────────── */
.detail-overlay {
  position: fixed; inset: 0; background: var(--overlay);
  z-index: 200; display: none;
}
.detail-overlay.open { display: block; }
.detail-panel {
  position: fixed; top: 0; right: 0; height: 100vh;
  width: min(1240px, 100vw); background: var(--bg2);
  border-left: 1px solid var(--border);
  z-index: 201; display: flex; flex-direction: column;
  transform: translateX(100%); transition: transform .25s ease;
  overflow: hidden;
}
.detail-panel.open { transform: translateX(0); }
.detail-panel-header {
  display: flex; align-items: center; gap: 12px;
  padding: 16px; border-bottom: 1px solid var(--border);
  flex-shrink: 0;
}
.detail-panel-body { flex: 1; overflow-y: auto; padding: 16px; }
.detail-section { margin-bottom: 20px; }
.detail-section-title {
  font-size: 11px; font-weight: 600; color: var(--text3);
  text-transform: uppercase; letter-spacing: .06em; margin-bottom: 10px;
}
.detail-row { display: flex; gap: 4px; padding: 8px 0; border-bottom: 1px solid var(--border); font-size: 13px; }
.detail-label { color: var(--text3); min-width: 120px; flex-shrink: 0; }
.detail-value { color: var(--text); flex: 1; }

/* ── Dettaglio completo (pagina) ──────────────────────────────────────────── */
/* La scheda a schermo intero riusa .card / .card-header / .detail-row: la testata con il pulsante
   "‹ Indietro" è la stessa che la scheda campagna aveva già. L'unica cosa che il pannello non
   poteva permettersi era la larghezza, quindi qui si aggiungono solo le colonne. */
.dettaglio-grid {
  display: grid; gap: 16px; align-items: start;
  grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
}
/* Le sezioni dentro una colonna non hanno bisogno del margine di coda del pannello: la card che le
   contiene ha già il proprio respiro, e l'ultimo margine lascerebbe un buco in fondo. */
.dettaglio-grid .detail-section:last-child { margin-bottom: 0; }

/* Variante a DUE riquadri per riga, non "quanti ce ne stanno": `.dettaglio-grid` da sola, su uno
   schermo largo, allinea quattro riquadri in fila e ognuno diventa una colonnina di campi stretti.
   La usano le schede con riquadri densi (opportunità, attività, lead in modifica). */
.dettaglio-grid-2 { grid-template-columns: minmax(0, 1fr); }
@media (min-width: 900px) { .dettaglio-grid-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

/* Sezione resa riquadro: bordo, sfondo e spaziatura propri, così i gruppi di campi si leggono come
   blocchi distinti invece che come un elenco unico. Lo sfondo è quello della pagina, che dentro la
   card (var(--bg2)) stacca senza bisogno di un colore in più. */
.dettaglio-riquadro {
  display: flex; flex-direction: column; gap: 12px;
  background: var(--bg); border: 1px solid var(--border);
  border-radius: var(--radius-lg); padding: 14px 16px;
}
/* Il titolo dentro il riquadro spazia col gap del flex: il margine del pannello lo raddoppierebbe. */
.dettaglio-riquadro .detail-section-title { margin-bottom: 0; }

/* ── Search input ─────────────────────────────────────────────────────────── */
.search-input {
  background: var(--bg2); border: 1px solid var(--border2);
  border-radius: var(--radius-sm); padding: 6px 12px; height: var(--h-control);
  font-size: 13px; color: var(--text); font-family: var(--font);
  outline: none; width: 220px; transition: border-color .15s;
}
.search-input:focus { border-color: var(--accent); }

/* ── Mobile ───────────────────────────────────────────────────────────────── */
@media (max-width: 768px) {
  .kpi-row { grid-template-columns: 1fr 1fr; gap: 10px; }
  .search-input { width: 140px; }
  .form-row { flex-direction: column; }
  /* .hide-mobile la usano la topbar e quasi tutte le liste: sta qui perché stava
     nello style *scoped* di Agenda.vue, dove valeva solo per l'agenda — altrove
     la classe non nascondeva nulla. */
  .hide-mobile { display: none; }
}
