/* =============================================================================
   tg0 — Stili applicativi (REDESIGN MOBILE-FIRST · FASE 2)
   Si appoggiano ai token di str4tum-ds (tokens.css/components.css via CDN).
   Strategia: MOBILE-FIRST. Base = smartphone (360-414px) con navigazione a viste
   (bottom nav) e mappa quasi full-screen. Da >=900px torna la grid a 2 colonne
   (desktop secondario). Variabili nuove: --tg-* (colori squadra/tragitto,
   allineati a TEAM_COLORS in app.js) + altezze chrome.
   ============================================================================= */

/* L'attributo `hidden` deve sempre vincere su qualsiasi regola di display con
   pari specificità (.login-screen, .app-shell, .btn, [data-view-panel]...). */
[hidden] { display: none !important; }

:root {
  --tg-team-alfa:    #d4a04a;   /* ocra   */
  --tg-team-bravo:   #3ba864;   /* verde  */
  --tg-team-charlie: #d96a52;   /* terracotta */
  --tg-command:      #b08cff;   /* viola — Comando / op_lead */
  --tg-route:        #3b82f6;   /* blu — tragitto primario */
  --tg-self-ring:    #ffffff;
  --header-h:        56px;
  --tabbar-h:        58px;
  /* [MAP-THEME] filtro "tattico" (scuro/militare) sui tile raster OSM. */
  --tactical-filter: invert(1) hue-rotate(180deg) brightness(0.85) contrast(0.92) grayscale(0.5) sepia(0.18) saturate(0.85);
}

/* Boost contrasto per uso all'aperto (sole): alza muted/dim e ispessisce le
   hairline. Override LOCALI, non toccano il DS. */
:root[data-contrast="high"] {
  --text-muted:   #c2c0b8;
  --text-dim:     #9a978f;
  --hairline:     #34322e;
  --hairline-w:   1px;
}

*, *::before, *::after { -webkit-tap-highlight-color: transparent; }

/* Accessibilità: link "salta al contenuto" visibile solo al focus da tastiera. */
.skip-link {
  position: absolute; left: -999px; top: 0;
  background: var(--bg-panel); color: var(--text-primary);
  padding: var(--space-2) var(--space-4); z-index: var(--z-toast);
}
.skip-link:focus { left: var(--space-3); top: var(--space-3); }

/* Touch targets: tutti i controlli primari mobile >=48px (linee guida ergonomia). */
.btn-touch { min-height: 48px; min-width: 48px; display: inline-flex; align-items: center; justify-content: center; }
.btn-icon  { min-height: 44px; min-width: 44px; padding: 0 var(--space-2); font-size: var(--fs-md); line-height: 1; }

/* =============================================================================
   VISTA LOGIN
   ============================================================================= */
.login-screen {
  min-height: 100svh; display: grid; place-items: center;
  /* [SAFE-AREA 2026-07-01] rispetta status bar / notch su Capacitor Android e iOS. */
  padding-top: calc(var(--space-6) + env(safe-area-inset-top, 0px));
  padding-right: calc(var(--space-4) + env(safe-area-inset-right, 0px));
  padding-bottom: calc(var(--space-6) + env(safe-area-inset-bottom, 0px));
  padding-left: calc(var(--space-4) + env(safe-area-inset-left, 0px));
}
.login-card {
  width: 100%; max-width: 380px;
  background: var(--bg-panel); border: var(--hairline-w) solid var(--hairline-strong);
  border-radius: var(--r-lg); padding: var(--space-8) var(--space-6);
}
.login-head { text-align: center; margin-bottom: var(--space-6); }
.login-brand { font-size: var(--fs-2xl); font-weight: var(--fw-bold); letter-spacing: var(--tracking-wide); }
.login-tagline { margin-top: var(--space-1); font-size: var(--fs-sm); color: var(--text-muted); text-transform: uppercase; letter-spacing: var(--tracking-wider); }
.login-form { display: flex; flex-direction: column; gap: var(--space-4); }
.login-form .field { display: flex; flex-direction: column; gap: var(--space-1); }
.login-form .btn { margin-top: var(--space-2); width: 100%; }
.login-error { margin: 0; font-size: var(--fs-sm); color: var(--accent-negative); text-align: center; }
/* [SEC-LOCK] Overlay di blocco NON-distruttivo su inattività. Posizione/z-index sono inline in app.js
   (sopra il night-dim z=4000 e ogni modale); qui solo l'aspetto della card e del sotto-testo. */
.lock-overlay .lock-card { max-width: 360px; }
.lock-overlay .login-brand { font-size: var(--fs-2xl); }
.lock-sub { margin-top: var(--space-2); font-size: var(--fs-sm); color: var(--text-primary); text-align: center; }
#lock-passcode { text-align: center; letter-spacing: var(--tracking-wide); }
.login-demo { margin-top: var(--space-6); padding-top: var(--space-5); border-top: 1px dashed var(--hairline); }
.login-demo-label { font-size: var(--fs-xs); color: var(--text-muted); text-transform: uppercase; letter-spacing: var(--tracking-wider); margin-bottom: var(--space-2); text-align: center; }
.login-demo-btns { display: grid; grid-template-columns: repeat(auto-fit, minmax(132px, 1fr)); gap: var(--space-2); }
.login-demo-btns .btn { width: 100%; font-size: var(--fs-xs); padding: var(--space-2); white-space: normal; line-height: var(--lh-snug); }
.login-demo-btns .login-demo-btn { display: flex; flex-direction: column; align-items: center; gap: 1px; min-height: 44px; text-align: center; }
.login-demo-role { font-size: var(--fs-xs); color: var(--text-muted); }
.login-demo-user { font-size: var(--fs-sm); font-weight: var(--fw-semibold); }
.login-note { margin-top: var(--space-5); font-size: var(--fs-xs); color: var(--text-dim); line-height: var(--lh-snug); text-align: center; }

/* =============================================================================
   SHELL APP — mobile: colonna flex a tutta altezza, tabbar in fondo.
   ============================================================================= */
.app-shell { height: 100svh; display: flex; flex-direction: column; overflow: hidden; }

.app-header {
  flex: 0 0 auto;
  background: var(--bg-base);
  /* [SAFE-AREA 2026-07-01] Capacitor/Android edge-to-edge + iOS notch:
     - env(safe-area-inset-top): protegge da notch/status-bar traslucente (iOS + eventuale
       @capacitor/status-bar overlaysWebView:true su Android).
     - max(var(--space-3), …): garantisce un respiro minimo di 12px anche quando env()
       riporta 0 (browser desktop, Android emulator con status bar solida), evitando
       la sensazione di "appiccicato" alla status bar chiara segnalata dall'utente.
     - inset laterali: notch in landscape.
     Su desktop ≥900px questa regola è sovrascritta con padding equivalente basato su --space-3. */
  padding-top: max(var(--space-3), calc(var(--space-2) + env(safe-area-inset-top, 0px)));
  padding-right: calc(var(--space-3) + env(safe-area-inset-right, 0px));
  padding-bottom: var(--space-2);
  padding-left: calc(var(--space-3) + env(safe-area-inset-left, 0px));
  gap: var(--space-2);
  align-items: center;
}
.app-brand { min-width: 0; }
.app-brand .page-title { font-size: var(--fs-md); }
.app-brand .page-subtitle { margin-top: 0; font-size: var(--fs-xs); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 52vw; }
.app-toolbar { gap: var(--space-1); flex-wrap: nowrap; }
/* [UX-MOBILE] menu "Aspetto": <details> nativo, header meno affollato. */
.hdr-menu { position: relative; }
.hdr-menu > summary.hdr-menu-trigger { list-style: none; cursor: pointer; }
.hdr-menu > summary.hdr-menu-trigger::-webkit-details-marker { display: none; }
.hdr-menu > summary.hdr-menu-trigger::marker { content: ""; }
.hdr-menu[open] > summary.hdr-menu-trigger { background: var(--bg-panel-elevated); }
.hdr-menu-pop {
  position: absolute; right: 0; top: calc(100% + var(--space-1));
  display: flex; flex-wrap: wrap; justify-content: flex-end; gap: var(--space-1);
  max-width: 232px; padding: var(--space-2);
  background: var(--bg-panel); border: var(--hairline-w) solid var(--hairline-strong);
  border-radius: var(--r-sm); box-shadow: 0 4px 12px rgba(0,0,0,0.4); z-index: 1600;
}
#btn-help { display: none; }   /* [MAP-FIX] "?" guida: solo desktop (su mobile si usa il FAB) */

