:root {
  --bg: #f6f7f8;
  --panel: #ffffff;
  --line: #d8dde3;
  --text: #1d252d;
  --muted: #65717e;
  --accent: #1f6feb;
  --accent-strong: #144d9f;
  --danger: #b42318;
  --warn: #b54708;
  --info: #175cd3;
  --success: #067647;
  --pending: #6f5d00;
  /* Blu istituzionale del materiale Tolleranza Zero (campionato dal mockup). */
  --brand-navy: #06223e;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font: 14px/1.4 Arial, Helvetica, sans-serif;
}

button, input, select, textarea { font: inherit; }
button { cursor: pointer; }

.app-header {
  align-items: center;
  background: var(--panel);
  border-bottom: 1px solid var(--line);
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  gap: 24px;
  padding: 14px 20px;
  position: sticky;
  top: 0;
  z-index: 10;
}
.title-block { justify-self: start; }
.brand-logo { display: block; height: 56px; width: auto; max-width: 100%; }
.brand-title { font-size: 30px; font-weight: 800; letter-spacing: .04em; margin: 0; line-height: 1.05; }
.brand-subtitle { color: var(--muted); font-size: 12px; margin: 2px 0 0; letter-spacing: .01em; }
.system-status { color: var(--muted); margin: 4px 0 0; }
.last-refresh { color: var(--muted); font-size: 12px; margin: 4px 0 0; }

.header-right { justify-self: end; display: flex; flex-direction: column; align-items: flex-end; gap: 8px; }
.header-status { text-align: right; }
.header-status p { margin: 2px 0 0; }

.main-actions, .row-actions { display: flex; gap: 8px; }
.main-actions { align-items: center; flex-wrap: wrap; justify-content: flex-end; }

/* Statistiche operative centrate nella topbar: griglia 2x2 (colonna sinistra = piloti,
   destra = record). Flusso per colonna: le card seguono l'ordine del markup. */
.header-stats {
  justify-self: center;
  display: grid;
  grid-template-rows: 1fr 1fr;
  grid-auto-flow: column;
  gap: 1px;                 /* le fughe mostrano il colore di sfondo come linee divisorie */
  background: var(--line);
  border: 1px solid var(--line);
  border-radius: 12px;
  box-shadow: 0 1px 2px rgba(0, 0, 0, .05);
  overflow: hidden;
}
.stat-card { display: flex; align-items: center; gap: 12px; padding: 10px 22px; background: var(--panel); }
/* Le card sono 5 su una griglia a 2 righe: la quinta lascerebbe una cella vuota (che
   mostrerebbe lo sfondo grigio usato per disegnare le fughe). Occupa entrambe le righe,
   il che le da' anche il risalto che merita, essendo l'unica azionabile. */