/* Stato collegamento realtime (button tappabile → apre KB tema connessione).
   [UX-MOBILE 2026-07-01] Mobile: senza il label la vecchia regola lasciava un
   rettangolo bordato "vuoto" che sembrava un input rotto. Sul mobile passa a
   icon-only (nessun border/padding), sopra dot più grande (12px) per touch.
   Desktop: border+label riappaiono (vedi @media min-width:900px). */
.link-status {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--space-2);
  min-height: 44px; min-width: 36px; padding: 0;
  background: transparent; border: none; border-radius: var(--r-sm);
  font-family: var(--font-mono); font-size: var(--fs-xs); text-transform: uppercase; letter-spacing: var(--tracking-wide);
  color: var(--text-muted); white-space: nowrap; cursor: pointer;
  flex: 0 0 auto;   /* non comprimere in una toolbar affollata */
}
.link-dot { width: 12px; height: 12px; border-radius: 50%; background: var(--text-dim); flex: 0 0 auto; box-shadow: 0 0 0 1px rgba(0,0,0,0.4); }
.link-status[data-state="online"]     { color: var(--accent-positive); }
.link-status[data-state="online"] .link-dot { background: var(--accent-positive); }
.link-status[data-state="connecting"] { color: var(--accent-warn); }
.link-status[data-state="connecting"] .link-dot { background: var(--accent-warn); animation: pulse 1.2s infinite; }
.link-status[data-state="offline"]    { color: var(--accent-negative); }
.link-status[data-state="offline"] .link-dot { background: var(--accent-negative); }
@keyframes pulse { 0%,100% { opacity: 1; } 50% { opacity: 0.3; } }
/* [#89][FE-TRACK] Mission-mode toggle: ora vive nel menu Aspetto come .btn.btn-icon.
   Il glifo ⦿ colora via `color` (currentColor) per stato: verde on / ambra degraded|starting
   / grigio off. (Prima colorava un .link-dot, rimosso con lo spostamento dall'header.) */
.btn-icon.track-pill[data-state="on"]        { color: var(--accent-positive); }
.btn-icon.track-pill[data-state="degraded"]  { color: var(--accent-warn); }
.btn-icon.track-pill[data-state="starting"]  { color: var(--accent-warn); animation: pulse 1.2s infinite; }
.btn-icon.track-pill[data-state="off"]       { color: var(--text-dim); opacity: 0.85; }
.link-label { display: none; }                 /* mobile: solo il pallino per risparmiare spazio */

/* Icone essenziali dell'header mobile: mai comprimibili (touch target garantito). */
.app-toolbar > #health-dot,
.app-toolbar > #link-status,
.app-toolbar > .hdr-menu,
.app-toolbar > #btn-admin,
.app-toolbar > #btn-logout { flex: 0 0 auto; }

#btn-contrast[aria-pressed="true"] { color: var(--accent-warn); border-color: var(--accent-warn); }

/* Banner ruolo + ambito visibilità + stato geo. */
.role-banner {
  flex: 0 0 auto;
  display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap;
  padding: var(--space-2) var(--space-3);
  background: var(--bg-panel); border-top: var(--hairline-w) solid var(--hairline); border-bottom: var(--hairline-w) solid var(--hairline);
  font-size: var(--fs-xs); color: var(--text-secondary);
}
.role-banner .role-scope { color: var(--text-muted); }
.role-banner .tag { flex: 0 0 auto; }

/* Banner di stato non-modale (connessione persa / fuori-AO). */
.state-banner {
  flex: 0 0 auto;
  display: flex; align-items: center; gap: var(--space-2);
  padding: var(--space-2) var(--space-3);
  font-size: var(--fs-sm); font-weight: var(--fw-medium);
  border-bottom: var(--hairline-w) solid var(--hairline);
}
.state-banner[data-tone="warn"]     { background: var(--warn-dim);     color: var(--accent-warn); }
.state-banner[data-tone="negative"] { background: var(--negative-dim); color: var(--accent-negative); }
.state-banner[data-tone="positive"] { background: var(--positive-dim); color: var(--accent-positive); }
.state-banner::before { content: '●'; font-size: 0.7em; }

/* =============================================================================
   LAYOUT / VISTE — mobile: una vista alla volta (controllata da #main[data-view]).
   ============================================================================= */
.layout {
  flex: 1 1 auto; min-height: 0;
  display: block; overflow-y: auto; -webkit-overflow-scrolling: touch;
  padding: var(--space-3);
  /* [UX-MOBILE] spazio in fondo: la FAB "?" è fixed e si sovrapporrebbe all'ultimo
     contenuto scrollato (es. azioni Overview). 52px FAB + margini. */
  padding-bottom: calc(52px + var(--space-3) + var(--space-3));
}
.col-left { display: flex; flex-direction: column; gap: var(--space-3); min-width: 0; }
.col-right { min-width: 0; height: 100%; }
/* [#5 ROOT] HQ-ROOT = console di SOLA gestione missioni: nascondi la mappa e i pannelli operativi
   (resta solo la console missioni panel-hq). Su desktop la console va a tutta larghezza (vedi @media). */
#main[data-root="true"] .col-right { display: none; }
#main[data-root="true"] .col-left [data-view-panel]:not([data-view-panel="hq"]) { display: none; }

/* Mobile: nasconde tutte le viste-pannello tranne quella attiva. */
@media (max-width: 899px) {
  [data-view-panel] { display: none; }
  #main[data-view="overview"]  [data-view-panel="overview"],
  #main[data-view="manage"]    [data-view-panel="manage"],   /* [ROLES] gestione missione (op_lead/hq) */
  #main[data-view="hq"]        [data-view-panel="hq"],
  #main[data-view="briefing"]  [data-view-panel="briefing"],
  #main[data-view="weather"]   [data-view-panel="weather"],
  #main[data-view="tasks"]     [data-view-panel="tasks"],
  #main[data-view="roster"]    [data-view-panel="roster"],
  #main[data-view="checklist"] [data-view-panel="checklist"],   /* [UI-FIX 2026-07-01] mancava → operatore vedeva schermo vuoto */
  #main[data-view="map"]       [data-view-panel="map"] { display: block; }
  /* [UX-MOBILE] header: la toolbar icone va a capo invece di tagliare l'ultima
     (il logout ⏻ usciva dallo schermo a destra); sottotitolo missione più stretto. */
  .app-toolbar { flex-wrap: wrap; justify-content: flex-end; row-gap: var(--space-1); }
  .app-brand .page-subtitle { max-width: 34vw; }
  /* [UX-MOBILE] l'header deve creare uno stacking context SOPRA la mappa, altrimenti il
     popover del menu "Aspetto" finisce sotto i layer Leaflet (z fino a ~1000). z-index esplicito. */
  .app-header { position: relative; z-index: 1600; }
  /* Vista mappa: edge-to-edge, niente scroll. */
  #main[data-view="map"] { overflow: hidden; padding: 0; }
  #main[data-view="map"] .map-wrap { height: 100%; border-radius: 0; border: none; }
}

.panel { padding: var(--panel-padding-sm); background: var(--bg-panel); border: var(--hairline-w) solid var(--hairline); border-radius: var(--r-md); }
.panel-title {
  font-size: var(--fs-sm); font-weight: var(--fw-semibold); text-transform: uppercase; letter-spacing: var(--tracking-wider);
  color: var(--text-primary); margin-bottom: var(--space-3);
  display: flex; align-items: center; justify-content: space-between; gap: var(--space-2);
}
.panel-title .panel-actions { display: inline-flex; gap: var(--space-2); align-items: center; }
.panel-sub { font-size: var(--fs-xs); color: var(--text-muted); margin-bottom: var(--space-3); }

/* Link contestuale "Guida su questa sezione". */
.kb-link { background: none; border: none; padding: var(--space-1) var(--space-2); color: var(--accent-link); font-family: var(--font-mono); font-size: var(--fs-xs); cursor: pointer; text-decoration: underline; text-underline-offset: 2px; min-height: 36px; }
.kb-link::before { content: '? '; }

/* --- Briefing --- */
.briefing-block { margin-bottom: var(--space-4); }
.briefing-block:last-child { margin-bottom: 0; }
.briefing-label { font-size: var(--fs-xs); color: var(--text-muted); text-transform: uppercase; letter-spacing: var(--tracking-wider); margin-bottom: var(--space-1); }
.briefing-text { font-size: var(--fs-base); color: var(--text-secondary); line-height: var(--lh-normal); white-space: pre-line; }
.briefing-meta { display: grid; grid-template-columns: auto 1fr; gap: var(--space-1) var(--space-3); font-size: var(--fs-sm); }
.briefing-meta dt { color: var(--text-muted); }
.briefing-meta dd { margin: 0; color: var(--text-secondary); }

/* --- Overview (op_lead): card stato + KPI sintetici --- */
.ov-status { display: flex; flex-direction: column; gap: var(--space-1); margin-bottom: var(--space-4); }
.ov-status-name { font-size: var(--fs-lg); font-weight: var(--fw-semibold); }
.ov-status-meta { font-size: var(--fs-sm); color: var(--text-muted); }
.kpi-grid { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-2); margin-bottom: var(--space-4); }
.kpi { padding: var(--space-3); background: var(--bg-base); border: var(--hairline-w) solid var(--hairline); border-radius: var(--r-md); }
.kpi-label { font-size: var(--fs-xs); color: var(--text-muted); text-transform: uppercase; letter-spacing: var(--tracking-wide); margin-bottom: var(--space-1); }
.kpi-value { font-size: var(--fs-xl); font-weight: var(--fw-semibold); line-height: var(--lh-tight); }
.kpi-value[data-tone="positive"] { color: var(--accent-positive); }
.kpi-value[data-tone="warn"]     { color: var(--accent-warn); }
.kpi-value[data-tone="negative"] { color: var(--accent-negative); }
.ov-actions { display: flex; flex-direction: column; gap: var(--space-2); }
.ov-actions .btn { width: 100%; }

/* --- Meteo (timeline 12h) --- */
.wx-switch { margin-bottom: var(--space-3); }
.wx-switch .toggle-group { display: inline-flex; width: 100%; }
.wx-switch .toggle-btn { flex: 1; min-height: 44px; }
.wx-loc { font-size: var(--fs-xs); color: var(--text-muted); margin-bottom: var(--space-2); }
.wx-rows { display: flex; flex-direction: column; }
.wx-row { display: grid; grid-template-columns: 3.4em 1.8em 1fr auto; align-items: center; gap: var(--space-2); padding: var(--space-2) 0; border-bottom: 1px dashed var(--hairline); font-size: var(--fs-base); }
.wx-row:last-child { border-bottom: none; }
.wx-time { color: var(--text-secondary); font-variant-numeric: tabular-nums; }   /* leggibile al sole */
.wx-icon { font-size: var(--fs-md); text-align: center; }
.wx-cond { color: var(--text-secondary); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.wx-vals { display: inline-flex; gap: var(--space-3); justify-content: flex-end; white-space: nowrap; }
/* [UI-FIX 2026-07-01] su schermi molto stretti il testo "Partly cloudy", "Thunderstorm" ecc.
   viene troncato a "Partly clo…" e diventa rumore visivo: l'icona basta (semantica identica,
   riconoscibile in un colpo d'occhio). Sotto 380px togliamo la colonna testo e la griglia
   diventa 3 colonne: ora, icona, valori. Manteniamo il testo per screen reader via aria-label
   già presente sull'icona. */
@media (max-width: 379px) {
  .wx-row { grid-template-columns: 3.4em 1.8em 1fr; }
  .wx-cond { display: none; }
  /* [P3-1 2026-07-01] iPhone SE (360px): il subtitle "MOB-A-1 · Operator · M-MOB1 · MOB-01 · CAMMINATA LIBERA"
     con max-width:34vw (=~122px) veniva troncato a 3-4 caratteri con ellipsis.
     Opzione C: il brand va a colonna, il subtitle va a riga singola ma può
     usare tutto lo spazio disponibile del contenitore (min-width:0 sul
     genitore evita che si comprima). Il testo scorre in linea ma il codename
     principale (fino al primo separatore) resta sempre visibile.
     Header cresce di ~1 riga solo sotto 380px; a 380px+ resta invariato. */
  .app-header { flex-wrap: wrap; }
  .app-brand {
    flex: 1 1 100%;
    display: flex; flex-direction: column; align-items: flex-start; gap: 0;
    min-width: 0;
  }
  .app-brand .page-subtitle {
    max-width: 100%;
    width: 100%;
    /* mantiene nowrap + ellipsis ma su un vw pieno → codename leggibile,
       il resto scorre come coda. */
  }
  .app-toolbar { flex: 0 1 auto; margin-left: auto; }
}
.wx-temp { color: var(--text-primary); font-weight: var(--fw-medium); }
.wx-rain { color: var(--tg-route); }
.wx-wind { color: var(--text-muted); }
.wx-dir { color: var(--text-dim); }   /* [AGENTE-D #2] sigla direzione vento, tono attenuato */
.wx-note { margin-top: var(--space-2); font-size: var(--fs-xs); color: var(--text-dim); }

/* --- Task --- */
.task-group { margin-bottom: var(--space-4); }
.task-group:last-child { margin-bottom: 0; }
.task-summary { display: flex; flex-wrap: wrap; gap: var(--space-2); margin-bottom: var(--space-3); }
.task-group-title { font-size: var(--fs-xs); color: var(--text-muted); text-transform: uppercase; letter-spacing: var(--tracking-wider); margin-bottom: var(--space-2); display: flex; align-items: center; gap: var(--space-2); }
.task { display: grid; grid-template-columns: auto 1fr auto; gap: var(--space-3); align-items: start; padding: var(--space-3) 0; border-bottom: 1px dashed var(--hairline); }
.task:last-child { border-bottom: none; }
.task-dot { width: 10px; height: 10px; border-radius: 50%; margin-top: 5px; flex: 0 0 auto; }
.task-dot[data-status="pending"]     { background: var(--text-dim); }
.task-dot[data-status="in_progress"] { background: var(--accent-warn); }
.task-dot[data-status="done"]        { background: var(--accent-positive); }
.task-main { min-width: 0; }
.task-title { font-size: var(--fs-base); color: var(--text-primary); }
.task.is-done .task-title { color: var(--text-muted); text-decoration: line-through; }
.task-desc { font-size: var(--fs-sm); color: var(--text-muted); margin-top: 2px; }
.task-assignee { font-size: var(--fs-xs); color: var(--text-dim); margin-top: 2px; }
.task-status-select { font-size: var(--fs-xs); min-height: 40px; }
.task-new { margin-top: var(--space-3); padding-top: var(--space-3); border-top: 1px dashed var(--hairline); display: flex; flex-direction: column; gap: var(--space-2); }
.task-new[hidden] { display: none; }
.task-new .input, .task-new .select { width: 100%; min-height: 44px; }

/* --- Roster (squadre + operatori) --- */
.roster-team { margin-bottom: var(--space-4); }
.roster-team:last-child { margin-bottom: 0; }
.roster-team-head { display: flex; align-items: center; gap: var(--space-2); margin-bottom: var(--space-2); }
.roster-swatch { width: 11px; height: 11px; border-radius: 50%; flex: 0 0 auto; }
.roster-team-name { font-size: var(--fs-sm); font-weight: var(--fw-semibold); }
.roster-team-meta { font-size: var(--fs-xs); color: var(--text-muted); margin-left: auto; }
.roster-op { display: flex; align-items: center; gap: var(--space-2); padding: var(--space-2) 0; font-size: var(--fs-base); border-bottom: 1px dashed var(--hairline); }
.roster-op:last-child { border-bottom: none; }
.roster-op-codename { color: var(--text-secondary); }
.roster-op .tag { margin-left: auto; }

/* =============================================================================
   MAPPA
   ============================================================================= */
.map-wrap { position: relative; height: 100%; border: var(--hairline-w) solid var(--hairline); border-radius: var(--r-md); overflow: hidden; }
#map { width: 100%; height: 100%; background: var(--bg-panel); }
.leaflet-container { font-family: var(--font-mono); background: var(--bg-panel); }
.leaflet-bar a, .leaflet-control-attribution { background: var(--bg-panel) !important; color: var(--text-secondary) !important; border-color: var(--hairline) !important; }
.leaflet-bar a { width: 36px !important; height: 36px !important; line-height: 36px !important; font-size: var(--fs-md) !important; }   /* zoom touch-friendly */
.leaflet-bar a:hover { background: var(--bg-panel-elevated) !important; }
.leaflet-control-attribution a { color: var(--accent-link) !important; }

.op-tooltip { background: var(--bg-panel) !important; color: var(--text-primary) !important; border: var(--hairline-w) solid var(--hairline-strong) !important; border-radius: var(--r-sm) !important; font-family: var(--font-mono) !important; font-size: var(--fs-xs) !important; box-shadow: none !important; }
.op-tooltip::before { display: none !important; }

/* Controlli mappa custom — zona pollice (basso-destra), target grandi.
   [SAFE-AREA 2026-07-01 P3-2] Android gesture bar (~35px) e iOS home indicator
   coprivano l'ultimo pulsante della colonna (route toggle / fullscreen). Il
   max() con env(safe-area-inset-bottom) alza la colonna sopra la barra
   sistema; su browser desktop env()=0 → resta var(--space-2). */
.map-controls { position: absolute; right: var(--space-2); bottom: max(var(--space-2), calc(var(--space-2) + env(safe-area-inset-bottom, 0px))); z-index: 550; display: flex; flex-direction: column; gap: var(--space-2); align-items: flex-end; }
.map-ctrl { min-width: 44px; min-height: 44px; display: inline-flex; align-items: center; justify-content: center; gap: var(--space-2); padding: 0 var(--space-3); background: var(--bg-panel); border: var(--hairline-w) solid var(--hairline-strong); border-radius: var(--r-sm); color: var(--text-primary); font-family: var(--font-mono); font-size: var(--fs-md); cursor: pointer; }
.map-ctrl:active { background: var(--bg-panel-elevated); }
.map-ctrl[data-active="false"] { color: var(--text-dim); }
.map-ctrl .ctrl-label { font-size: var(--fs-xs); }
/* [MAP-ROUTES] pulsante route ciclico nella colonna controlli: etichetta compatta, colore della route attiva. */
.map-ctrl.route-cycle { padding: 0 var(--space-2); font-size: var(--fs-xs); font-weight: var(--fw-semibold); letter-spacing: var(--tracking-wide); color: var(--accent-link); }

/* Filtro squadre (popover sopra i controlli). */
.team-filter { position: absolute; right: var(--space-2); bottom: calc(var(--space-2) + 7 * 44px + 7 * var(--space-2)); z-index: 560; background: var(--bg-panel); border: var(--hairline-w) solid var(--hairline-strong); border-radius: var(--r-sm); padding: var(--space-2); display: flex; flex-direction: column; gap: var(--space-1); }
.team-filter[hidden] { display: none; }
.team-filter-row { display: flex; align-items: center; gap: var(--space-2); min-height: 40px; padding: 0 var(--space-1); font-size: var(--fs-sm); cursor: pointer; }
.team-filter-row[data-active="false"] { opacity: 0.45; }

/* Legenda — chip collassabile (default chiuso su mobile per non coprire mappa). */
/* Legenda in alto a destra (lo zoom Leaflet sta in alto a sinistra). */
.map-legend { position: absolute; right: var(--space-2); top: var(--space-2); z-index: 500; background: var(--bg-panel); border: var(--hairline-w) solid var(--hairline); border-radius: var(--r-sm); font-size: var(--fs-xs); max-width: 70%; }
.map-legend-toggle { display: flex; align-items: center; gap: var(--space-2); min-height: 40px; padding: 0 var(--space-3); background: none; border: none; color: var(--text-secondary); font-family: var(--font-mono); font-size: var(--fs-xs); cursor: pointer; text-transform: uppercase; letter-spacing: var(--tracking-wide); width: 100%; }
.map-legend-body { padding: 0 var(--space-3) var(--space-2); }
.map-legend:not(.open) .map-legend-body { display: none; }
.legend-row { display: flex; align-items: center; gap: var(--space-2); padding: 2px 0; color: var(--text-secondary); }
.legend-swatch { width: 12px; height: 12px; border-radius: 50%; flex: 0 0 auto; }
.legend-line { width: 16px; height: 0; border-top: 3px solid var(--tg-route); flex: 0 0 auto; }

/* Full-screen mappa immersivo. */
.map-fs-exit {
  position: absolute;
  /* [SAFE-AREA 2026-07-01] Capacitor/Android edge-to-edge: status bar traslucente
     copriva il pulsante "Esci fullscreen". Il max() garantisce >=8px anche su
     browser desktop dove env() = 0. */
  top: max(var(--space-2), calc(var(--space-1) + env(safe-area-inset-top, 0px)));
  right: max(var(--space-2), calc(var(--space-1) + env(safe-area-inset-right, 0px)));
  z-index: 620;   /* sopra i controlli Leaflet (z=800) per rimanere sempre cliccabile */
  background: var(--bg-panel); border: var(--hairline-w) solid var(--hairline-strong);
}
body.map-fs .map-wrap { position: fixed; inset: 0; z-index: var(--z-overlay); border: none; border-radius: 0; height: 100vh; }
body.map-fs .app-header, body.map-fs .role-banner, body.map-fs .state-banner, body.map-fs #tabbar, body.map-fs #kb-fab { display: none !important; }
/* [FS-FIX 2026-07-01] Legenda in fullscreen: era a bottom-left → collideva col
   FAB MD (anch'esso bottom-left). Resta bottom-left ma sale SOPRA il MD (52px
   + margine) — a destra la colonna controlli occupa il bordo, quindi mantenere
   sinistra evita anche quella collisione. */
body.map-fs .map-legend {
  top: auto; right: auto;
  left: max(var(--space-2), calc(var(--space-2) + env(safe-area-inset-left, 0px)));
  bottom: calc(52px + var(--space-3) + var(--space-2) + env(safe-area-inset-bottom, 0px));
}
/* [FS-FIX 2026-07-01] Controlli Leaflet nativi (zoom +/−, attribution) in
   fullscreen: Android/iOS status bar copre il "+". Sposto il container del
   layer top con padding safe-area (Leaflet posiziona i controlli dentro
   .leaflet-top). Trick: uso translate sui figli così non rompe le API interne. */
body.map-fs .leaflet-top { padding-top: env(safe-area-inset-top, 0px); }
body.map-fs .leaflet-left { padding-left: env(safe-area-inset-left, 0px); }
body.map-fs .leaflet-right { padding-right: env(safe-area-inset-right, 0px); }
body.map-fs .leaflet-bottom { padding-bottom: env(safe-area-inset-bottom, 0px); }
/* Pulsante fullscreen (⛶) → cambio icona quando siamo in fs (indica "esci").
   [P3-3 2026-07-01] Il pulsante contiene "⛶" come text-node nudo (creato in
   MapView.render, app.js). Vincolo: NON toccare app.js. Trick CSS-only: in
   fullscreen azzero il font-size del button → il glifo "⛶" scompare (non
   c'è nodo da nascondere altrimenti), poi un ::before ripristina il font-size
   e stampa "✕". Border/background rafforzati per stato "attivo/premuto". */
body.map-fs #ctrl-fs {
  color: var(--accent-warn);
  font-size: 0;   /* nasconde il text-node "⛶" senza toccare il DOM */
  border-color: var(--accent-warn);
  background: color-mix(in srgb, var(--accent-warn) 15%, var(--bg-panel));
}
body.map-fs #ctrl-fs::before {
  content: '✕';
  font-family: var(--font-mono);
  font-size: var(--fs-md);
  line-height: 1;
}