.header-stats > #stat-backlog-card { grid-row: span 2; }
.stat-icon {
  width: 40px; height: 40px; flex: 0 0 40px;
  border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
}
.stat-icon svg { width: 22px; height: 22px; }
.stat-icon-flights { background: #e7f0fe; color: var(--accent); }
.stat-icon-operational { background: #eef0f6; color: #5b6b9a; }
.stat-icon-records { background: #e6f6ee; color: var(--success); }
.stat-icon-signaled { background: #fdefe7; color: #c2410c; }
.stat-icon-backlog { background: #f3eefe; color: #6d28d9; }
/* Card cliccabile: porta al filtro corrispondente nello storico. Senza un'affordance
   esplicita sembrava una statistica passiva, quindi porta un pulsante "Vedi". */
.stat-card-action { cursor: pointer; }
.stat-card-action:hover { background: #f7faff; }
.stat-card-action:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.stat-card-action.is-alert .stat-icon-backlog { background: #fdece9; color: var(--danger); }
.stat-card-action.is-alert #stat-backlog { color: var(--danger); }
.stat-action {
  margin-left: auto;
  display: inline-flex; align-items: center; gap: 5px;
  border: 1px solid var(--accent); border-radius: 999px;
  padding: 4px 11px;
  font-size: 12px; font-weight: 700; color: var(--accent);
  background: var(--panel); white-space: nowrap;
}
.stat-action svg { width: 15px; height: 15px; }
.stat-card-action:hover .stat-action { background: var(--accent); color: #fff; }
.stat-card-action.is-alert .stat-action { border-color: var(--danger); color: var(--danger); }
.stat-card-action.is-alert:hover .stat-action { background: var(--danger); color: #fff; }
.stat-body { display: flex; flex-direction: column; line-height: 1.2; }
.stat-label { font-size: 12px; color: var(--muted); }
.stat-value { display: flex; align-items: baseline; gap: 6px; }
.stat-value strong { font-size: 22px; font-weight: 700; color: var(--text); }
.stat-caption { font-size: 12px; font-weight: 600; }
.stat-caption.pos { color: var(--success); }
.stat-caption.neg { color: var(--danger); }
.stat-caption.zero { color: var(--muted); }

/* --- Topbar responsive ---
   La griglia a 3 colonne (marchio | statistiche | azioni) regge solo sopra i ~1340px:
   sotto, la colonna delle azioni si stringe, i sei comandi si impilano in verticale e
   l'header passa da 174px a 235px, fino a 366px a 900px di larghezza.
   Si passa quindi a due righe: marchio + azioni sopra, statistiche a tutta larghezza sotto.
   Soglia misurata: a 1300px l'header e' ancora 235px, a 1360px torna a 174px. */
@media (max-width: 1340px) {
  .app-header {
    grid-template-columns: auto minmax(0, 1fr);
    grid-template-areas:
      'logo actions'
      'stats stats';
    gap: 12px 16px;
  }
  .title-block { grid-area: logo; }
  .header-right { grid-area: actions; }
  .header-stats { grid-area: stats; justify-self: stretch; }
  .brand-logo { height: 46px; }
  /* A tutta larghezza il flusso per colonne lascerebbe una cella vuota (le card sono
     5, dispari): si passa a colonne elastiche che si riempiono sempre. */
  .header-stats {
    grid-template-rows: none;
    grid-auto-flow: row;
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  }
  /* Le card sono 5 e l'ultima riga resta quasi sempre spaiata. Sul desktop le fughe
     sono disegnate dallo sfondo del contenitore, ma qui quello sfondo verrebbe fuori
     come fascia grigia nelle celle vuote: si passa a separatori disegnati dalle card. */
  .header-stats { background: var(--panel); gap: 0; }
  .stat-card { box-shadow: inset -1px 0 0 var(--line), inset 0 -1px 0 var(--line); }
  /* Qui il flusso e' per righe, quindi niente span verticale. In compenso questa card
     porta anche il pulsante "Vedi": in una colonna sola la pill sborda e viene tagliata
     dall'overflow:hidden del contenitore, quindi ne occupa due. */
  .header-stats > #stat-backlog-card { grid-row: auto; grid-column: span 2; }
  /* Le tre righe di stato (data, indirizzo, autosave) in colonna costano ~40px:
     su una riga sola, che va a capo solo se serve. */
  .header-status { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 2px 14px; }
  .header-status p { margin: 0; }
}

@media (max-width: 1000px) {
  /* Card compatte: cosi' le cinque stanno su una riga sola piu' a lungo. */
  .header-stats { grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); }
  .stat-card { padding: 8px 12px; gap: 8px; }
  .stat-icon { width: 30px; height: 30px; flex: 0 0 30px; }
  .stat-icon svg { width: 17px; height: 17px; }
  .stat-value strong { font-size: 18px; }
  .header-right { align-items: stretch; }
  .main-actions { justify-content: flex-start; }
  .header-status { text-align: left; }
}

/* Sotto i 760px la colonna delle azioni non regge sei comandi accanto al marchio:
   si impila tutto in verticale e il marchio si rimpicciolisce. */
@media (max-width: 760px) {
  .app-header {
    grid-template-columns: minmax(0, 1fr);
    grid-template-areas: 'logo' 'actions' 'stats';
    gap: 10px;
    padding: 12px 14px;
  }
  .brand-logo { height: 38px; }
  .header-right { align-items: flex-start; }
  .header-status { justify-content: flex-start; }
  /* 158px: la card "Da completare" deve contenere etichetta e pulsante "Vedi"
     senza mandare a capo il testo. */
  .header-stats { grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); }
  .stat-icon { display: none; }   /* l'etichetta basta: si recupera larghezza */
}

.primary-command, .secondary-command, .row-action, .state-badge {
  border: 1px solid var(--line);
  border-radius: 6px;
  min-height: 32px;
  padding: 6px 10px;
  background: var(--panel);
}
.primary-command { background: var(--accent); border-color: var(--accent); color: #fff; }
.primary-command:hover { background: var(--accent-strong); }
.secondary-command:hover { border-color: var(--accent); }

.quick-launch {
  background: var(--panel);
  border-bottom: 1px solid var(--line);
  padding: 12px 20px;
}
/* Chiuso, resta solo l'intestazione: recupera spazio verticale sugli schermi bassi. */
.quick-launch > summary { cursor: pointer; list-style: none; user-select: none; }
.quick-launch > summary::-webkit-details-marker { display: none; }
.quick-launch > summary::before {
  content: '▸'; display: inline-block; width: 1em;
  transition: transform .15s ease; font-size: 15px;
}
.quick-launch[open] > summary::before { transform: rotate(90deg); }
.quick-launch[open] > summary { margin-bottom: 10px; }
.quick-launch-count { color: var(--muted); font-size: 12px; font-weight: 600; letter-spacing: 0; text-transform: none; }
.quick-launch-count.is-alert { color: var(--danger); }
.pilot-quick-groups { display: flex; flex-direction: column; gap: 8px; width: 100%; }
.pilot-quick-row { display: flex; align-items: baseline; gap: 8px; }
.pilot-quick-category {
  flex: 0 0 110px;
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .03em;
  color: var(--muted);
}
.quick-launch-label {
  color: var(--accent);
  font-size: 18px;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: .04em;
}
.pilot-quick-buttons { display: flex; flex-wrap: wrap; gap: 6px; }
.pilot-quick-button {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 6px;
  color: var(--text);
  font-weight: 600;
  min-height: 30px;
  padding: 4px 10px;
}
.pilot-quick-button:hover { border-color: var(--accent); color: var(--accent); }
.pilot-quick-button:active { background: var(--accent); border-color: var(--accent); color: #fff; }
/* Pilota in volo: pill blu (mantiene il blu anche in hover). */
.pilot-quick-button.is-in-flight,
.pilot-quick-button.is-in-flight:hover { background: var(--accent); border-color: var(--accent); color: #fff; }

/* Alert inattività piloti (sidebar, sopra "Record di oggi") */
.inactivity-alert {
  border: 1px solid var(--warn);
  background: #fff8ef;
  border-radius: 8px;
  padding: 10px 12px;
  margin-bottom: 14px;
}
.inactivity-title { color: var(--warn); margin: 0 0 8px; }
.inactivity-group { margin-bottom: 8px; }
.inactivity-group:last-child { margin-bottom: 0; }
.inactivity-cat {
  display: block; font-size: 11px; font-weight: 700;
  text-transform: uppercase; letter-spacing: .03em; color: var(--muted); margin-bottom: 2px;
}
.inactivity-row { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; padding: 2px 0; }
.inactivity-name { flex: 1; min-width: 0; overflow-wrap: anywhere; }
.inactivity-time { font-variant-numeric: tabular-nums; font-weight: 700; color: var(--warn); white-space: nowrap; }

/* Alert voli aperti oltre la durata massima: stesso box, chiave di lettura "rossa". */
.long-flight-alert { border-color: var(--danger); background: #fdf3f2; }
.long-flight-title { color: var(--danger); margin: 0 0 8px; }
.long-flight-row { cursor: pointer; border-radius: 6px; padding: 3px 4px; }
.long-flight-row:hover { background: #fbe4e2; }
.long-flight-row .inactivity-time { color: var(--danger); }

/* Volo senza streaming: evidenza nella lista di oggi e sulla pill del pilota. */
.record-item.is-no-streaming { border-color: var(--danger); background: #fffafa; }
.no-streaming-badge {
  align-self: flex-start;
  border: 1px solid var(--danger); border-radius: 999px;
  padding: 1px 8px; font-size: 11px; font-weight: 700; color: var(--danger);
}
.pilot-quick-button.is-no-streaming,
.pilot-quick-button.is-no-streaming:hover {
  background: var(--danger); border-color: var(--danger); color: #fff;
}

.app-main {
  display: grid;
  grid-template-columns: 320px minmax(0, 1fr);
  gap: 16px;
  padding: 16px 20px;
  align-items: start;
}
/* minmax(0, 1fr) e non 1fr: una traccia "1fr" vale minmax(auto, 1fr) e non scende sotto
   la larghezza minima del contenuto, quindi la tabella dello storico (11 colonne)
   allargava la pagina invece di scorrere dentro #history-body. */
@media (max-width: 900px) { .app-main { grid-template-columns: minmax(0, 1fr); } }
/* Stessa ragione: colonna flex che deve poter stringersi sotto il suo contenuto. */
.main-column { min-width: 0; }

/* Lista compatta dei record di oggi (colonna laterale). */
.records-sidebar {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 12px;
  position: sticky;
  /* L'header è sticky e cambia altezza col viewport (statistiche che vanno a capo):
     la misura vera la scrive syncStickyOffset() in --sticky-top. */
  top: var(--sticky-top, 84px);
  max-height: calc(100vh - var(--sticky-top, 84px) - 16px);
  overflow: auto;
}
.sidebar-title { font-size: 13px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: var(--muted); margin: 0 0 10px; }
.sidebar-hint { font-weight: 400; font-size: 11px; text-transform: none; letter-spacing: 0; }
.record-list { display: flex; flex-direction: column; gap: 8px; }

.record-item {
  position: relative;
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 8px 10px 8px 38px;
  cursor: pointer;
  background: #fff;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.record-item:hover { border-color: var(--accent); background: #f7faff; }
.record-item.is-selected { border-color: var(--accent); background: #e7effb; }
.record-item-index {
  position: absolute;
  top: 8px;
  left: 8px;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: var(--accent);
  color: #fff;
  font-size: 12px;
  font-weight: 700;
  display: flex;
  align-items: center;
  justify-content: center;
}
.record-item-main { font-weight: 600; }
.record-item-sub { color: var(--muted); font-size: 12px; }
.record-item-code { font-family: "SFMono-Regular", Consolas, monospace; font-size: 11px; color: var(--muted); }
.record-item .row-actions { margin-top: 2px; flex-wrap: wrap; }
.record-item .row-action { padding: 4px 8px; min-height: 0; font-size: 12px; }
.row-action.quick-landing { background: var(--success); border-color: var(--success); color: #fff; font-weight: 700; }
.row-action.quick-landing:hover { background: var(--success); filter: brightness(.95); }

.empty-hint { color: var(--muted); padding: 16px; text-align: center; }

/* Colonna principale: compilazione (sopra) + storico (sotto). */
.main-column { display: flex; flex-direction: column; gap: 16px; }

.editor-area {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 20px 24px;
}

.history-area {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 16px 20px 20px;
}
.history-body { overflow: auto; }

.data-table { border-collapse: collapse; width: 100%; }
.data-table th, .data-table td { border-bottom: 1px solid var(--line); padding: 7px 10px; text-align: left; vertical-align: middle; font-size: 13px; }
.data-table th { color: var(--muted); font-size: 11px; text-transform: uppercase; letter-spacing: .03em; }
.data-table tbody tr:hover td { background: #f0f4fb; }
.data-table .num-col { width: 36px; color: var(--muted); }

.section-title { font-size: 18px; font-weight: 700; margin: 0 0 14px; }

/* Form di compilazione a griglia responsive (sfrutta la larghezza dell'area principale). */
.edit-form { display: block; }
.field--wide { grid-column: 1 / -1; }
.edit-form .field { margin-bottom: 0; }
.edit-form > .field { margin-top: 12px; }   /* Note Operative, fuori categoria */

/* Categorie a scomparsa del pannello di compilazione */
.panel-category { border: 1px solid var(--line); border-radius: 8px; margin-bottom: 12px; background: var(--panel); }
.panel-category > summary {
  cursor: pointer; list-style: none; user-select: none;
  padding: 9px 12px; font-size: 12px; font-weight: 700;
  text-transform: uppercase; letter-spacing: .03em;
  background: var(--accent); color: #fff; border-radius: 7px;
}
.panel-category > summary:hover { background: var(--accent-strong); }
.panel-category > summary::-webkit-details-marker { display: none; }
.panel-category > summary::before { content: '▸'; display: inline-block; width: 1em; transition: transform .15s ease; }
.panel-category[open] > summary::before { transform: rotate(90deg); }
.panel-category[open] > summary { border-radius: 7px 7px 0 0; }
/* Il corpo della categoria è una colonna di righe; ogni riga è la griglia auto-fill
   che prima stava sul corpo, così le categorie senza renderer dedicato non cambiano. */
.panel-category-body { display: flex; flex-direction: column; gap: 14px; padding: 12px; }
.panel-row {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: 12px 20px;
  align-items: start;
}
.panel-row-title {
  grid-column: 1 / -1;
  font-size: 11px; font-weight: 700; text-transform: uppercase;
  letter-spacing: .03em; color: var(--muted);
}

/* Riga dei canali di segnalazione: un riquadro per canale, affiancati finché c'è
   spazio. Sotto i 260px per riquadro si impilano (ripiego a riga piena). */
.panel-row-signals { grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); }
.signal-pair {
  border: 1px solid var(--line); border-radius: 8px;
  padding: 8px 10px 10px; background: #fbfcfd;
  display: flex; flex-direction: column; gap: 8px;
}
.signal-pair-label {
  font-size: 11px; font-weight: 700; text-transform: uppercase;
  letter-spacing: .03em; color: var(--text);
}
.signal-pair .field { margin-bottom: 0; }

/* Sotto-gruppi del blocco Trasmissione (Registrazione / Masterizzazione). */
.panel-group {
  border: 1px solid var(--line); border-radius: 8px;
  padding: 8px 10px 10px; background: #fbfcfd;
  display: flex; flex-direction: column; gap: 10px;
}
.panel-group-title {
  font-size: 11px; font-weight: 700; text-transform: uppercase;
  letter-spacing: .03em; color: var(--text);
}
/* Finestra temporale ammessa dal gruppo: la regola detta prima dell'errore. */
.panel-group-hint { margin: -4px 0 0; color: var(--muted); font-size: 12px; }
/* Coppia data+ora su una riga, con la scorciatoia "Adesso" in fondo. */
.datetime-pair {
  display: grid;
  grid-template-columns: 56px minmax(120px, 1fr) minmax(90px, .7fr) auto;
  gap: 8px; align-items: end;
}
.datetime-pair-label { font-size: 12px; font-weight: 700; color: var(--muted); padding-bottom: 8px; }
.datetime-pair .field { margin-bottom: 0; }
.datetime-now { white-space: nowrap; }
@media (max-width: 640px) {
  .datetime-pair { grid-template-columns: 1fr 1fr; }
  .datetime-pair-label { grid-column: 1 / -1; padding-bottom: 0; }
  .datetime-now { grid-column: 1 / -1; }
}

.state-details { border: 1px solid var(--line); border-radius: 8px; padding: 10px 12px; margin-bottom: 14px; background: #fafbfc; }
.state-details p { margin: 4px 0 0; color: var(--muted); }
/* Badge e codice volo sulla stessa riga: nella barra agganciata l'altezza è spazio
   sottratto al form, e le due informazioni si leggono insieme. */
.state-details-head { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; }
.state-details-head .code-cell { margin: 0; }

/* Titolo + stato restano agganciati in alto mentre si scorre il pannello: il badge dice
   dinamicamente a che punto è la procedura e cosa manca, ed è compilando i campi in
   fondo che serve saperlo. Sborda sui lati per coprire i campi che passano sotto. */
.panel-sticky {
  position: sticky;
  top: var(--sticky-top, 84px);
  z-index: 5;
  background: var(--panel);
  margin: -20px -24px 0;
  padding: 16px 24px 0;
  border-radius: 10px 10px 0 0;
  border-bottom: 1px solid var(--line);
}
.panel-sticky .state-details { margin-bottom: 12px; }
/* Il messaggio di stato può essere lungo: due righe al massimo, il resto è nel title. */
.panel-sticky .state-details p:not(.code-cell) {
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
@media (max-width: 900px) { .panel-sticky { position: static; margin: 0; padding: 0; border-bottom: 0; } }

.state-badge { display: inline-block; font-weight: 600; }
.severity-error { border-color: var(--danger); color: var(--danger); }
.severity-warning { border-color: var(--warn); color: var(--warn); }
.severity-info { border-color: var(--info); color: var(--info); }
.severity-success { border-color: var(--success); color: var(--success); }
.severity-pending { border-color: var(--pending); color: var(--pending); }

.field { display: flex; flex-direction: column; gap: 4px; margin-bottom: 12px; }
.field-label { color: var(--muted); font-size: 12px; font-weight: 600; display: flex; justify-content: space-between; align-items: baseline; gap: 8px; }
.field-status { font-size: 11px; color: var(--muted); }
.field-status.saving { color: var(--info); }
.field-status.saved { color: var(--success); }
.field-status.dirty { color: var(--warn); }
.field-status.error { color: var(--danger); }
.field.is-missing .field-label { color: var(--warn); }

.field input, .field select, .field textarea {
  border: 1px solid var(--line);
  border-radius: 6px;
  padding: 7px 9px;
  width: 100%;
  background: #fff;
}
.field input:focus, .field select:focus, .field textarea:focus { outline: 2px solid var(--accent); border-color: var(--accent); }
.field textarea { min-height: 60px; resize: vertical; }

/* Interruttore Sì/No: binario nel valore, a tre stati nell'aspetto. Il tratteggio
   del campo mai compilato è l'unico segnale che non dipende dal colore, quindi
   resta leggibile anche a chi non distingue il verde dal rosso. */
.switch {
  display: inline-flex; align-items: center; gap: 8px;
  border: 0; background: transparent; padding: 2px 0; cursor: pointer;
  align-self: flex-start;
}
.switch-track {
  position: relative; flex: 0 0 auto; width: 40px; height: 22px; border-radius: 11px;
  border: 1px solid var(--line); background: #f2f4f7;
  transition: background-color .12s ease, border-color .12s ease;
}
.switch-knob {
  position: absolute; top: 2px; left: 2px; width: 16px; height: 16px; border-radius: 50%;
  background: #fff; border: 1px solid var(--line);
  transition: transform .12s ease, border-color .12s ease;
}
.switch-label { font-size: 12px; font-weight: 700; color: var(--muted); }
.switch:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 6px; }

/* Mai compilato: nessun colore, bordo tratteggiato, cursore a metà corsa. */
.switch.is-empty .switch-track { border-style: dashed; background: #fff; }
.switch.is-empty .switch-knob { transform: translateX(9px); border-style: dashed; }

/* Convenzione unica in tutta la compilazione: 'Sì' = verde, 'No' = rosso. */
.switch.is-yes .switch-track { background: #ecfdf3; border-color: var(--success); }
.switch.is-yes .switch-knob { transform: translateX(18px); border-color: var(--success); }
.switch.is-yes .switch-label { color: var(--success); }
.switch.is-no .switch-track { background: #fef3f2; border-color: var(--danger); }
.switch.is-no .switch-knob { transform: translateX(0); border-color: var(--danger); }
.switch.is-no .switch-label { color: var(--danger); }

@media (prefers-reduced-motion: reduce) {
  .switch-track, .switch-knob { transition: none; }
}

.panel-notice { border-radius: 6px; padding: 8px 10px; margin-bottom: 12px; display: flex; justify-content: space-between; gap: 10px; }
.panel-notice-error { background: #fef3f2; color: var(--danger); border: 1px solid var(--danger); }
.panel-notice-warning { background: #fffaeb; color: var(--warn); border: 1px solid var(--warn); }
.panel-notice-info { background: #eff8ff; color: var(--info); border: 1px solid var(--info); }
.panel-notice-close { background: transparent; border: 0; color: inherit; font-weight: 700; }

/* Avviso transitorio ancorato in basso a destra, sopra a tutto: in cima alla pagina
   passava inosservato mentre l'operatore stava guardando il campo appena compilato. */
.ui-notice {
  position: fixed; right: 16px; bottom: 16px; z-index: 60;
  max-width: min(420px, calc(100vw - 32px));
  border-radius: 8px; padding: 10px 14px;
  font-weight: 600; line-height: 1.35;
  box-shadow: 0 8px 24px rgba(16, 24, 40, .18);
  animation: ui-notice-in .16s ease-out;
}
.ui-notice.warning { background: #fffaeb; color: var(--warn); border: 1px solid var(--warn); }
.ui-notice.error { background: #fef3f2; color: var(--danger); border: 1px solid var(--danger); }
@keyframes ui-notice-in {
  from { opacity: 0; transform: translateY(8px); }
  to { opacity: 1; transform: translateY(0); }
}
@media (prefers-reduced-motion: reduce) { .ui-notice { animation: none; } }

.row-action { background: var(--panel); }
.row-action.danger { color: var(--danger); border-color: var(--danger); }
/* Barra azioni sotto un campo: i pulsanti mantengono la loro altezza naturale invece
   di stirarsi a quella del più alto (Telemetria e "Adesso" convivono qui). */
.position-actions { align-items: center; }
/* "Adesso": scorciatoia, non azione principale. Deve stare accanto al campo senza
   competere con esso, quindi resta più piccola dei pulsanti di riga. */
.row-action.time-now { padding: 3px 8px; min-height: 0; font-size: 12px; }
.row-action.is-loading { cursor: progress; opacity: .8; }
/* Spinner inline per i pulsanti in caricamento (es. Posizione da Zello). */
.btn-spinner {
  display: inline-block; width: 12px; height: 12px; vertical-align: -2px;
  border: 2px solid currentColor; border-right-color: transparent; border-radius: 50%;
  animation: btn-spin .6s linear infinite;
}
@keyframes btn-spin { to { transform: rotate(360deg); } }

.code-cell { font-family: "SFMono-Regular", Consolas, monospace; font-size: 12px; }

[hidden] { display: none !important; }
.history-filters { display: flex; gap: 10px; flex-wrap: wrap; align-items: flex-end; margin-bottom: 12px; }
.history-filters label { display: flex; flex-direction: column; gap: 4px; font-size: 12px; color: var(--muted); }
.history-filters .grow { flex: 1; min-width: 160px; }
.history-filters input, .history-filters select { border: 1px solid var(--line); border-radius: 6px; padding: 6px 8px; }

/* Piè di pagina dello storico: conteggio + "Carica altre" (lo storico è paginato). */
.history-footer {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; flex-wrap: wrap; margin-top: 10px;
}
.history-count { color: var(--muted); font-size: 12px; }

/* Filtro "Da completare": chip cliccabile invece della checkbox nuda. */
.history-filters label.history-chip {
  flex-direction: row; align-items: center; gap: 6px;
  border: 1px solid var(--line); border-radius: 999px;
  padding: 7px 12px; background: var(--panel);
  color: var(--text); font-weight: 600; cursor: pointer; user-select: none;
}
.history-filters label.history-chip:hover { border-color: var(--warn); color: var(--warn); }
.history-filters label.history-chip input { padding: 0; accent-color: var(--warn); cursor: pointer; }
.history-filters label.history-chip.is-active {
  border-color: var(--warn); background: #fff8ef; color: var(--warn);
}

/* Popup Sintesi (modale) */
.modal-backdrop {
  position: fixed; inset: 0; z-index: 100;
  background: rgba(15, 23, 31, .45);
  display: flex; align-items: center; justify-content: center;
  padding: 20px;
}
.summary-dialog {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 10px;
  box-shadow: 0 12px 40px rgba(0, 0, 0, .3);
  width: 100%; max-width: 560px; max-height: 85vh;
  display: flex; flex-direction: column;
}
.summary-dialog-header {
  display: flex; align-items: center; justify-content: space-between;
  padding: 14px 18px; border-bottom: 1px solid var(--line);
}
.summary-dialog-title { margin: 0; font-size: 18px; font-weight: 700; }
.summary-dialog-close {
  background: none; border: none; color: var(--muted);
  font-size: 24px; line-height: 1; padding: 0 4px;
}
.summary-dialog-close:hover { color: var(--text); }
.summary-dialog-body { padding: 16px 18px; overflow-y: auto; }
.summary-dialog-body .state-details { margin-bottom: 12px; }

/* ===================== autenticazione + lock di editing ===================== */

/* Header: operatore connesso e logout */
.current-user {
  align-self: center;
  color: var(--muted);
  font-weight: 700;
  padding-left: 4px;
}
.logout-form { margin: 0; }

/* Login: marchio easycity in alto, card centrale, Tolleranza Zero in basso,
   su fondo blu istituzionale. I due marchi hanno inchiostro chiaro (bianco/rosso),
   il logo S.C.O.P.E. e' scuro e resta dentro la card bianca. */
.login-body {
  /* Tre righe: il logo in alto e quello in basso occupano due bande di uguale
     altezza (1fr) ai lati della card (auto), che resta centrata verticalmente.
     Ciascun logo e' poi centrato dentro la propria banda: cosi' i marchi sono
     equidistanti dalla card e dai bordi, con piu' respiro verticale. */
  display: grid;
  grid-template-rows: 1fr auto 1fr;
  justify-items: center;
  align-items: center;
  /* Le misure dei marchi sono legate all'altezza della finestra: sui 1366x768 delle
     postazioni di sala i tre blocchi devono stare tutti a schermo, senza scroll. */
  min-height: 100vh;
  padding: clamp(12px, 2.2vh, 32px) 20px;
  background: var(--brand-navy);
}
/* Marchi dimensionati in ALTEZZA sul viewport: su schermi bassi si stringono da soli
   invece di spingere il logo in fondo fuori dallo schermo. */
.login-brand { display: block; width: auto; max-width: 88vw; object-fit: contain; }
.login-brand-top { height: clamp(46px, 13vh, 128px); }
/* easycity in fondo, volutamente più piccolo del marchio in alto. */
.login-brand-bottom { height: clamp(24px, 6vh, 52px); }

.login-card {
  background: var(--panel);
  border-radius: 22px;
  box-shadow: 0 18px 50px rgba(0, 0, 0, .35);
  padding: 12px;
  width: 100%;
  max-width: 330px;
}
/* Pannello interno leggermente incassato, come nel mockup. */
.login-panel {
  background: #fbfbfc;
  border: 1px solid var(--line);
  border-radius: 14px;
  padding: 16px 14px;
}
.login-logo { display: block; width: 88%; max-width: 240px; height: auto; margin: 6px auto 10px; }
/* Usato da "Cambia password", che condivide card e pannello con l'accesso.
   Nella login non c'e': ripeterebbe il logo S.C.O.P.E. appena sopra. */
.login-title { font-size: 16px; font-weight: 700; margin: 0 0 2px; letter-spacing: .02em; }
.login-subtitle { color: var(--text); font-size: 13px; font-weight: 600; margin: 0 0 12px; }
.login-title + .login-subtitle { color: var(--muted); font-weight: 400; }
.login-form { display: flex; flex-direction: column; gap: 10px; }
.login-form label { display: flex; flex-direction: column; gap: 4px; font-size: 13px; color: var(--muted); }
.login-form input[type="text"],
.login-form input[type="password"] {
  border: 1px solid var(--line);
  border-radius: 6px;
  min-height: 36px;
  padding: 6px 10px;
}
.login-remember { flex-direction: row !important; align-items: center; gap: 6px; }
.login-form .primary-command { margin-top: 6px; min-height: 38px; }
.login-error {
  background: #fdecea;
  border: 1px solid var(--danger);
  border-radius: 6px;
  color: var(--danger);
  margin-bottom: 14px;
  padding: 8px 10px;
}
.login-hint { color: var(--muted); font-size: 12px; margin: 0 0 14px; }

/* Pannello di editing: intestazione con pulsante Chiudi */
.panel-head {
  align-items: center;
  display: flex;
  gap: 12px;
  justify-content: space-between;
}
.panel-exit { min-height: 30px; }

/* Indicatore "in modifica da un altro operatore" */
.record-item-lock {
  color: var(--warn);
  font-size: 12px;
  font-weight: 700;
  margin-top: 4px;
}


/* =======================================================================
   Schermo di sala (/dashboard) — sola visione, letta da 3-4 metri.
   Riusa i token e i componenti della console (stat-card, inactivity-alert,
   state-badge): qui ci sono la fascia dei marchi, i contatori ingranditi e
   la griglia dei voli. Le misure sono in clamp() sulla larghezza del
   viewport, cosi' la stessa pagina regge un 1080p in sala e un 4K.
   ======================================================================= */

.dashboard-body { min-height: 100vh; display: flex; flex-direction: column; }

/* --- Topbar: marchio, contatori, orologio ------------------------------- */

/* Stessa veste della topbar del portale (fondo chiaro + filetto): chi passa dalla
   console allo schermo di sala deve riconoscere la stessa applicazione. Il logo
   S.C.O.P.E. ha inchiostro scuro e qui sta bene senza card. */
.dash-header {
  display: flex;
  align-items: center;
  gap: clamp(12px, 1.6vw, 30px);
  padding: clamp(8px, .9vw, 16px) clamp(12px, 1.4vw, 24px);
  background: var(--panel);
  border-bottom: 1px solid var(--line);
}
.dash-brand { flex: 0 0 auto; }
.dash-brand img { display: block; height: clamp(32px, 2.6vw, 52px); width: auto; }

.dash-clock { display: flex; flex-direction: column; align-items: flex-end; gap: 2px; }
.dash-time { font-size: clamp(24px, 2.2vw, 40px); font-weight: 800; font-variant-numeric: tabular-nums; line-height: 1; }
/* nowrap: sono due righe di servizio, se vanno a capo alzano tutta la fascia. */
.dash-date, .dash-status { font-size: clamp(11px, .8vw, 14px); white-space: nowrap; color: var(--muted); }
.dash-date strong { color: var(--text); }

/* Tasto logout della sala: volutamente minuscolo e defilato — non deve competere
   con l'orologio né con i contatori. flex: 0 0 auto per non allargare la fascia. */
.dash-logout { flex: 0 0 auto; }
.dash-logout button {
  font-size: 11px;
  line-height: 1;
  padding: 4px 8px;
  color: var(--muted);
  background: transparent;
  border: 1px solid var(--line);
  border-radius: 6px;
  cursor: pointer;
}
.dash-logout button:hover { color: var(--text); border-color: var(--muted); }

/* I contatori sono il contenuto principale della fascia: prendono tutto lo
   spazio disponibile e restano SEMPRE in fila a colonne uguali. In console
   .header-stats ha tre media query che fanno l'opposto (righe elastiche,
   arretrati a cavallo di due colonne): qui la griglia va ridichiarata per
   intero, altrimenti quelle regole rientrano dalla finestra. */
.dashboard-body .header-stats {
  flex: 1 1 auto;
  min-width: 0;
  grid-template-rows: 1fr;
  grid-template-columns: none;
  grid-auto-flow: column;
  grid-auto-columns: minmax(0, 1fr);
  background: var(--line);
  gap: 1px;
}
.dashboard-body .stat-card {
  box-shadow: none;
  min-width: 0;
  gap: clamp(8px, .8vw, 16px);
  padding: clamp(8px, .9vw, 18px) clamp(10px, 1.1vw, 22px);
}
/* Il numero e' cio' che si legge da lontano: grande quanto l'orologio. */
.dashboard-body .stat-value strong { font-size: clamp(28px, 2.6vw, 52px); line-height: 1; }
.dashboard-body .stat-label { font-size: clamp(11px, .95vw, 17px); font-weight: 600; }
.dashboard-body .stat-caption { font-size: clamp(10px, .8vw, 15px); }
.dashboard-body .stat-body { gap: 2px; }
.dashboard-body .stat-icon {
  width: clamp(32px, 3vw, 58px); height: clamp(32px, 3vw, 58px);
  flex: 0 0 clamp(32px, 3vw, 58px);
}
.dashboard-body .stat-icon svg { width: 55%; height: 55%; }

/* --- Griglia dei voli in corso ------------------------------------------ */

.dash-main { flex: 1; padding: 10px clamp(10px, 1.2vw, 22px); }
/* Quattro per riga: card piu' piccole, ma una giornata piena resta a schermo
   senza scroll (12 voli = 3 righe). */
.dash-flights {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: clamp(8px, .8vw, 14px);
}
.dash-empty { color: var(--muted); font-size: clamp(16px, 1.6vw, 26px); padding: clamp(24px, 5vh, 80px); text-align: center; }

.dash-card {
  background: var(--panel);
  border: 1px solid var(--line);
  border-left: 5px solid var(--accent);
  border-radius: 10px;
  padding: clamp(8px, .7vw, 14px) clamp(9px, .85vw, 16px);
  display: flex;
  flex-direction: column;
  gap: 5px;
  box-shadow: 0 1px 2px rgba(0, 0, 0, .05);
}
/* Volo senza streaming: stessa chiave di lettura della lista in console. */
.dash-card.is-no-streaming { border-color: var(--danger); border-left-color: var(--danger); background: #fffafa; }

.dash-card-head { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; }
.dash-who { display: flex; align-items: center; gap: 7px; min-width: 0; }
/* Icona drone accanto all'alias del pilota: rossa quando il volo non trasmette. */
.dash-drone-icon {
  width: clamp(15px, 1.25vw, 23px); height: clamp(15px, 1.25vw, 23px);
  flex: 0 0 auto; color: var(--accent);
}
.dash-card.is-no-streaming .dash-drone-icon { color: var(--danger); }
.dash-pilot { font-size: clamp(15px, 1.25vw, 23px); font-weight: 800; line-height: 1.1; overflow-wrap: anywhere; }
.dash-elapsed {
  font-size: clamp(17px, 1.45vw, 27px); font-weight: 800;
  font-variant-numeric: tabular-nums; white-space: nowrap; color: var(--accent);
}
/* Oltre la durata massima: e' lo stesso volo che compare nell'alert qui sopra. */
.dash-elapsed.is-late { color: var(--danger); }

.dash-badges { display: flex; flex-wrap: wrap; align-items: center; gap: 5px; }
.dash-badges .state-badge { font-size: clamp(10px, .8vw, 14px); min-height: 0; padding: 3px 7px; }
.dash-badges .no-streaming-badge { font-size: clamp(10px, .75vw, 13px); }

.dash-place { font-size: clamp(13px, 1vw, 19px); font-weight: 600; overflow-wrap: anywhere; }

.dash-tlm { display: flex; flex-wrap: wrap; align-items: center; gap: 5px; }
.dash-drone { color: var(--muted); font-size: clamp(11px, .8vw, 15px); }
.dash-chip {
  border: 1px solid var(--line); border-radius: 999px;
  padding: 1px 8px;
  font-size: clamp(11px, .82vw, 15px); font-weight: 700;
  font-variant-numeric: tabular-nums; white-space: nowrap;
}
.dash-chip.is-low { border-color: var(--danger); color: var(--danger); }
.dash-chip.is-rec { border-color: var(--danger); background: var(--danger); color: #fff; }
/* Campione vecchio o assente: il drone e' spento o senza rete. Non si mostra
   una batteria di mezz'ora fa come se fosse attuale. */
.dash-chip.is-stale { border-color: var(--warn); color: var(--warn); font-weight: 600; }

.dash-foot {
  display: flex; flex-wrap: wrap; justify-content: space-between; gap: 1px 8px;
  margin-top: auto;
  color: var(--muted); font-size: clamp(10px, .75vw, 13px);
}
.dash-code { font-family: "Courier New", monospace; overflow-wrap: anywhere; }

/* --- Fascia dei marchi istituzionali, in fondo -------------------------- */

/* Inchiostro bianco su fondo blu. Un'unica tela combinata già allineata: si
   dimensiona in altezza sul viewport (è molto larga, ~7.8:1, quindi altezza
   contenuta) con un tetto in larghezza per non sforare su schermi stretti. */
.dash-marks {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: clamp(8px, .9vw, 16px);
  background: var(--brand-navy);
}
.dash-mark {
  display: block;
  width: auto;
  height: clamp(30px, 2.8vw, 54px);
  max-width: 92vw;
  object-fit: contain;
}

/* Sotto i ~1650px le cinque etichette non stanno accanto all'icona senza andare
   a capo: si toglie l'icona, che e' decorativa (stessa scelta della topbar in
   console). Sotto i ~1100px i voli passano a due per riga. */
@media (max-width: 1650px) {
  .dashboard-body .stat-icon { display: none; }
}
@media (max-width: 1100px) {
  .dash-flights { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 700px) {
  .dash-flights { grid-template-columns: minmax(0, 1fr); }
}

/* --- Vista mappa dello schermo di sala (toggle Voli/Mappa) --------------- */

/* Toggle nella topbar, fra i contatori e l'orologio. */
.dash-viewswitch {
  display: inline-flex;
  border: 1px solid var(--line); border-radius: 999px;
  padding: 2px; background: var(--bg); flex: 0 0 auto;
}
.dash-viewbtn {
  border: none; background: transparent; border-radius: 999px;
  padding: clamp(5px, .5vw, 9px) clamp(12px, 1vw, 20px);
  font-size: clamp(12px, .95vw, 16px); font-weight: 700; color: var(--muted);
}
.dash-viewbtn.is-active { background: var(--accent); color: #fff; }

/* Le due viste riempiono l'intero <main> (flex column): la vista attiva è flex:1,
   quella nascosta è display:none e non partecipa. height:100% non basta perché
   l'altezza del main non è "definita" per la risoluzione delle percentuali —
   il flex sì, e fa arrivare la mappa a piena altezza. */
.dashboard-body .dash-main { display: flex; flex-direction: column; min-height: 0; }
.dash-view { flex: 1; min-height: 0; }
.dash-view[hidden] { display: none; }
/* La griglia card scorre internamente se serve; la mappa riempie tutto il riquadro. */
#dash-view-flights { overflow: auto; }
#dash-view-map { display: flex; }
.dash-map { flex: 1; width: 100%; min-height: 0; border-radius: 10px; overflow: hidden; border: 1px solid var(--line); }

/* Marker drone: stessa icona e stessi colori delle card. Il divIcon di Leaflet non
   ha stile proprio, quindi lo diamo qui. Colore = accent; grigio se il segnale è
   vecchio. La rotazione per heading sta sul wrapper interno. */
.dash-marker { color: var(--accent); }
.dash-marker .dash-marker-rot { width: 40px; height: 40px; }
.dash-marker .dash-marker-rot img {
  width: 40px; height: 40px; display: block; object-fit: contain;
  filter: drop-shadow(0 1px 2px rgba(0, 0, 0, .5));
}
/* Nome pilota sotto l'icona, sempre visibile e SEMPRE dritto (fuori dal wrapper
   che ruota per heading). Pillola chiara con testo scuro: leggibile sia su strade
   sia su satellite. pointer-events:none per non intercettare pan/zoom della mappa. */
.dash-marker-label {
  position: absolute;
  top: 40px; left: 20px; transform: translateX(-50%);
  white-space: nowrap;
  font: 700 clamp(9px, .62vw, 12px)/1.15 Arial, Helvetica, sans-serif;
  color: var(--text);
  background: rgba(255, 255, 255, .9);
  padding: 1px 7px; border-radius: 7px;
  box-shadow: 0 1px 3px rgba(0, 0, 0, .35);
  pointer-events: none;
}

/* --- Marker segnalazione (record di oggi, per «Evento Osservato») -------- */
/* Icona-immagine (PNG/GIF) da public/icons per le categorie mappate; per il resto
   un esclamativo SVG inline. Sotto, il comune, sempre visibile (kiosk senza mouse).
   Il divIcon di Leaflet non ha stile proprio: lo diamo qui. */
.dash-evento-icon {
  width: 38px; height: 38px; display: block; object-fit: contain;
  filter: drop-shadow(0 1px 2px rgba(0, 0, 0, .55));
}
/* Esclamativo generico: triangolo ambra con "!" bianco, contorno chiaro. */
.dash-segn-excl {
  width: 32px; height: 32px;
  filter: drop-shadow(0 1px 2px rgba(0, 0, 0, .55));
}
.dash-segn-excl .excl-bg { fill: #f59e0b; stroke: #fff; stroke-width: 1.4; stroke-linejoin: round; }
.dash-segn-excl .excl-mark { fill: #fff; }
.dash-fire-label {
  color: #7c2d12;                /* testo caldo scuro per le segnalazioni */
  top: 38px;
}

/* --- Marker pilota (posizione Zello) ------------------------------------ */
/* Icona-immagine da public/icons/pilot.png, distinta dal drone. Nome sotto, sempre
   visibile (kiosk senza mouse). */
.dash-pilota img {
  width: 26px; height: 26px; display: block; object-fit: contain;
  filter: drop-shadow(0 1px 2px rgba(0, 0, 0, .5));
}
.dash-pilota-label { top: 26px; color: var(--text); }

/* --- Aree operative CALA (poligoni) ------------------------------------- */
/* Etichetta centrata sul poligono: si toglie la "pillola" del tooltip di Leaflet
   e si lascia il solo testo con alone bianco + ombra, leggibile su strade e su
   satellite. La freccetta del tooltip va nascosta. */
.leaflet-tooltip.zone-label {
  background: transparent;
  border: none;
  box-shadow: none;
  padding: 0;
  color: #4c1d95;
  font: 700 clamp(8px, .48vw, 11px)/1 Arial, Helvetica, sans-serif;
  letter-spacing: .02em;
  text-shadow: 0 0 2px #fff, 0 0 2px #fff, 0 1px 1px rgba(0, 0, 0, .4);
  pointer-events: none;
}
.leaflet-tooltip.zone-label::before { display: none; }