/* =============================================================================
   BOTTOM NAV (mobile) — generata per ruolo.
   ============================================================================= */
.tabbar {
  flex: 0 0 auto;
  display: flex; align-items: stretch;
  height: calc(var(--tabbar-h) + env(safe-area-inset-bottom, 0px));
  padding-bottom: env(safe-area-inset-bottom, 0px);
  background: var(--bg-panel); border-top: var(--hairline-w) solid var(--hairline-strong);
}
.tab {
  flex: 1 1 0; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px;
  background: none; border: none; border-top: 2px solid transparent;
  color: var(--text-muted); font-family: var(--font-mono); cursor: pointer; min-width: 0; position: relative;
}
.tab-ico { font-size: var(--fs-lg); line-height: 1; }
.tab-label { font-size: 0.625rem; text-transform: uppercase; letter-spacing: var(--tracking-wide); }
.tab[data-active="true"] { color: var(--accent-link); border-top-color: var(--accent-link); }
.tab-badge { position: absolute; top: 6px; right: 50%; transform: translateX(14px); min-width: 16px; height: 16px; padding: 0 4px; border-radius: 8px; background: var(--accent-negative); color: #fff; font-size: 0.625rem; display: inline-flex; align-items: center; justify-content: center; }

/* =============================================================================
   KNOWLEDGE BASE — FAB + overlay (sheet mobile / pannello desktop) + accordion.
   ============================================================================= */
.kb-fab {
  position: fixed; left: var(--space-3); bottom: calc(var(--tabbar-h) + env(safe-area-inset-bottom, 0px) + var(--space-3));
  width: 52px; height: 52px; border-radius: 50%;
  font-size: var(--fs-xl); font-weight: var(--fw-bold);
  /* [UX-MOBILE] tema scuro esplicito: senza, il <button> ereditava lo sfondo bianco di
     default del browser (FAB bianca sul tema scuro). */
  background: var(--bg-panel); color: var(--text-primary); border: var(--hairline-w) solid var(--hairline-strong);
  z-index: 1500; pointer-events: auto; box-shadow: 0 2px 8px rgba(0,0,0,0.35);   /* [MAP-FIX] sopra i controlli Leaflet (z 1000), sotto il modale KB (z 2000) */
}

.kb-overlay { position: fixed; inset: 0; z-index: var(--z-modal); display: flex; align-items: flex-end; justify-content: center; background: rgba(0,0,0,0.5); opacity: 0; transition: opacity var(--duration-normal) var(--ease-out); }
.kb-overlay.open { opacity: 1; }
.kb-panel { width: 100%; max-width: 640px; max-height: 88svh; display: flex; flex-direction: column; background: var(--bg-panel); border: var(--hairline-w) solid var(--hairline-strong); border-bottom: none; border-radius: var(--r-lg) var(--r-lg) 0 0; transform: translateY(100%); transition: transform var(--duration-slow) var(--ease-out); }
.kb-overlay.open .kb-panel { transform: none; }
.kb-head { display: flex; align-items: center; gap: var(--space-2); padding: var(--space-3) var(--space-4); border-bottom: var(--hairline-w) solid var(--hairline); position: relative; }
.kb-handle { position: absolute; top: 6px; left: 50%; transform: translateX(-50%); width: 36px; height: 4px; border-radius: 2px; background: var(--text-dim); }
.kb-title { font-size: var(--fs-sm); font-weight: var(--fw-semibold); text-transform: uppercase; letter-spacing: var(--tracking-wider); flex: 1; }
.kb-close { background: none; border: none; color: var(--text-muted); font-size: var(--fs-md); cursor: pointer; }
.kb-body { padding: var(--space-3) var(--space-4) var(--space-6); overflow-y: auto; -webkit-overflow-scrolling: touch; }
.kb-search { width: 100%; min-height: 44px; margin-bottom: var(--space-3); }
.kb-intro { font-size: var(--fs-sm); color: var(--text-muted); margin-bottom: var(--space-3); }

/* Accordion KB (native <details>). */
.kb-acc { border: var(--hairline-w) solid var(--hairline); border-radius: var(--r-sm); margin-bottom: var(--space-2); overflow: hidden; }
.kb-acc[hidden] { display: none; }
.kb-acc > summary { list-style: none; cursor: pointer; min-height: 48px; display: flex; align-items: center; gap: var(--space-2); padding: var(--space-2) var(--space-3); font-size: var(--fs-base); font-weight: var(--fw-medium); color: var(--text-primary); background: var(--bg-base); }
.kb-acc > summary::-webkit-details-marker { display: none; }
.kb-acc > summary::after { content: '+'; margin-left: auto; color: var(--text-muted); font-size: var(--fs-md); }
.kb-acc[open] > summary::after { content: '–'; }
.kb-acc-chapter { font-size: var(--fs-xs); color: var(--text-muted); margin-right: var(--space-1); }
.kb-acc-body { padding: var(--space-3); font-size: var(--fs-base); color: var(--text-secondary); line-height: var(--lh-normal); border-top: var(--hairline-w) solid var(--hairline); }
.kb-acc-body p { margin-bottom: var(--space-2); }
.kb-acc-body p:last-child { margin-bottom: 0; }
.kb-tour-start { margin-top: var(--space-3); width: 100%; }
.kb-empty { font-size: var(--fs-sm); color: var(--text-dim); padding: var(--space-4); text-align: center; }

/* Coachmark mini-tour (overlay non-modale). */
.kb-tour { position: fixed; inset: 0; z-index: var(--z-toast); pointer-events: none; }
.kb-tour-spot { position: absolute; border: 2px solid var(--accent-link); border-radius: var(--r-sm); box-shadow: 0 0 0 9999px rgba(0,0,0,0.6); transition: all var(--duration-normal) var(--ease-out); }
.kb-tour-bubble { position: absolute; max-width: 280px; background: var(--bg-panel); border: var(--hairline-w) solid var(--hairline-strong); border-radius: var(--r-md); padding: var(--space-3); pointer-events: auto; }
.kb-tour-text { font-size: var(--fs-base); color: var(--text-primary); margin-bottom: var(--space-3); }
.kb-tour-actions { display: flex; gap: var(--space-2); justify-content: flex-end; }

/* =============================================================================
   MODALE GESTIONE MISSIONE (op_lead)
   ============================================================================= */
.admin-section { margin-bottom: var(--space-5); }
.admin-section:last-child { margin-bottom: 0; }
.admin-section h3 { font-size: var(--fs-sm); text-transform: uppercase; letter-spacing: var(--tracking-wider); color: var(--text-muted); margin-bottom: var(--space-3); }
.admin-grid { display: grid; grid-template-columns: 1fr; gap: var(--space-3); }
.admin-grid .field { display: flex; flex-direction: column; gap: var(--space-1); }
.admin-grid .input { min-height: 44px; }
.admin-grid .input:disabled { opacity: 0.55; cursor: not-allowed; }   /* [AGENTE-D #4] campo raggio AO non in uso (poligono) */
.admin-grid textarea.input { resize: vertical; min-height: 64px; font-family: var(--font-mono); }
.route-current { font-size: var(--fs-sm); color: var(--text-secondary); padding: var(--space-3); border: 1px dashed var(--hairline); border-radius: var(--r-sm); margin-bottom: var(--space-3); }
.route-current strong { color: var(--accent-link); }
.file-row { display: flex; flex-direction: column; gap: var(--space-2); }
.file-hint { font-size: var(--fs-xs); color: var(--text-dim); }
.modal { width: min(560px, 94vw); }

/* =============================================================================
   DESKTOP / TABLET LANDSCAPE (>=900px) — grid 2 colonne, niente tabbar.
   Il comportamento desktop preesistente è conservato.
   ============================================================================= */
@media (min-width: 900px) {
  .app-shell { height: 100svh; overflow: hidden; }   /* [MAP-FIX] shell ancorata al viewport: niente scroll globale su desktop */
  /* [SAFE-AREA 2026-07-01] su desktop env() vale 0 (nessuna regressione); il pattern
     con calc() è mantenuto per coerenza e per tablet landscape con notch. */
  .app-header {
    position: sticky; top: 0; z-index: 1600;
    padding-top: calc(var(--space-3) + env(safe-area-inset-top, 0px));
    padding-right: calc(var(--space-5) + env(safe-area-inset-right, 0px));
    padding-bottom: var(--space-3);
    padding-left: calc(var(--space-5) + env(safe-area-inset-left, 0px));
  }   /* z sopra i layer Leaflet (~1000) per il dropdown menu Aspetto */
  .app-brand .page-title { font-size: var(--fs-lg); }
  .app-brand .page-subtitle { max-width: none; }
  /* Desktop: ripristina bordo/padding del pulsante link-status (con label). */
  .link-label { display: inline; }
  .link-status { padding: var(--space-1) var(--space-2); border: var(--hairline-w) solid var(--hairline); justify-content: flex-start; }
  .link-status[data-state="online"]     { border-color: var(--accent-positive); }
  .link-status[data-state="connecting"] { border-color: var(--accent-warn); }
  .link-status[data-state="offline"]    { border-color: var(--accent-negative); }
  .link-dot { width: 9px; height: 9px; box-shadow: none; }

  .layout { display: grid; grid-template-columns: minmax(340px, 400px) 1fr; grid-template-rows: 1fr; gap: var(--space-5); padding: var(--space-5); overflow: hidden; min-height: 0; }   /* [MAP-FIX] riga unica a tutta altezza; scroll solo interno alle colonne */
  .col-left { height: 100%; min-height: 0; overflow-y: auto; }   /* [MAP-FIX] solo la colonna pannelli scrolla */
  .col-right { height: 100%; min-height: 0; }   /* [MAP-FIX] niente sticky: la colonna mappa riempie l'altezza */
  #main[data-root="true"] { grid-template-columns: 1fr; }   /* [#5 ROOT] console a tutta larghezza (niente colonna mappa) */
  .map-wrap { height: 100%; min-height: 360px; }   /* [MAP-FIX] mappa = 100% colonna, controlli sempre visibili senza scroll pagina */

  .kpi-grid { grid-template-columns: 1fr 1fr; }
  .tabbar { display: none; }

  /* [MAP-FIX] Desktop: niente FAB (gli angoli bassi sono occupati — controlli mappa a destra,
     pulsanti pannello a sinistra). Il "?" guida passa nella toolbar header (#btn-help). Su mobile
     il FAB resta. Overlay KB centrato (sotto). */
  .kb-fab { display: none; }
  #btn-help { display: inline-flex; }
  .kb-overlay { align-items: center; }
  .kb-panel { border: var(--hairline-w) solid var(--hairline-strong); border-radius: var(--r-lg); max-height: 80svh; transform: scale(0.98); }
  .kb-overlay.open .kb-panel { transform: none; }

  .wx-switch .toggle-group { width: auto; }
}

/* =============================================================================
   REVIEW 4-AGENTI — nuovi componenti operativi/sicurezza (FASE D)
   ============================================================================= */

/* [MAP-THEME] Basemap a 3 stili (selettore in toolbar): 'auto' segue il tema,
   'light' sempre chiara, 'tactical' sempre scura/militare. Il filtro tattico si
   applica quando lo stile è 'tactical' OPPURE 'auto' in tema scuro → la mappa
   segue il tema senza JS. Alternativa vettoriale (Shortbread + MapLibre GL) =
   cambio infra, vedi README. */
body[data-mapstyle="tactical"] .leaflet-tile,
:root[data-theme="dark"] body[data-mapstyle="auto"] .leaflet-tile {
  filter: var(--tactical-filter);
}
/* 'auto' senza data-theme esplicito: segue la preferenza di sistema. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme]) body[data-mapstyle="auto"] .leaflet-tile { filter: var(--tactical-filter); }
}

/* Stato pulsanti toggle in toolbar. */
#btn-energy[aria-pressed="true"] { color: var(--accent-warn); border-color: var(--accent-warn); }

/* [CMD-HEALTH] semaforo salute missione (toolbar). */
.health-dot { width: 12px; height: 12px; border-radius: 50%; flex: 0 0 auto; background: var(--text-dim); }
.health-dot[data-tone="positive"] { background: var(--accent-positive); }
.health-dot[data-tone="warn"]     { background: var(--accent-warn); }
.health-dot[data-tone="negative"] { background: var(--accent-negative); }

/* [KB-TRAIN] banner modalità addestramento. */
.training-banner {
  flex: 0 0 auto; text-align: center;
  padding: var(--space-1) var(--space-3);
  background: var(--warn-dim); color: var(--accent-warn);
  font-size: var(--fs-xs); text-transform: uppercase; letter-spacing: var(--tracking-wide);
  border-bottom: var(--hairline-w) solid var(--accent-warn);
}

/* [ALERT] banner allarmi (offline / fuori-AO / man-down). */
.alert-banner::before { content: none; }
.alert-banner { gap: var(--space-2); }
.alert-ico { flex: 0 0 auto; }
.alert-msg { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.alert-go {
  flex: 0 0 auto; min-height: 36px; padding: 0 var(--space-3);
  background: transparent; border: var(--hairline-w) solid currentColor; border-radius: var(--r-sm);
  color: inherit; font-family: var(--font-mono); font-size: var(--fs-xs); cursor: pointer;
}

/* [OP-NOW] barra "ORA": stato + prossimo task + on/off-route. */
.now-bar {
  flex: 0 0 auto; display: flex; align-items: center; gap: var(--space-2);
  padding: var(--space-2) var(--space-3);
  background: var(--bg-base); border-bottom: var(--hairline-w) solid var(--hairline);
  font-size: var(--fs-sm);
}
.now-state { flex: 0 0 auto; padding: 2px var(--space-2); border-radius: var(--r-sm); font-weight: var(--fw-bold); letter-spacing: var(--tracking-wide); border: var(--hairline-w) solid currentColor; }
.now-state[data-tone="positive"] { color: var(--accent-positive); }
.now-state[data-tone="warn"]     { color: var(--accent-warn); }
.now-task { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--text-secondary); }
.now-route { flex: 0 0 auto; padding: 2px var(--space-2); border-radius: var(--r-sm); font-weight: var(--fw-medium); border: var(--hairline-w) solid currentColor; white-space: nowrap; }
.now-route[data-tone="positive"] { color: var(--accent-positive); }
.now-route[data-tone="negative"] { color: var(--accent-negative); }
.now-route[data-tone="warn"]     { color: var(--accent-warn); }   /* [UI-FIX 2026-07-01] GPS stimata: fallback, non usare on/off-route */
.now-route[data-tone="muted"]    { color: var(--text-dim); }

/* [OP-PANIC / PANIC-FAB 2026-07-01] Man-down (long-press) come FAB rosso fisso
   in basso a SINISTRA, accanto al kb-fab ("?"). Coppia: [ ? ] [ MD ] in basso
   a sinistra, stessa zona pollice — aiuto e emergenza raggiungibili senza
   cambiare presa. Il DOM vive top-level (fuori dall'header) così sopravvive a
   body.map-fs (dove l'header è display:none).
   Long-press semantics invariate ([OP-PANIC] in app.js). */
.btn-panic {
  position: fixed;
  /* subito a destra del kb-fab (left=space-3, width=52) → offset = space-3 + 52 + space-3 */
  left: calc(env(safe-area-inset-left, 0px) + var(--space-3) + 52px + var(--space-3));
  bottom: calc(var(--tabbar-h) + env(safe-area-inset-bottom, 0px) + var(--space-3));
  width: 52px; height: 52px; min-width: 52px; padding: 0;
  border-radius: 50%;
  background: var(--accent-negative) !important;
  color: #fff !important;
  border: var(--hairline-w) solid var(--accent-negative) !important;
  font-family: var(--font-mono); font-weight: var(--fw-bold);
  font-size: var(--fs-md); line-height: 1; letter-spacing: 0;
  display: inline-flex; align-items: center; justify-content: center;
  touch-action: none;
  z-index: 1550;   /* sopra i controlli Leaflet (~1000) e sopra il kb-fab (1500) per priorità safety */
  box-shadow: 0 2px 8px rgba(0,0,0,0.4);
  cursor: pointer;
}
.btn-panic:hover, .btn-panic:focus-visible {
  background: var(--accent-negative) !important; filter: brightness(1.15);
}
.btn-panic.arming { animation: panicArm 0.7s linear forwards; }
@keyframes panicArm { from { filter: brightness(1); transform: scale(1); } to { filter: brightness(1.6); transform: scale(1.12); } }

/* In fullscreen mappa il tabbar sparisce → tolgo l'offset tabbar mantenendo
   solo la safe-area inferiore. Il DOM top-level è già immune a `display:none`
   sull'header (l'elemento non è più discendente di app-header). */
body.map-fs .btn-panic {
  bottom: calc(env(safe-area-inset-bottom, 0px) + var(--space-3));
}

/* [CMD-HEALTH] riga salute nell'Overview. */
.ov-health { display: flex; align-items: center; gap: var(--space-2); padding: var(--space-2) var(--space-3); border-radius: var(--r-sm); margin-bottom: var(--space-3); border: var(--hairline-w) solid var(--hairline); font-size: var(--fs-sm); }
.ov-health-dot { width: 12px; height: 12px; border-radius: 50%; flex: 0 0 auto; }
.ov-health[data-tone="positive"] { color: var(--accent-positive); } .ov-health[data-tone="positive"] .ov-health-dot { background: var(--accent-positive); }
.ov-health[data-tone="warn"]     { color: var(--accent-warn); }     .ov-health[data-tone="warn"] .ov-health-dot { background: var(--accent-warn); }
.ov-health[data-tone="negative"] { color: var(--accent-negative); } .ov-health[data-tone="negative"] .ov-health-dot { background: var(--accent-negative); }
.ov-health-count { margin-left: auto; font-size: var(--fs-xs); }

/* [MAP-CKPT] checkpoint sulla mappa (divIcon: badge glifo + etichetta). */
.kp-marker { display: flex; align-items: center; gap: 4px; white-space: nowrap; background: none; border: none; }
.kp-glyph { display: inline-flex; align-items: center; justify-content: center; width: 18px; height: 18px; border: 1.5px solid; border-radius: 50%; background: var(--bg-panel); font-size: 11px; line-height: 1; flex: 0 0 auto; }
.kp-name { font-size: 10px; color: var(--text-primary); background: color-mix(in srgb, var(--bg-panel) 85%, transparent); padding: 0 3px; border-radius: 2px; letter-spacing: var(--tracking-wide); }
.legend-kp { font-size: var(--fs-sm); letter-spacing: 1px; }

/* [MAP-ROUTES] il selettore route è ora il pulsante ciclico `.map-ctrl.route-cycle` nella colonna controlli. */

/* Fit toolbar su schermi molto stretti (molti toggle). */
@media (max-width: 480px) {
  .app-toolbar { gap: 2px; }
  .btn-icon { min-width: 36px; padding: 0; }
  .app-brand .page-subtitle { max-width: 40vw; }
}
/* Desktop (>=900px): niente tabbar mobile, e il kb-fab è display:none (il "?" vive
   in header toolbar come #btn-help).
   [PANIC-DECISION 2026-07-01 v4] MD NASCOSTO SU DESKTOP.
   Rationale: MD è safety-critical per operator sul campo con smartphone. team_lead
   che siede in postazione BASE avanzata su desktop/tablet ≥900px ha canali voce/
   radio primari; se ferito in postazione, non ha bisogno del long-press MD. HQ e
   op_lead sono già nascosti via RBAC. Coerente con la filosofia: MD = alert
   automatico per l'operatore che potrebbe non poter rispondere alla radio.
   Su desktop la superficie mobile-first non ha senso; meglio zero cognitive load
   che una posizione mediocre in header/map-controls (già valutate v1-v3, tutte
   scartate). Se un team_lead ha bisogno del MD sul campo, usa mobile/APK Android.
   Nota: il vincolo hard "fullscreen mappa MD sempre visibile" si applica al
   contesto mobile (ne è la definizione: dita, guanti, allarme rapido). */
@media (min-width: 900px) {
  .btn-panic {
    display: none !important;
  }
}

/* =============================================================================
   BACKLOG ATTUABILE (FASE D2) — nuovi componenti
   ============================================================================= */

/* [PRINCIPAL] marker entità protetta. */
.principal-marker { display: flex; align-items: center; gap: 4px; background: none; border: none; }
.principal-glyph { display: inline-flex; align-items: center; justify-content: center; width: 20px; height: 20px; color: #e6b34a; font-size: 15px; line-height: 1; text-shadow: 0 0 3px rgba(0,0,0,0.7); flex: 0 0 auto; }

/* [MAP-DIR] frecce direzione di marcia sulla route. */
.route-arrow { background: none; border: none; }
.route-arrow-g { display: inline-block; font-size: 11px; line-height: 1; opacity: 0.95; }

/* [TL-STRIP] striscia stato squadra (Capo Squadra). */
.team-strip { flex: 0 0 auto; display: flex; align-items: center; gap: var(--space-2); padding: var(--space-1) var(--space-3); background: var(--bg-panel); border-bottom: var(--hairline-w) solid var(--hairline); overflow-x: auto; scrollbar-width: none; }
.team-strip::-webkit-scrollbar { display: none; }
.ts-label { flex: 0 0 auto; font-size: var(--fs-xs); color: var(--text-muted); text-transform: uppercase; letter-spacing: var(--tracking-wide); }
.ts-chip { flex: 0 0 auto; min-width: 26px; height: 22px; display: inline-flex; align-items: center; justify-content: center; padding: 0 4px; border-radius: 4px; font-size: var(--fs-xs); font-weight: var(--fw-semibold); border: 1px solid currentColor; }
.ts-chip[data-tone="positive"] { color: var(--accent-positive); }
.ts-chip[data-tone="warn"]     { color: var(--accent-warn); }
.ts-chip[data-tone="negative"] { color: var(--accent-negative); background: var(--negative-dim); }
.ts-chip[data-tone="muted"]    { color: var(--text-dim); }

/* [CMD-TIMELINE] barra finestra operativa (Overview). */
.ov-timeline { margin-bottom: var(--space-4); }
.ov-tl-head { display: flex; justify-content: space-between; gap: var(--space-2); font-size: var(--fs-xs); color: var(--text-muted); margin-bottom: var(--space-1); }
.ov-tl-state { text-transform: uppercase; letter-spacing: var(--tracking-wide); }
.ov-tl-track { height: 6px; background: var(--bg-base); border: var(--hairline-w) solid var(--hairline); border-radius: 3px; overflow: hidden; }
.ov-tl-fill { height: 100%; background: var(--accent-positive); }
.ov-timeline[data-tone="warn"]     .ov-tl-fill { background: var(--accent-warn); }
.ov-timeline[data-tone="warn"]     .ov-tl-state { color: var(--accent-warn); }
.ov-timeline[data-tone="negative"] .ov-tl-fill { background: var(--accent-negative); }
.ov-timeline[data-tone="negative"] .ov-tl-state { color: var(--accent-negative); }

/* [KB-CARDS] scheda d'azione in cima alla KB sheet. */
.kb-card { border: var(--hairline-w) solid var(--accent-link); border-radius: var(--r-sm); padding: var(--space-3); margin-bottom: var(--space-3); }
.kb-card-title { font-size: var(--fs-xs); text-transform: uppercase; letter-spacing: var(--tracking-wider); color: var(--text-muted); margin-bottom: var(--space-2); }
.kb-card-line { font-size: var(--fs-sm); color: var(--text-secondary); padding: 2px 0; line-height: var(--lh-snug); }
.kb-card-line::before { content: '▸ '; color: var(--accent-link); }

/* [ACK] conferma lettura briefing. */
.ack-btn { width: 100%; margin-top: var(--space-3); }

/* [NIGHT] modalità notte/stealth: dim globale + niente animazioni attira-occhio. */
#btn-night[aria-pressed="true"] { color: var(--accent-link); }
body[data-night]::after { content: ''; position: fixed; inset: 0; background: rgba(0,0,0,0.34); pointer-events: none; z-index: 4000; }
body[data-night] .link-status[data-state="connecting"] .link-dot { animation: none; }
body[data-night] .btn-panic { box-shadow: none; }

/* Riduci motion se richiesto dal sistema. */
@media (prefers-reduced-motion: reduce) {
  .link-status[data-state="connecting"] .link-dot { animation: none; }
  .btn-panic.arming { animation: none; }
  * { transition: none !important; }
}

/* ===========================================================================
   [HQ] VISTA BASE / HQ — stato comando, sotto-tab, tabella utenti, log, documenti.
   =========================================================================== */
.hq-command {
  display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); flex-wrap: wrap;
  padding: var(--space-3); margin-bottom: var(--space-3);
  background: var(--bg-panel-elevated); border: var(--hairline-w) solid var(--hairline); border-radius: var(--r-sm);
}
.hq-command[data-owned="true"] { border-color: var(--accent-warn); background: var(--warn-dim); }
.hq-cmd-state { font-size: var(--fs-sm); }
/* [REPORT] blocco riepilogo missione (after-action) nella vista BASE/HQ. */
.hq-report {
  display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); flex-wrap: wrap;
  padding: var(--space-3); margin-bottom: var(--space-3);
  background: var(--bg-panel-elevated); border: var(--hairline-w) solid var(--hairline); border-radius: var(--r-sm);
}
.hq-report-info { font-size: var(--fs-sm); }
/* [ML-01] blocco ciclo di vita missione (chiudi missione) nella vista BASE/HQ. */
.hq-lifecycle {
  display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); flex-wrap: wrap;
  padding: var(--space-3); margin-bottom: var(--space-3);
  background: var(--bg-panel-elevated); border: var(--hairline-w) solid var(--hairline); border-radius: var(--r-sm);
}
.hq-lifecycle[data-done="true"] { border-color: var(--accent-positive); }
/* Il DS non espone un variant "danger": lo definiamo scoped al pulsante di chiusura missione. */
.hq-lifecycle .btn[data-variant="danger"] {
  color: var(--accent-negative); border-color: var(--accent-negative); background: var(--negative-dim);
}
.hq-lifecycle .btn[data-variant="danger"]:hover { background: var(--accent-negative); color: var(--bg-panel); }
/* [HQ-SWITCH] nome missione cliccabile: header (BASE/HQ) + righe della console multi-missione. */
.hdr-switch { cursor: pointer; }
.hdr-switch:hover { text-decoration: underline; }
.hq-mission-link { background: none; border: none; padding: 0; margin: 0; font: inherit; color: inherit; cursor: pointer; text-align: left; }
.hq-mission-link:hover b { text-decoration: underline; }

.hq-tabs { display: flex; gap: var(--space-1); margin-bottom: var(--space-3); }
.hq-tabs .toggle-btn {
  flex: 1; min-height: 40px; padding: var(--space-2); cursor: pointer;
  background: var(--bg-base); color: var(--text-secondary);
  border: var(--hairline-w) solid var(--hairline); border-radius: var(--r-sm);
  font-family: var(--font-mono); font-size: var(--fs-xs);
}
.hq-tabs .toggle-btn[data-active="true"] { background: var(--bg-panel-elevated); color: var(--text-primary); border-color: var(--accent-link); }

.hq-userform { display: flex; flex-wrap: wrap; gap: var(--space-2); margin-bottom: var(--space-3); }
.hq-input {
  flex: 1; min-width: 110px; min-height: 44px; padding: 0 var(--space-2);
  background: var(--bg-base); color: var(--text-primary);
  border: var(--hairline-w) solid var(--hairline); border-radius: var(--r-sm);
  font-family: var(--font-mono); font-size: var(--fs-sm);
}
.hq-msg { font-size: var(--fs-xs); padding: var(--space-2); margin-bottom: var(--space-2); border-radius: var(--r-sm); }
.hq-msg[data-tone="positive"] { color: var(--accent-positive); background: var(--positive-dim); }
.hq-msg[data-tone="negative"] { color: var(--accent-negative); background: var(--negative-dim); }
.hq-muted { color: var(--text-muted); font-size: var(--fs-xs); }

.hq-table-wrap { overflow-x: auto; }
.hq-table { width: 100%; border-collapse: collapse; font-size: var(--fs-xs); }
.hq-table th, .hq-table td { text-align: left; padding: var(--space-2); border-bottom: var(--hairline-w) solid var(--hairline); white-space: nowrap; }
.hq-table th { color: var(--text-muted); text-transform: uppercase; letter-spacing: var(--tracking-wide); font-weight: var(--fw-semibold); }
.hq-table tr[data-disabled="true"] td { opacity: 0.5; }
.hq-table tr[data-alert="true"] td { background: var(--negative-dim); }

.hq-pill { display: inline-block; padding: 1px var(--space-2); border-radius: var(--r-sm); font-size: var(--fs-xs); border: var(--hairline-w) solid var(--hairline); }
.hq-pill[data-tone="positive"] { color: var(--accent-positive); }
.hq-pill[data-tone="negative"] { color: var(--accent-negative); }
.hq-pill[data-tone="warn"] { color: var(--accent-warn); border-color: var(--accent-warn); }
.btn-sm { min-height: 32px; padding: var(--space-1) var(--space-2); font-size: var(--fs-xs); }

.hq-loglist { display: flex; flex-direction: column; gap: 2px; }
.hq-logrow { display: grid; grid-template-columns: auto auto 1fr; gap: var(--space-2); align-items: baseline; padding: var(--space-2); border-bottom: var(--hairline-w) solid var(--hairline); font-size: var(--fs-xs); }
.hq-log-time { color: var(--text-muted); font-variant-numeric: tabular-nums; }
.hq-log-type { color: var(--text-primary); font-weight: var(--fw-medium); }
.hq-log-type[data-ev="assume_command"], .hq-log-type[data-ev="panic_open"] { color: var(--accent-warn); }
.hq-log-actor { color: var(--text-secondary); }
.hq-log-detail { grid-column: 1 / -1; color: var(--text-muted); }

.hq-doclist { display: flex; flex-direction: column; gap: var(--space-2); }
.hq-doc { display: flex; align-items: center; gap: var(--space-2); min-height: 48px; padding: 0 var(--space-3); text-decoration: none; color: var(--accent-link); background: var(--bg-base); border: var(--hairline-w) solid var(--hairline); border-radius: var(--r-sm); }
.hq-doc-ico { color: var(--text-muted); }

/* ===========================================================================
   [ENROLL] Toggle accesso/arruolamento (login) + console comando + tab arruolamento.
   =========================================================================== */
/* Toggle a 2 rami nel login: riusa .toggle-btn (come i tab HQ), scoped al login. */
.login-mode { display: flex; gap: var(--space-1); margin-bottom: var(--space-4); }
.login-mode .toggle-btn {
  flex: 1; min-height: 44px; padding: var(--space-2); cursor: pointer;
  background: var(--bg-base); color: var(--text-secondary);
  border: var(--hairline-w) solid var(--hairline); border-radius: var(--r-sm);
  font-family: var(--font-mono); font-size: var(--fs-xs);
}
.login-mode .toggle-btn[data-active="true"] { background: var(--bg-panel-elevated); color: var(--text-primary); border-color: var(--accent-link); }
#enroll-code { text-transform: uppercase; letter-spacing: var(--tracking-wide); }
/* Checkbox + label nel form nuova missione (root). */
.hq-check { display: flex; align-items: center; gap: var(--space-2); margin-bottom: var(--space-2); font-size: var(--fs-sm); }
.hq-newmission { margin-bottom: var(--space-3); }
.hq-newmission > .btn { margin-top: var(--space-2); }
/* Blocco credenziali (username/password una volta) + codici arruolamento. */
.hq-cred { padding: var(--space-3); margin: var(--space-2) 0; background: var(--bg-base); border: var(--hairline-w) solid var(--hairline); border-radius: var(--r-sm); }
.hq-cred-row { display: flex; align-items: center; flex-wrap: wrap; gap: var(--space-2); margin-bottom: var(--space-2); }
.hq-cred-val { font-family: var(--font-mono); font-size: var(--fs-sm); color: var(--text-primary); background: var(--bg-panel-elevated); padding: 1px var(--space-2); border-radius: var(--r-sm); word-break: break-all; }
.hq-cred-pwd { color: var(--accent-warn); }
.hq-enroll-fresh { padding: var(--space-3); margin-bottom: var(--space-3); background: var(--bg-base); border: var(--hairline-w) solid var(--accent-warn); border-radius: var(--r-sm); }
.hq-enroll-codes { display: flex; flex-direction: column; gap: var(--space-2); margin: var(--space-2) 0; }
.hq-enroll-code { display: flex; align-items: center; flex-wrap: wrap; gap: var(--space-2); }

/* [SHIFT] controllo turno in servizio (overview, scenari residenziali). */
.shift-box { margin-top: var(--space-3); padding: var(--space-3); background: var(--bg-panel-elevated); border: var(--hairline-w) solid var(--hairline); border-radius: var(--r-sm); }
.shift-head { font-size: var(--fs-sm); margin-bottom: var(--space-2); }
.shift-btns { display: flex; flex-wrap: wrap; gap: var(--space-2); }

/* [TAKEOVER] azioni comando HQ + avviso op_lead a comando sospeso. */
.hq-cmd-actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); }
.ov-takeover-warn { margin: var(--space-2) 0 var(--space-3); padding: var(--space-2) var(--space-3); border-radius: var(--r-sm); background: var(--warn-dim); color: var(--accent-warn); border: var(--hairline-w) solid var(--accent-warn); font-size: var(--fs-sm); }

/* [CHECKLIST] checklist strategica: spuntabile da op_lead/hq, sola lettura per gli altri. */
.ck-progress { display: flex; align-items: center; justify-content: space-between; gap: var(--space-2); margin-bottom: var(--space-3); font-size: var(--fs-sm); color: var(--text-secondary); }
.ck-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--space-2); }
.ck-empty { color: var(--text-secondary); font-size: var(--fs-sm); padding: var(--space-2) 0; }
.ck-item { display: flex; align-items: flex-start; gap: var(--space-2); padding: var(--space-2) var(--space-3); background: var(--bg-panel-elevated); border: var(--hairline-w) solid var(--hairline); border-radius: var(--r-sm); }
.ck-item[data-done="true"] .ck-label { color: var(--text-secondary); text-decoration: line-through; }
.ck-box {
  flex: 0 0 auto; width: 26px; height: 26px; min-height: 26px; display: inline-flex; align-items: center; justify-content: center;
  border: var(--hairline-w) solid var(--hairline-strong); border-radius: var(--r-sm);
  background: transparent; color: var(--accent-positive); font-family: var(--font-mono); font-size: var(--fs-sm); line-height: 1;
}
button.ck-box { cursor: pointer; }
.ck-item[data-done="true"] .ck-box { border-color: var(--accent-positive); background: var(--positive-dim); }
.ck-label { flex: 1 1 auto; min-width: 0; font-size: var(--fs-sm); line-height: 1.35; overflow-wrap: anywhere; }
.ck-by { flex: 0 0 auto; font-size: var(--fs-xs); color: var(--accent-positive); white-space: nowrap; }
.ck-del { flex: 0 0 auto; background: transparent; border: none; color: var(--text-secondary); cursor: pointer; font-size: var(--fs-sm); padding: 0 var(--space-1); line-height: 1; }
.ck-del:hover { color: var(--accent-negative); }
.ck-add { display: flex; gap: var(--space-2); margin-top: var(--space-3); }
.ck-add .ck-input { flex: 1 1 auto; min-width: 0; }
