/* ======================================================================
   Unitec HelpDesk — frontend unificato (Chat + Voce)
   Design system condiviso (estratto dalla chatbot) + stili modalità voce.
   ====================================================================== */

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

:root {
    /* Brand palette — Unitec corporate (blu estratto dal logo #003a79) */
    --paper: #ffffff;
    --paper-2: #f5f6f7;
    --paper-3: #eaecef;
    --blue: #003a79;
    --blue-dim: #002c5e;
    --ink: #0f1e33;
    --ink-dim: #48576e;
    --fog: #7a8594;
    --rule: #e5e7eb;
    --rule-ink: #003a79;
    --rosso: #c8102e;
    --rosso-dim: #a00d26;

    /* 4 aree assistente tecnico — palette monocroma blu Unitec */
    --mecc: #2e4a73;
    --mecc-bg: rgba(46, 74, 115, 0.08);
    --elet: #003a79;
    --elet-bg: rgba(0, 58, 121, 0.08);
    --elettron: #1d7ccc;
    --elettron-bg: rgba(29, 124, 204, 0.08);
    --tracc: #0e7b8f;
    --tracc-bg: rgba(14, 123, 143, 0.08);
    --verde: #1f9966;
    /* «Attenzione» non aveva un colore nel sistema: il prodotto finora diceva
       solo «va» o «non va». Lo stato del servizio ha un gradino in mezzo (il
       servizio risponde, ma lento), e senza un token qui sarebbe finito come
       valore letterale dentro una schermata — fuori dal sistema, invisibile a
       chi domani cambia la palette. Ambra scura, non gialla: sul bianco il
       giallo puro non si legge. */
    --ambra: #a8620a;
    --ambra-bg: rgba(168, 98, 10, 0.10);

    /* Unico font del prodotto: Lato (stack Unitec). La gerarchia titoli/etichette/
       paragrafi si fa con peso, dimensione, spaziatura e maiuscolo — non con un
       secondo typeface. --mono resta per compat dei tanti usi esistenti, ma punta
       allo stesso stack (le "etichette tecniche" restano tali via letter-spacing
       + uppercase, in Lato). */
    --sans: 'Lato', Helvetica, Arial, Lucida, sans-serif;
    --mono: 'Lato', Helvetica, Arial, Lucida, sans-serif;

    /* Elevazione — sistema Apple-style: ombre NEUTRE, morbide, stratificate
       (ambient diffusa + contatto stretta), bassa opacità. Niente tinte forti
       che "colano" sugli elementi sotto. Raggi gentili coerenti col brand. */
    /* Altezza di una finestra d'elenco. Su :root e non su una
       schermata: gli elenchi vivono in quattro viste diverse, e una
       `var()` che non risolve non è un errore per il browser — la
       dichiarazione sparisce e resta il vuoto.

       ⚠️ Relativa alla finestra, non fissa. Con 26rem fissi il primo
       elenco si mangiava mezzo schermo e il titolo del secondo finiva
       sotto la piega: per passare da «Sessioni attive» a «Tentativi di
       accesso» bisognava scorrere, che è esattamente ciò che queste
       finestre dovevano evitare. Il `clamp` tiene il pavimento (su uno
       schermo basso resta leggibile) e il soffitto (su un monitor alto
       non diventa di nuovo una pagina). */
    --finestra-elenco: clamp(9rem, 22dvh, 18rem);
    /* Le righe delle credenziali sono alte il doppio di una riga di log — due
       livelli di testo più un bottone — e a 22dvh se ne vedeva una e mezzo,
       con quella tagliata a metà che sembra un difetto. Su una schermata con
       due soli elenchi la finestra può respirare.
       ⚠️ Sta su `:root` come l'altra, non sulla sezione «Credenziali»: una var()
       dichiarata su un id non vale per nessun altro, e quando un domani il
       componente viene riusato altrove la dichiarazione sparisce in silenzio
       — a schermo resta il vuoto, e il browser non lo segnala. */
    --finestra-elenco-alta: clamp(14rem, 42dvh, 30rem);

    --radius-sm: 8px;
    --radius-md: 12px;
    --radius-lg: 18px;
    --elev-1: 0 1px 2px rgba(15, 30, 51, 0.05), 0 2px 6px rgba(15, 30, 51, 0.05);
    --elev-2: 0 2px 6px rgba(15, 30, 51, 0.06), 0 10px 24px -6px rgba(15, 30, 51, 0.10);
    --elev-3: 0 4px 10px rgba(15, 30, 51, 0.07), 0 20px 40px -12px rgba(15, 30, 51, 0.13);
    --elev-hover: 0 6px 14px rgba(15, 30, 51, 0.08), 0 26px 52px -14px rgba(0, 58, 121, 0.18);

    --amp: 0;
    color-scheme: light;
}

html, body { height: 100%; }

body {
    background: var(--paper);
    color: var(--ink);
    font-family: var(--sans);
    font-feature-settings: "ss01", "cv11";
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    overflow: hidden;
}

.hidden { display: none !important; }

/* ====================================================== */
/* MONO / EYEBROW UTILITIES                                */
/* ====================================================== */
.eyebrow {
    font-family: var(--mono);
    font-size: 11px;
    font-weight: 500;
    text-transform: uppercase;
    letter-spacing: 0.14em;
    color: var(--ink-dim);
}
.eyebrow.dim { color: var(--fog); }

.pulse-dot {
    display: inline-block;
    width: 7px;
    height: 7px;
    background: var(--blue);
    border-radius: 50%;
    margin-right: 8px;
    vertical-align: middle;
    animation: pulse 1.8s ease-in-out infinite;
    position: relative;
    top: -1px;
}
@keyframes pulse {
    0%, 100% { box-shadow: 0 0 0 0 rgba(0, 58, 121, 0.45); }
    50% { box-shadow: 0 0 0 7px rgba(0, 58, 121, 0); }
}

/* ====================================================== */
/* START SCREEN                                            */
/* ====================================================== */
.start {
    height: 100dvh;
    display: grid;
    grid-template-rows: auto 1fr auto;
    padding: 40px 56px 32px;
    max-width: 1280px;
    margin: 0 auto;
}

.start-head {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding-bottom: 20px;
    border-bottom: 1px solid var(--rule);
}

.brand {
    display: flex;
    align-items: center;
    gap: 14px;
}

.brand-mark {
    height: 38px;
    width: auto;
}

.brand-txt {
    font-family: var(--sans);
    font-weight: 800;
    font-size: 15px;
    letter-spacing: -0.01em;
    line-height: 1.1;
}

.brand-txt em {
    font-style: italic;
    font-weight: 400;
    color: var(--blue);
}

.start-meta {
    display: flex;
    align-items: center;
    gap: 18px;
}

.start-meta .eyebrow { color: var(--ink); }

/* Ingresso voce-only: colonna unica centrata, struttura identica PC/mobile. */
.start-main {
    display: grid;
    /* safe center: centra quando c'è spazio, ma se il contenuto è più alto della
       riga centrale allinea in alto invece di sbordare su header/footer; lo
       scroll interno lo rende sempre raggiungibile. */
    align-content: safe center;
    justify-items: center;
    gap: 32px;
    padding: 28px 0;
    min-height: 0;
    overflow-y: auto;
}

.start-col-l { max-width: 640px; }

.start-col-l .eyebrow {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    margin-bottom: 28px;
}
.display {
    font-family: var(--sans);
    font-weight: 700;
    font-size: clamp(36px, 5vw, 56px);
    line-height: 1.1;
    letter-spacing: -0.025em;
    color: var(--ink);
    margin-bottom: 24px;
    animation: displayIn 1.1s cubic-bezier(0.22, 1, 0.36, 1) both;
}

.display em {
    font-style: normal;
    font-weight: 700;
    color: var(--blue);
}

@keyframes displayIn {
    from { opacity: 0; transform: translateY(18px); }
    to { opacity: 1; transform: translateY(0); }
}

.lede {
    font-size: 17px;
    line-height: 1.55;
    color: var(--ink-dim);
    max-width: 480px;
    margin-bottom: 40px;
}

.start-col-r {
    padding: 36px 32px;
    background: var(--blue);
    color: #ffffff;
    position: relative;
    box-shadow: 0 30px 60px -30px rgba(0, 58, 121, 0.4);
}

.start-col-r .eyebrow { color: rgba(255, 255, 255, 0.6); }

.access-label {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    margin: 18px 0 12px;
}

.access-label-main {
    font-family: var(--sans);
    font-weight: 600;
    font-size: 15px;
    color: var(--paper);
}

.field-num {
    font-family: var(--mono);
    font-size: 11px;
    letter-spacing: 0.1em;
}

.access-input {
    display: grid;
    grid-template-columns: 1fr;
    border: 1px solid rgba(255, 255, 255, 0.25);
    border-radius: var(--radius-sm);
    transition: border-color 0.25s;
}

.access-input:focus-within {
    border-color: #ffffff;
}

.access-input input {
    background: transparent;
    border: none;
    padding: 20px 22px;
    color: #ffffff;
    font-family: var(--mono);
    font-size: 22px;
    font-weight: 500;
    letter-spacing: 0.02em;
    text-transform: uppercase;
    outline: none;
    width: 100%;
}

.access-input input::placeholder {
    color: rgba(255, 255, 255, 0.35);
    text-transform: none;
    letter-spacing: 0;
}

/* --- MODE PICKER (Chat / Voce) --- */
.mode-picker {
    margin-top: 22px;
    display: flex;
    flex-direction: column;
    gap: 10px;
}
.mode-picker .eyebrow { color: rgba(255, 255, 255, 0.55); }

.mode-picker-row {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 12px;
}

.mode-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 10px;
    background: #ffffff;
    color: var(--blue);
    border: 1px solid #ffffff;
    padding: 16px 18px;
    font-family: var(--sans);
    font-weight: 700;
    font-size: 14px;
    letter-spacing: 0.02em;
    text-transform: uppercase;
    cursor: pointer;
    transition: background 0.2s, color 0.2s, border-color 0.2s;
}
.mode-btn svg { width: 18px; height: 18px; }
.mode-btn:hover {
    background: var(--blue-dim);
    color: #ffffff;
    border-color: var(--blue-dim);
}
.mode-btn:active { transform: scale(0.98); }

.access-foot {
    display: flex;
    justify-content: space-between;
    margin-top: 22px;
    font-family: var(--mono);
    font-size: 11px;
    color: rgba(255, 255, 255, 0.55);
    letter-spacing: 0.06em;
    text-transform: uppercase;
}

/* ------------------------------------------------------ */
/* PILOT DROPDOWN — menù a tendina degli 8 pilota         */
/* ------------------------------------------------------ */
.pilot-wrap {
    margin-top: 22px;
    position: relative;
}

.pilot-head {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    margin-bottom: 8px;
}

.pilot-head .eyebrow { color: rgba(255, 255, 255, 0.55); }

.pilot-trigger {
    display: grid;
    grid-template-columns: 1fr auto auto;
    gap: 14px;
    align-items: center;
    width: 100%;
    background: rgba(255, 255, 255, 0.05);
    border: 1px solid rgba(255, 255, 255, 0.22);
    border-radius: var(--radius-sm);
    color: #ffffff;
    padding: 13px 16px;
    cursor: pointer;
    font: inherit;
    text-align: left;
    transition: background 0.18s, border-color 0.18s;
}

.pilot-trigger:hover {
    background: rgba(255, 255, 255, 0.08);
    border-color: rgba(255, 255, 255, 0.4);
}

.pilot-trigger:focus-visible {
    outline: none;
    border-color: #ffffff;
}

.pilot-wrap.open .pilot-trigger {
    border-color: #ffffff;
    background: rgba(255, 255, 255, 0.08);
}

.pilot-trigger-label {
    font-family: var(--sans);
    font-size: 14px;
    font-weight: 500;
    color: rgba(255, 255, 255, 0.7);
    letter-spacing: -0.005em;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.pilot-trigger-label.has-value {
    font-family: var(--mono);
    font-weight: 600;
    color: #ffffff;
    letter-spacing: 0.02em;
    font-size: 13px;
}

.pilot-trigger-meta {
    font-family: var(--mono);
    font-size: 10px;
    letter-spacing: 0.14em;
    color: rgba(255, 255, 255, 0.4);
    text-transform: uppercase;
    white-space: nowrap;
}

.pilot-chevron {
    width: 11px;
    height: 11px;
    color: rgba(255, 255, 255, 0.7);
    transition: transform 0.22s cubic-bezier(0.22, 1, 0.36, 1);
    flex-shrink: 0;
}

.pilot-wrap.open .pilot-chevron { transform: rotate(180deg); }

.pilot-options {
    position: absolute;
    top: calc(100% + 4px);
    left: 0;
    right: 0;
    background: var(--blue-dim);
    border: 1px solid #ffffff;
    border-radius: var(--radius-md);
    z-index: 30;
    box-shadow: 0 18px 40px -12px rgba(0, 0, 0, 0.40), 0 4px 10px rgba(0, 0, 0, 0.18);
    overflow: hidden auto;
    scrollbar-width: thin;
    scrollbar-color: rgba(255, 255, 255, 0.3) transparent;
}

.pilot-options.flip-up {
    top: auto;
    bottom: calc(100% + 4px);
}

.pilot-options::-webkit-scrollbar { width: 6px; }
.pilot-options::-webkit-scrollbar-thumb { background: rgba(255, 255, 255, 0.3); }

.pilot-wrap.open .pilot-options {
    animation: dropIn 0.18s cubic-bezier(0.22, 1, 0.36, 1);
}
.pilot-wrap.open .pilot-options.flip-up {
    animation: dropInUp 0.18s cubic-bezier(0.22, 1, 0.36, 1);
}

@keyframes dropIn {
    from { opacity: 0; transform: translateY(-6px); }
    to { opacity: 1; transform: translateY(0); }
}
@keyframes dropInUp {
    from { opacity: 0; transform: translateY(6px); }
    to { opacity: 1; transform: translateY(0); }
}

.pilot-option {
    display: grid;
    /* Il nome cliente e' lungo (fino a ~40 char): la vecchia colonna fissa da
       76px, disegnata per un codice impianto, lo mandava a capo su 3 righe
       addosso alla colonna accanto. Nome e dettaglio ora sono impilati. */
    grid-template-columns: 1fr auto;
    gap: 14px;
    align-items: center;
    width: 100%;
    background: transparent;
    border: none;
    border-bottom: 1px solid rgba(255, 255, 255, 0.08);
    color: #ffffff;
    padding: 11px 16px 11px 19px;
    cursor: pointer;
    font: inherit;
    text-align: left;
    transition: background 0.12s;
    position: relative;
}

.pilot-option:last-child { border-bottom: none; }

.pilot-option:hover {
    background: rgba(255, 255, 255, 0.07);
}

.pilot-option.selected {
    background: rgba(255, 255, 255, 0.11);
}

.pilot-option-main {
    display: flex;
    flex-direction: column;
    gap: 3px;
    min-width: 0;          /* senza, il figlio con ellipsis sfonda la griglia */
}

.pilot-option-name {
    font-family: var(--sans);
    font-size: 13.5px;
    font-weight: 600;
    color: #ffffff;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.pilot-option-sub {
    font-family: var(--sans);
    font-size: 11.5px;
    font-weight: 400;
    color: rgba(255, 255, 255, 0.58);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.pilot-option-meta {
    font-family: var(--mono);
    font-size: 10px;
    letter-spacing: 0.12em;
    color: rgba(255, 255, 255, 0.5);
    text-transform: uppercase;
    white-space: nowrap;
}

.pilot-option[data-paese="IT"] { --paese-color: #008c45; }
.pilot-option[data-paese="ES"] { --paese-color: #ffc400; }
.pilot-option[data-paese="CL"] { --paese-color: #d52b1e; }
.pilot-option[data-paese="US"] { --paese-color: #b22234; }

.access-err {
    margin-top: 14px;
    font-family: var(--mono);
    font-size: 12px;
    color: #ff8591;
    padding: 10px 14px;
    background: rgba(200, 16, 46, 0.15);
    border-left: 2px solid var(--rosso);
}

/* ====================================================== */
/* INGRESSO VOCE-ONLY + LOGIN + DEV (2026-06-18)          */
/* ====================================================== */
.login-main {
    display: grid;
    place-content: center;
    justify-items: center;
    min-height: 0;
    padding: 40px 0;
}

/* Pannello blu d'accesso (login e ingresso): iconico Unitec, centrato. */
.access-panel {
    width: 100%;
    max-width: 460px;
    background: var(--blue);
    color: #fff;
    padding: 34px 32px;
    border-radius: var(--radius-lg);
    box-shadow: var(--elev-3);
    position: relative;
}
.access-panel .eyebrow,
.access-eyebrow { color: rgba(255, 255, 255, 0.6); display: block; }
.access-title {
    font-family: var(--sans);
    font-weight: 700;
    font-size: 26px;
    letter-spacing: -0.02em;
    line-height: 1.1;
    margin: 10px 0 24px;
}
.access-field-label {
    display: block;
    font-family: var(--sans);
    font-weight: 600;
    font-size: 13px;
    color: rgba(255, 255, 255, 0.85);
    margin: 0 0 8px;
}
.access-field-label + .access-input { margin-bottom: 16px; }
/* Login: niente maiuscolo forzato — le credenziali sono case-sensitive e
   l'utente deve vedere esattamente cosa digita (il codice impianto invece
   resta uppercase, è il comportamento voluto su #impiantoInput). */
/* ⚠️ Regola legata agli id: i campi della schermata «scegli la password» sono
   i gemelli di questi e senza aggiungerli qui resterebbero maiuscoli e più
   piccoli. È la trappola già pagata due volte in questo progetto (la palette su
   #dashboardScreen, #dashKpi .kpi-cell em): una regola su un id non vale per il
   gemello, e il difetto si vede solo a schermo. */
#loginUser, #loginPass, #nuovaPassword, #nuovaPassword2 {
    text-transform: none;
    letter-spacing: 0.01em;
    font-size: 18px;
}
#loginUser::placeholder, #loginPass::placeholder,
#nuovaPassword::placeholder, #nuovaPassword2::placeholder { letter-spacing: 0; }

/* ====================================================== */
/* PASSWORD SCELTA DALL'UTENTE (2026-08-25)               */
/* ====================================================== */

/* Bottone che si comporta da collegamento: serve un <button>, perché è
   un'azione e non una destinazione, ma deve leggersi come un link. */
.pw-link {
    background: none;
    border: 0;
    padding: 0;
    font: inherit;
    color: var(--blue);
    text-decoration: underline;
    text-underline-offset: 3px;
    cursor: pointer;
}
.pw-link:hover { color: var(--blue-dim); }
/* Dentro il pannello blu il testo è bianco: senza questa riga il collegamento
   sarebbe blu su blu, cioè invisibile. */
.access-panel .pw-link { color: rgba(255, 255, 255, 0.9); }
.access-panel .pw-link:hover { color: #fff; }

/* Nota sotto i campi: le regole della password, e l'esito del recupero. */
.pw-nota {
    margin-top: 10px;
    font-size: 12.5px;
    line-height: 1.45;
    color: rgba(255, 255, 255, 0.7);
}
.pw-riga-link { margin-top: 16px; font-size: 13px; }
/* «Per l'accesso <utente>», subito sotto il titolo: senza questa erediterebbe
   il margine superiore di .pw-nota e si staccherebbe dal titolo. */
.pw-nota-utente { margin: 0 0 20px; }
.pw-nota-utente strong { color: #fff; font-weight: 700; }

/* Esito positivo nello stesso posto dell'errore. Senza questa variante
   «Password impostata» esce in rosso con la barra rossa: la forma dice
   "è andata male" mentre il testo dice il contrario, e a schermo vince la
   forma. Chi scrive un esito qui deve scegliere quale dei due è. */
.access-err.pw-ok {
    color: #7fe0b0;
    background: rgba(31, 153, 102, 0.18);
    border-left-color: var(--verde);
}
.access-divider {
    display: flex;
    align-items: center;
    gap: 14px;
    margin: 20px 0 16px;
    font-family: var(--mono);
    font-size: 10.5px;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: rgba(255, 255, 255, 0.45);
}
.access-divider::before,
.access-divider::after { content: ''; flex: 1; height: 1px; background: rgba(255, 255, 255, 0.18); }
.access-panel .pilot-wrap { margin-top: 0; }

/* CTA primaria (Avvia chiamata / Accedi): touch target ampio */
.cta-voice {
    margin-top: 24px;
    width: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 12px;
    background: #fff;
    color: var(--blue);
    border: 1px solid #fff;
    padding: 18px;
    min-height: 56px;
    font-family: var(--sans);
    font-weight: 800;
    font-size: 15px;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    cursor: pointer;
    border-radius: var(--radius-md);
    box-shadow:
        0 1px 2px rgba(0, 12, 28, 0.10),
        0 8px 20px -8px rgba(0, 12, 28, 0.22);
    transition: background 0.2s, color 0.2s, border-color 0.2s, box-shadow 0.2s, transform 0.2s;
}
/* Login in corso: il bottone lo DICE. Senza questo si disabilitava soltanto, e
   i ~2 s della risposta (connessioni al pooler + bcrypt) sembravano un clic
   perso — si ricliccava. L'icona pulsa piano: un movimento, non un'animazione
   che distrae. `prefers-reduced-motion` la spegne, resta il testo. */
.cta-voice.in-corso { cursor: progress; opacity: .85; }
.cta-voice.in-corso svg { animation: cta-pulsa 1.1s ease-in-out infinite; }
@keyframes cta-pulsa {
    0%, 100% { opacity: .35; }
    50%      { opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
    .cta-voice.in-corso svg { animation: none; opacity: .6; }
}

.cta-voice:hover {
    background: var(--blue-dim);
    color: #fff;
    border-color: var(--blue-dim);
    transform: translateY(-1px);
    box-shadow:
        0 2px 6px rgba(0, 12, 28, 0.16),
        0 14px 30px -10px rgba(0, 12, 28, 0.32);
}
.cta-voice:active { transform: translateY(0) scale(0.99); }
.cta-voice svg { width: 22px; height: 22px; }

/* Strumenti operatore sotto il pannello. Quante voci si vedano dipende dal
   ruolo (3 al cliente, 5 allo staff, 7 all'admin), quindi la larghezza di
   partenza va DICHIARATA: con `flex: 1 1 0` + `min-width: 0` i bottoni
   possono restringersi all'infinito e non vanno mai a capo — si schiacciano,
   e a sette per riga le etichette si tagliavano a metà parola. La griglia
   sceglie il numero di colonne dallo spazio vero e il gap lo conta da sé. */
.entry-tools {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(132px, 1fr));
    gap: 12px;
    width: 100%;
    /* ⚠️ `min-width: 0` sul CONTENITORE, non sulle tessere: come elemento
       flex la sua minimum size automatica è il min-content, che qui vale tre
       colonne (420px) e vince sul `width: 100%`. Su un telefono da 390px la
       griglia usciva dal padre da 358px — senza far scorrere la pagina,
       quindi senza che nulla lo segnalasse: le tessere ai lati erano
       semplicemente tagliate. Azzerato il minimo, auto-fit conta le colonne
       sullo spazio vero e scende a due. */
    min-width: 0;
    max-width: 460px;
}

/* ⚠️ Quante tessere ci sono lo decide il RUOLO, e va scritto così: le tessere
   nascoste restano nel DOM (`display: none`), quindi né `:nth-child` né
   `:has()` sanno contare quelle che si vedono davvero — conterebbero tutte e
   sette.

   Agli interni ne restano quattro, dal 2026-09-01 (erano otto per l'admin):
   con tre colonne la quarta andava a capo da sola, orfana sotto le altre.
   Duecento pixel di minimo fanno due colonne dentro i 460 del pannello, cioè
   un 2×2 pieno. Al cliente le tessere sono TRE e la regola non lo tocca: lì
   una riga da tre è già piena, e portarlo a due gli rifarebbe lo stesso
   difetto al contrario.

   `min(200px, 100%)` e non `200px` secco: su uno schermo stretto la colonna
   scende a tutta larghezza invece di sfondare il padre — è lo stesso difetto
   che il `min-width: 0` qui sopra è venuto a chiudere. */
body:not(.role-cliente) .entry-tools {
    grid-template-columns: repeat(auto-fit, minmax(min(200px, 100%), 1fr));
}

.entry-tool {
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 3px;
    background: var(--paper-2);
    border: 1px solid var(--rule);
    padding: 16px 18px;
    cursor: pointer;
    text-align: left;
    border-radius: var(--radius-md);
    box-shadow: var(--elev-1);
    transition: border-color 0.18s, background 0.18s, box-shadow 0.18s, transform 0.18s;
}
.entry-tool:hover {
    border-color: rgba(0, 58, 121, 0.30);
    background: var(--paper);
    transform: translateY(-2px);
    box-shadow: var(--elev-hover);
}
.entry-tool:active { transform: translateY(0); }
.entry-tool-label { font-family: var(--sans); font-weight: 600; font-size: 14px; color: var(--ink); }
.entry-tool-sub { font-family: var(--mono); font-size: 10px; letter-spacing: 0.06em; text-transform: uppercase; color: var(--fog); }

/* ====================================================== */
/* CHAT SHELL                                              */
/* ====================================================== */
.chat-shell {
    height: 100dvh;
    display: grid;
    grid-template-rows: auto auto auto 1fr auto;
    max-width: 1240px;
    margin: 0 auto;
    padding: 20px 40px 18px;
}

/* --- top utility strip --- */
.chat-top {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding-bottom: 14px;
    border-bottom: 1px solid var(--rule);
}

.chat-brand {
    display: flex;
    align-items: center;
    gap: 10px;
}

.chat-brand .brand-mark {
    height: 22px;
    width: auto;
}

.chat-top-meta {
    display: flex;
    align-items: center;
    gap: 18px;
}

.chat-top-meta .eyebrow {
    display: inline-flex;
    align-items: center;
    color: var(--ink);
}

.btn-reset {
    font-family: var(--mono);
    font-size: 11px;
    font-weight: 500;
    text-transform: uppercase;
    letter-spacing: 0.1em;
    color: var(--ink);
    background: transparent;
    border: 1px solid var(--ink);
    border-radius: var(--radius-sm);
    padding: 6px 12px;
    cursor: pointer;
    transition: all 0.15s;
    display: inline-flex;
    align-items: center;
    gap: 7px;
}

.btn-reset:hover {
    background: var(--ink);
    color: var(--paper);
    box-shadow: var(--elev-2);
}

.btn-reset svg { width: 11px; height: 11px; }

/* --- HERO: impianto in assistenza --- */
.impianto-hero {
    display: grid;
    grid-template-columns: 1fr auto;
    gap: 32px;
    padding: 14px 0 14px;
    border-bottom: 1px solid var(--rule);
    align-items: end;
}

.imp-primary .eyebrow {
    display: block;
    margin-bottom: 6px;
}

.imp-code {
    font-family: var(--sans);
    font-weight: 800;
    font-size: clamp(24px, 3.2vw, 34px);
    line-height: 1;
    letter-spacing: -0.03em;
    color: var(--ink);
    margin-bottom: 4px;
    font-variant-numeric: tabular-nums;
}

.imp-sub {
    font-family: var(--sans);
    font-weight: 500;
    font-size: 13.5px;
    line-height: 1.3;
    color: var(--ink-dim);
}

.imp-sub strong {
    color: var(--ink);
    font-weight: 600;
}

.imp-secondary {
    display: flex;
    flex-direction: column;
    gap: 6px;
    padding-left: 32px;
    border-left: 1px solid var(--rule);
    align-self: stretch;
    justify-content: end;
    min-width: 140px;
}

.imp-secondary .eyebrow {
    margin-bottom: 2px;
}

.imp-value {
    font-family: var(--sans);
    font-weight: 600;
    font-size: 15px;
    color: var(--ink);
    line-height: 1.2;
    letter-spacing: -0.01em;
}

.variant-badge {
    display: inline-block;
    align-self: flex-start;
    font-family: var(--mono);
    font-size: 11px;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--rule-ink);
    border: 1px solid var(--rule);
    padding: 4px 8px;
}

/* --- PANEL --- */
.panel {
    padding: 20px 0 22px;
    border-bottom: 1px solid var(--rule);
}

.panel-head {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    margin-bottom: 16px;
}

/* --- INDICATORE AREA · 4 banner (scelto pieno, altri 3 attenuati) --- */
.area-banners {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 10px;
}
.area-banner {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 8px;
    padding: 12px 14px;
    border: 1px solid var(--rule);
    border-left: 3px solid var(--area-color, var(--fog));
    background: var(--area-bg, transparent);
    transition: opacity 0.35s, border-color 0.35s, background 0.35s;
}
.area-banner .ab-name {
    font-family: var(--sans);
    font-weight: 700;
    font-size: clamp(11px, 1.05vw, 15px);
    letter-spacing: -0.01em;
    line-height: 1.1;
    color: var(--area-color, var(--ink));
}
.area-banner .ab-conf {
    font-family: var(--mono);
    font-size: 15px;
    font-weight: 600;
    color: var(--area-color, var(--fog));
    font-variant-numeric: tabular-nums;
}
/* Prima della classificazione: tutti neutri. */
.area-banners.pending .area-banner {
    --area-color: var(--fog);
    --area-bg: transparent;
    opacity: 0.55;
}
/* Dopo: il classificato pieno, gli altri 3 piu' trasparenti. */
.area-banner.chosen { opacity: 1; }
.area-banner.chosen .ab-name { font-weight: 800; }
.area-banner.dimmed { opacity: 0.3; }
.area-banner[data-area="MECCANICO"]    { --area-color: var(--mecc);     --area-bg: var(--mecc-bg); }
.area-banner[data-area="ELETTRICO"]    { --area-color: var(--elet);     --area-bg: var(--elet-bg); }
.area-banner[data-area="ELETTRONICO"]  { --area-color: var(--elettron); --area-bg: var(--elettron-bg); }
.area-banner[data-area="TRACCIABILITÀ"]{ --area-color: var(--tracc);    --area-bg: var(--tracc-bg); }

/* --- CHAT · WhatsApp-style bubbles --- */
.chat {
    padding: 22px 20px;
    overflow-y: auto;
    display: flex;
    flex-direction: column;
    gap: 4px;
    scroll-behavior: smooth;
    scrollbar-width: thin;
    scrollbar-color: rgba(0, 58, 121, 0.2) transparent;
    background: #f4f6f9;
    background-image: radial-gradient(circle, rgba(0, 58, 121, 0.07) 1px, transparent 1px);
    background-size: 20px 20px;
    min-height: 0;
}

.chat::-webkit-scrollbar { width: 6px; }
.chat::-webkit-scrollbar-thumb {
    background: rgba(0, 58, 121, 0.2);
}

.message {
    max-width: 72%;
    padding: 9px 14px 6px;
    font-size: 15px;
    line-height: 1.5;
    font-family: var(--sans);
    position: relative;
    animation: msgIn 0.3s cubic-bezier(0.22, 1, 0.36, 1) both;
    word-wrap: break-word;
    overflow-wrap: anywhere;
}

@keyframes msgIn {
    from { opacity: 0; transform: translateY(4px); }
    to { opacity: 1; transform: translateY(0); }
}

.message .bubble-body { white-space: pre-wrap; }

.message .bubble-time {
    display: block;
    font-family: var(--mono);
    font-size: 10px;
    font-weight: 500;
    letter-spacing: 0.04em;
    margin-top: 3px;
    text-align: right;
    opacity: 0.65;
}

.message.agent {
    align-self: flex-start;
    background: #ffffff;
    border: 1px solid var(--rule);
    color: var(--ink);
    border-radius: 12px 12px 12px 2px;
    box-shadow: 0 1px 2px rgba(15, 30, 51, 0.06);
    margin-top: 8px;
}

.message.user {
    align-self: flex-end;
    background: var(--blue);
    color: #ffffff;
    border-radius: 12px 12px 2px 12px;
    box-shadow: 0 1px 2px rgba(0, 58, 121, 0.18);
    margin-top: 8px;
}

.message.agent + .message.agent {
    border-radius: 12px 12px 12px 12px;
    margin-top: 2px;
}
.message.user + .message.user {
    border-radius: 12px 12px 12px 12px;
    margin-top: 2px;
}

.message.system {
    align-self: center;
    margin: 10px 0;
    padding: 4px 12px;
    background: rgba(255, 255, 255, 0.92);
    border: 1px solid var(--rule);
    box-shadow: 0 1px 2px rgba(15, 30, 51, 0.04);
    color: var(--ink-dim);
    font-family: var(--mono);
    font-size: 10.5px;
    font-weight: 500;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    max-width: fit-content;
}

/* --- TYPING --- */
.typing {
    align-self: flex-start;
    padding: 14px 18px;
    background: #ffffff;
    border: 1px solid var(--rule);
    border-radius: 12px 12px 12px 2px;
    box-shadow: 0 1px 2px rgba(15, 30, 51, 0.06);
    margin-top: 8px;
    display: none;
}

.typing.visible { display: flex; gap: 6px; }

.typing-dot {
    width: 6px;
    height: 6px;
    background: var(--fog);
    border-radius: 50%;
    animation: typingBounce 1.2s ease-in-out infinite;
}
.typing-dot:nth-child(2) { animation-delay: 0.15s; }
.typing-dot:nth-child(3) { animation-delay: 0.3s; }
@keyframes typingBounce {
    0%, 60%, 100% { transform: translateY(0); opacity: 0.35; }
    30% { transform: translateY(-5px); opacity: 1; }
}

/* --- INPUT --- */
.input-area {
    padding: 18px 0 8px;
    border-top: 1px solid var(--rule);
}

.input-row {
    display: grid;
    grid-template-columns: 1fr auto;
    gap: 10px;
    align-items: stretch;
}

.input-wrap {
    position: relative;
    display: flex;
    flex-direction: column;
    background: var(--paper-2);
    border: 1px solid var(--rule);
    transition: border-color 0.2s;
}

.input-wrap:focus-within { border-color: var(--ink); }

.input-wrap .eyebrow {
    padding: 8px 18px 0;
    font-size: 10px;
    letter-spacing: 0.14em;
}

.input-field {
    background: transparent;
    border: none;
    padding: 4px 18px 12px;
    color: var(--ink);
    font-family: var(--sans);
    font-size: 16px;
    outline: none;
}

.input-field::placeholder { color: var(--fog); }
.input-field:disabled { opacity: 0.4; cursor: not-allowed; }

.btn {
    width: 54px;
    border: 1px solid var(--rule);
    background: var(--paper-2);
    color: var(--ink);
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: all 0.15s;
}

.btn:hover { background: var(--paper-3); }
.btn:active { transform: scale(0.97); }
.btn svg { width: 18px; height: 18px; }

.btn-send {
    background: var(--blue);
    color: #ffffff;
    border-color: var(--blue);
}

.btn-send:hover { background: var(--blue-dim); border-color: var(--blue-dim); }
.btn-send:disabled {
    background: var(--rule);
    color: var(--fog);
    border-color: var(--rule);
    cursor: not-allowed;
    transform: none;
}
.btn-send:disabled:hover { background: var(--rule); }

.history-shortcut {
    background: rgba(255, 255, 255, 0.04);
    border: 1px solid rgba(255, 255, 255, 0.18);
    border-radius: var(--radius-md);
    padding: 16px 20px;
    margin-top: 12px;
    cursor: pointer;
    transition: all 0.15s;
}

.history-shortcut:hover {
    border-color: #ffffff;
    background: rgba(255, 255, 255, 0.08);
}

.history-shortcut-label {
    font-family: var(--sans);
    font-size: 14px;
    font-weight: 600;
    color: #ffffff;
    display: block;
    margin-top: 4px;
}

.history-shortcut-sub {
    font-family: var(--mono);
    font-size: 11px;
    color: rgba(255, 255, 255, 0.55);
    letter-spacing: 0.04em;
    display: block;
    margin-top: 3px;
}

/* ====================================================== */
/* HISTORY · Industrial WhatsApp (Unitec palette)          */
/* ====================================================== */
.history-shell {
    display: grid;
    grid-template-columns: 380px 1fr;
    height: 100dvh;
    max-width: 1440px;
    margin: 0 auto;
    background: var(--paper);
    overflow: hidden;
    border-left: 1px solid var(--rule);
    border-right: 1px solid var(--rule);
}

.hist-side {
    display: flex;
    flex-direction: column;
    background: var(--paper);
    border-right: 1px solid var(--rule);
    overflow: hidden;
}

.hist-side-head {
    padding: 22px 22px 14px;
    display: flex;
    align-items: center;
    gap: 14px;
    border-bottom: 1px solid var(--rule);
}

.hist-back {
    width: 34px; height: 34px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: var(--paper);
    border: 1px solid var(--rule);
    border-radius: var(--radius-sm);
    color: var(--ink);
    cursor: pointer;
    box-shadow: var(--elev-1);
    transition: all 0.15s;
    flex-shrink: 0;
}
.hist-back:hover {
    background: var(--blue);
    border-color: var(--blue);
    color: #ffffff;
    box-shadow: var(--elev-2);
    transform: translateY(-1px);
}
.hist-back svg { width: 14px; height: 14px; }

.hist-title {
    display: flex;
    flex-direction: column;
    gap: 2px;
}
.hist-title .eyebrow { letter-spacing: 0.18em; }
.hist-title h2 {
    font-family: var(--sans);
    font-size: 22px;
    font-weight: 800;
    letter-spacing: -0.025em;
    color: var(--ink);
}

.hist-search {
    margin: 12px 16px 14px;
    padding: 9px 14px;
    border-radius: 980px;
    display: flex;
    align-items: center;
    gap: 9px;
    background: var(--paper-3);
    transition: background 0.15s, box-shadow 0.15s;
}
.hist-search:focus-within {
    background: var(--paper);
    box-shadow: 0 0 0 1px rgba(0, 58, 121, 0.30), var(--elev-1);
}
.hist-search svg {
    width: 15px; height: 15px;
    color: var(--fog);
    flex-shrink: 0;
}
.hist-search input {
    flex: 1;
    background: transparent;
    border: none;
    outline: none;
    font-family: var(--sans);
    font-size: 13.5px;
    color: var(--ink);
    letter-spacing: -0.005em;
}
.hist-search input::placeholder {
    color: var(--fog);
    font-weight: 400;
}

.conv-list {
    flex: 1;
    overflow-y: auto;
    scrollbar-width: thin;
    scrollbar-color: var(--rule) transparent;
}
.conv-list::-webkit-scrollbar { width: 6px; }
.conv-list::-webkit-scrollbar-thumb { background: var(--rule); }

.conv-item {
    display: grid;
    grid-template-columns: 44px 1fr auto;
    gap: 12px;
    align-items: center;
    margin: 2px 10px;
    padding: 10px 12px;
    border-radius: var(--radius-md);
    cursor: pointer;
    transition: background 0.15s;
    position: relative;
}
.conv-item:hover { background: var(--paper-2); }
.conv-item.selected { background: rgba(0, 58, 121, 0.08); }

.conv-avatar {
    width: 44px;
    height: 44px;
    border-radius: 50%;
    background: var(--blue);
    color: #ffffff;
    display: flex;
    align-items: center;
    justify-content: center;
    font-family: var(--sans);
    font-weight: 700;
    font-size: 14px;
    letter-spacing: 0.02em;
    user-select: none;
}

.conv-body {
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.conv-row {
    display: flex;
    align-items: center;
    gap: 8px;
    justify-content: space-between;
}

.conv-imp {
    font-family: var(--sans);
    font-weight: 700;
    font-size: 14px;
    color: var(--ink);
    letter-spacing: -0.01em;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.conv-time {
    font-family: var(--mono);
    font-size: 10.5px;
    color: var(--fog);
    letter-spacing: 0.04em;
    flex-shrink: 0;
}

.conv-cliente {
    font-family: var(--sans);
    font-size: 12px;
    color: var(--ink-dim);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.conv-preview {
    font-family: var(--sans);
    font-size: 12.5px;
    color: var(--fog);
    line-height: 1.35;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 100%;
}

.conv-meta {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 6px;
    padding-right: 2px;
}

.conv-area-tag {
    font-family: var(--mono);
    font-size: 9.5px;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    padding: 3px 9px;
    border-radius: 980px;
    color: #ffffff;
    background: var(--area-color, var(--fog));
    white-space: nowrap;
}
.conv-area-tag.pending {
    background: transparent;
    color: var(--fog);
    border: 1px solid var(--rule);
}

.conv-badge {
    min-width: 18px;
    height: 18px;
    padding: 0 5px;
    border-radius: 980px;
    background: var(--blue);
    color: #ffffff;
    font-family: var(--mono);
    font-size: 10px;
    font-weight: 600;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}

.conv-item[data-area="MECCANICO"] { --area-color: var(--mecc); }
.conv-item[data-area="ELETTRICO"] { --area-color: var(--elet); }
.conv-item[data-area="ELETTRONICO"] { --area-color: var(--elettron); }
.conv-item[data-area="TRACCIABILITÀ"] { --area-color: var(--tracc); }
.conv-item[data-area="in_corso"] { --area-color: var(--fog); }

.hist-empty-list {
    padding: 50px 24px;
    text-align: center;
    color: var(--fog);
    font-family: var(--mono);
    font-size: 11.5px;
    letter-spacing: 0.08em;
    text-transform: uppercase;
}

.hist-pane {
    display: flex;
    flex-direction: column;
    background: #fbfbfd;
    overflow: hidden;
    position: relative;
}

.pane-empty {
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 18px;
    color: var(--ink-dim);
    text-align: center;
    padding: 40px;
}
.pane-empty svg {
    width: 56px;
    height: 56px;
    color: var(--blue);
    opacity: 0.4;
}
.pane-empty p {
    font-family: var(--sans);
    font-size: 17px;
    font-weight: 600;
    color: var(--ink);
    letter-spacing: -0.01em;
}
.pane-empty .eyebrow {
    color: var(--fog);
}

.pane-head {
    display: grid;
    grid-template-columns: 44px 1fr auto;
    gap: 14px;
    align-items: center;
    padding: 16px 24px;
    background: var(--paper);
    border-bottom: 1px solid var(--rule);
    z-index: 1;
}

.pane-back {
    display: none;
    width: 34px; height: 34px;
    align-items: center;
    justify-content: center;
    background: var(--paper);
    border: 1px solid var(--rule);
    border-radius: var(--radius-sm);
    color: var(--ink);
    cursor: pointer;
    box-shadow: var(--elev-1);
    flex-shrink: 0;
}
.pane-back svg { width: 14px; height: 14px; }

.pane-avatar {
    width: 44px;
    height: 44px;
    border-radius: 50%;
    background: var(--blue);
    color: #ffffff;
    display: flex;
    align-items: center;
    justify-content: center;
    font-family: var(--sans);
    font-weight: 700;
    font-size: 15px;
}

.pane-head-info {
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.pane-head-title {
    font-family: var(--sans);
    font-weight: 700;
    font-size: 16px;
    letter-spacing: -0.01em;
    color: var(--ink);
}
.pane-head-title span {
    font-family: var(--mono);
    font-size: 12px;
    font-weight: 500;
    color: var(--ink-dim);
    margin-left: 8px;
    letter-spacing: 0.02em;
}

.pane-head-sub {
    font-family: var(--mono);
    font-size: 11px;
    color: var(--fog);
    letter-spacing: 0.08em;
    text-transform: uppercase;
}

.pane-head-area {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    font-family: var(--mono);
    font-size: 10.5px;
    font-weight: 600;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    padding: 6px 13px;
    border-radius: 980px;
    background: var(--area-color, var(--fog));
    color: #ffffff;
}
.pane-head-area.pending {
    background: transparent;
    color: var(--fog);
    border: 1px solid var(--rule);
}
.pane-head[data-area="MECCANICO"] { --area-color: var(--mecc); }
.pane-head[data-area="ELETTRICO"] { --area-color: var(--elet); }
.pane-head[data-area="ELETTRONICO"] { --area-color: var(--elettron); }
.pane-head[data-area="TRACCIABILITÀ"] { --area-color: var(--tracc); }

.pane-msgs {
    flex: 1;
    overflow-y: auto;
    padding: 28px 8% 28px;
    display: flex;
    flex-direction: column;
    gap: 6px;
    scrollbar-width: thin;
    scrollbar-color: rgba(0, 58, 121, 0.2) transparent;
}
.pane-msgs::-webkit-scrollbar { width: 6px; }
.pane-msgs::-webkit-scrollbar-thumb { background: rgba(0, 58, 121, 0.2); }

.day-sep {
    align-self: center;
    margin: 16px 0 10px;
    padding: 2px 12px;
    font-family: var(--sans);
    font-size: 11px;
    font-weight: 700;
    color: var(--fog);
    text-transform: uppercase;
    letter-spacing: 0.08em;
}

.bubble {
    max-width: 70%;
    padding: 8px 15px 6px;
    font-family: var(--sans);
    font-size: 14.5px;
    line-height: 1.4;
    position: relative;
    animation: bubbleIn 0.3s cubic-bezier(0.22, 1, 0.36, 1) both;
    word-wrap: break-word;
    overflow-wrap: anywhere;
}

@keyframes bubbleIn {
    from { opacity: 0; transform: translateY(4px); }
    to { opacity: 1; transform: translateY(0); }
}

.bubble-body {
    white-space: pre-wrap;
}

.bubble-time {
    display: block;
    font-family: var(--mono);
    font-size: 10px;
    font-weight: 500;
    letter-spacing: 0.04em;
    margin-top: 3px;
    text-align: right;
    opacity: 0.65;
}

.bubble.agent {
    align-self: flex-start;
    background: #e9e9eb;
    color: var(--ink);
    border-radius: 18px 18px 18px 5px;
}

.bubble.user {
    align-self: flex-end;
    background: var(--blue);
    color: #ffffff;
    border-radius: 18px 18px 5px 18px;
}

.bubble + .bubble.agent { margin-top: 2px; }
.bubble + .bubble.user { margin-top: 2px; }

/* Bolle consecutive dello stesso mittente: angoli pieni (gruppo iMessage) */
.bubble.agent + .bubble.agent { border-radius: 18px; }
.bubble.user + .bubble.user { border-radius: 18px; }

/* ---- Riascoltare la chiamata dallo Storico ----
   Il player sta FRA l'intestazione e l'elenco dei turni, non dentro: `.pane-msgs`
   e il contenitore che scorre, e `position: sticky` dentro un contenitore con
   `overflow` e la trappola classica. Qui non serve nessuno sticky. */
.pane-audio {
    padding: 10px 8% 0;
    background: var(--paper);
    border-bottom: 1px solid var(--rule);
}

.pane-audio-player {
    width: 100%;
    height: 34px;
    margin-bottom: 10px;
    display: block;
}

/* Un turno che si puo riascoltare lo dichiara: il minuto d'inizio accanto
   all'orario, e il cursore che cambia. Chi non ha `inizio_s` (chiamate in
   archivio) resta esattamente com'era. */
.bubble-ascoltabile {
    cursor: pointer;
}

.bubble-ascoltabile:focus-visible {
    outline: 2px solid var(--rule-ink);
    outline-offset: 2px;
}

.bubble-inizio {
    font-weight: 700;
    letter-spacing: 0.06em;
    margin-right: 6px;
    opacity: 0.9;
}

/* La bolla in ascolto. Sull'agente (fondo grigio) e sull'operatore (fondo blu)
   servono due segni diversi: sul blu un alone chiaro sparirebbe. */
.bubble-in-ascolto.agent {
    background: var(--elettron-bg);
    box-shadow: inset 0 0 0 1.5px var(--elettron);
}

.bubble-in-ascolto.user {
    box-shadow: inset 0 0 0 1.5px var(--paper), 0 0 0 2px var(--elettron);
}

/* ====================================================== */
/* VOICE SHELL — console audio nativa                      */
/* ====================================================== */
.shell {
    height: 100dvh;
    display: grid;
    /* rows: top · hero · panel · chat(1fr) · esito-slot(auto) · dock */
    grid-template-rows: auto auto auto 1fr auto auto;
    max-width: 1240px;
    margin: 0 auto;
    padding: 18px 40px 20px;
    gap: 0;
}

.shell .top {
    display: flex;
    align-items: center;
    gap: 18px;
    padding-bottom: 14px;
    border-bottom: 1px solid var(--rule);
}
.shell .top .brand { margin-right: auto; }

.shell .brand-rule {
    width: 1px;
    height: 30px;
    background: var(--rule);
}
.shell .brand-mark { height: 30px; }
.shell .brand-txt {
    font-weight: 800;
    font-size: 14px;
    line-height: 1.15;
    letter-spacing: -0.005em;
}
.shell .brand-txt em {
    font-style: italic;
    font-weight: 400;
    color: var(--blue);
    display: block;
    font-size: 12.5px;
}

.mode-block {
    display: grid;
    grid-template-columns: auto;
    justify-items: end;
    gap: 4px;
    padding-left: 24px;
    border-left: 1px solid var(--rule);
}
.mode-block .eyebrow { color: var(--ink-dim); }
.mode-block .mode-desc {
    font-family: var(--mono);
    font-size: 10.5px;
    color: var(--fog);
    letter-spacing: 0.05em;
    text-transform: none;
    line-height: 1.3;
    max-width: 320px;
    text-align: right;
}

/* Voice hero (flex, 4 celle) */
.shell .impianto-hero {
    display: flex;
    align-items: end;
    gap: 24px;
    padding: 16px 0 18px;
    border-bottom: 1px solid var(--rule);
}
.shell .imp-primary { margin-right: auto; }
.shell .imp-primary .eyebrow { display: block; margin-bottom: 6px; }
.shell .imp-sub {
    display: flex;
    align-items: center;
    gap: 10px;
}
.imp-flag-bar {
    width: 22px; height: 3px;
    background: var(--paese-color, var(--fog));
    display: inline-block;
    flex-shrink: 0;
}
.imp-cell {
    display: flex; flex-direction: column;
    gap: 4px;
    align-self: stretch;
    justify-content: end;
    padding-left: 24px;
    border-left: 1px solid var(--rule);
    min-width: 90px;
}
.imp-cell .eyebrow { margin-bottom: 2px; }
.imp-cell-val {
    font-weight: 800;
    font-size: 26px;
    line-height: 1;
    color: var(--blue);
    letter-spacing: -0.03em;
    font-variant-numeric: tabular-nums;
}
.imp-cell-val.small {
    font-size: 16px;
    color: var(--ink);
    font-weight: 600;
    letter-spacing: -0.01em;
}

/* Live tag (panel-head dx) */
.live-tag {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    font-family: var(--mono);
    font-size: 10px;
    font-weight: 600;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--fog);
}
.live-tag-dot {
    width: 7px; height: 7px;
    border-radius: 50%;
    background: var(--fog);
}
.live-tag[data-state="live"]     { color: var(--verde); }
.live-tag[data-state="live"]     .live-tag-dot { background: var(--verde); animation: pulse 1.1s ease-in-out infinite; box-shadow: 0 0 0 0 rgba(31,153,102,.45); }
.live-tag[data-state="speaking"] { color: var(--elettron); }
.live-tag[data-state="speaking"] .live-tag-dot { background: var(--elettron); animation: pulse 0.8s ease-in-out infinite; box-shadow: 0 0 0 0 rgba(29,124,204,.45); }
.live-tag[data-state="closed"]   { color: var(--ink-dim); }
.live-tag[data-state="closed"]   .live-tag-dot { background: var(--ink-dim); }
.live-tag[data-state="err"]      { color: var(--rosso); }
.live-tag[data-state="err"]      .live-tag-dot { background: var(--rosso); animation: pulse 0.7s ease-in-out infinite; }

/* Voice meters */
.meters {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 20px;
}
.meter {
    position: relative;
    padding-top: 14px;
    border-top: 1px solid var(--rule);
    transition: opacity 0.4s, border-color 0.4s;
}
.meter::before {
    content: '';
    position: absolute;
    top: -1px; left: 0;
    width: 0;
    height: 2px;
    background: var(--meter-color, var(--blue));
    transition: width 0.5s cubic-bezier(0.22, 1, 0.36, 1);
}
.meter.active::before { width: 100%; }
.meter .meter-head {
    display: grid;
    grid-template-columns: auto 1fr;
    align-items: baseline;
    gap: 8px;
    margin-bottom: 8px;
}
.meter .meter-num {
    font-family: var(--mono);
    font-size: 10px;
    font-weight: 500;
    color: var(--fog);
    letter-spacing: 0.1em;
}
.meter .meter-name {
    font-weight: 600;
    font-size: 13px;
    color: var(--ink-dim);
    letter-spacing: -0.005em;
}
.meter.active .meter-name { color: var(--meter-color, var(--blue)); }
.meter .meter-val {
    font-family: var(--sans);
    font-weight: 700;
    font-size: 22px;
    color: var(--ink);
    letter-spacing: -0.025em;
    font-variant-numeric: tabular-nums;
    line-height: 1.1;
}
.meter .meter-val .unit {
    font-family: var(--mono);
    font-size: 11px;
    font-weight: 500;
    color: var(--fog);
    margin-left: 4px;
    letter-spacing: 0.04em;
}
.meter .meter-val .mono {
    font-family: var(--mono);
    font-size: 18px;
    font-weight: 600;
    letter-spacing: 0.01em;
}
.meter.active .meter-val { color: var(--meter-color, var(--blue)); }
.meter[data-status="live"]     { --meter-color: var(--verde); }
.meter[data-status="speaking"] { --meter-color: var(--elettron); }
.meter[data-status="closed"]   { --meter-color: var(--fog); }
.meter[data-status="err"]      { --meter-color: var(--rosso); }
.meter[data-status="idle"]     { --meter-color: var(--fog); }

/* Regione trascrizione: wrapper grid-child della chat (riga 4 della shell).
   In chiamata occupa 1fr e la chat scorre dentro; a chiamata conclusa
   (.shell.esito-open) si comprime sotto il toggle — vedi blocco esito-open. */
.transcript-region {
    display: flex;
    flex-direction: column;
    min-height: 0;
}
.transcript-region .chat { flex: 1 1 auto; }

/* Toggle "Trascrizione · N" — nascosto durante la chiamata, compare a conclusione */
.transcript-toggle { display: none; }

/* Voice transcript bubbles */
.shell .chat {
    border-left: 1px solid var(--rule);
    border-right: 1px solid var(--rule);
}
.turn {
    max-width: 72%;
    padding: 9px 14px 6px;
    font-family: var(--sans);
    font-size: 15px;
    line-height: 1.5;
    position: relative;
    animation: bubbleIn 0.28s cubic-bezier(0.22, 1, 0.36, 1) both;
    word-wrap: break-word;
    overflow-wrap: anywhere;
}
.turn .who {
    font-family: var(--mono);
    font-size: 9.5px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.14em;
    margin-bottom: 3px;
    opacity: 0.65;
}
.turn.assistant {
    align-self: flex-start;
    background: #ffffff;
    color: var(--ink);
    border: 1px solid var(--rule);
    border-radius: 12px 12px 12px 2px;
    box-shadow: 0 1px 2px rgba(15, 30, 51, 0.06);
    margin-top: 8px;
}
.turn.user {
    align-self: flex-end;
    background: var(--blue);
    color: #ffffff;
    border-radius: 12px 12px 2px 12px;
    box-shadow: 0 1px 2px rgba(0, 58, 121, 0.18);
    margin-top: 8px;
}
.turn.assistant + .turn.assistant { border-radius: 12px; margin-top: 2px; }
.turn.user + .turn.user { border-radius: 12px; margin-top: 2px; }
.turn.partial { opacity: 0.62; font-style: italic; }

.chat-empty {
    align-self: center;
    margin: auto 0;
    text-align: center;
    color: var(--fog);
    max-width: 320px;
}
.chat-empty svg {
    width: 64px; height: 64px;
    color: var(--blue);
    opacity: 0.28;
    margin-bottom: 18px;
}
.chat-empty .eyebrow {
    color: var(--ink-dim);
    margin-bottom: 8px;
    display: block;
}
.chat-empty p {
    font-weight: 600;
    font-size: 16px;
    color: var(--ink);
    letter-spacing: -0.01em;
    margin-bottom: 6px;
}
.chat-empty span.hint {
    font-family: var(--mono);
    font-size: 11px;
    letter-spacing: 0.1em;
    color: var(--fog);
    text-transform: uppercase;
}

/* MIC DOCK */
.dock {
    padding: 18px 0 0;
    border-top: 1px solid var(--rule);
    display: grid;
    grid-template-columns: 1fr auto 1fr;
    gap: 24px;
    align-items: center;
}
.dock-l {
    display: flex; flex-direction: column;
    gap: 8px;
    min-width: 0;
}
.dock-l-head {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
}
.dock-l-head .eyebrow { color: var(--ink); }
.dock-l-head .chunks {
    font-family: var(--mono);
    font-size: 10.5px;
    color: var(--fog);
    letter-spacing: 0.06em;
    text-transform: uppercase;
}
.wave-wrap {
    position: relative;
    height: 64px;
    background: var(--paper-2);
    border: 1px solid var(--rule);
    overflow: hidden;
}
.wave-wrap::before {
    content: '';
    position: absolute;
    inset: 50% 0 auto 0;
    height: 1px;
    background: var(--rule);
}
.wave-wrap canvas {
    width: 100%;
    height: 100%;
    display: block;
}

.dock-c {
    display: flex; flex-direction: column;
    align-items: center;
    gap: 10px;
}
.mic-wrap {
    position: relative;
    width: 124px; height: 124px;
    display: grid;
    place-items: center;
}
.ring {
    position: absolute; inset: 0;
    border: 1.5px dashed var(--rule);
    border-radius: 50%;
    pointer-events: none;
    transform: scale(0.7);
    opacity: 0.8;
}
.stage[data-phase="live"] .ring,
.stage[data-phase="speaking"] .ring {
    border-style: solid;
    opacity: 0;
    animation: radar 2.2s cubic-bezier(0.22, 1, 0.36, 1) infinite;
}
.ring:nth-child(2) { animation-delay: 0.7s; }
.ring:nth-child(3) { animation-delay: 1.4s; }
.stage[data-phase="live"]     .ring { border-color: var(--verde); }
.stage[data-phase="speaking"] .ring { border-color: var(--elettron); animation-duration: 1.6s; }
@keyframes radar {
    0%   { transform: scale(0.7); opacity: 0.6; }
    100% { transform: scale(1.4); opacity: 0; }
}

.mic-btn {
    position: relative;
    width: 92px; height: 92px;
    border-radius: 50%;
    /* Sfera: highlight in alto a sx + fondo più scuro → volume 3D */
    background: radial-gradient(circle at 38% 30%,
        color-mix(in srgb, var(--blue) 74%, #ffffff) 0%,
        var(--blue) 52%,
        color-mix(in srgb, var(--blue) 80%, #000000) 100%);
    color: #fff;
    border: 3px solid var(--paper);
    box-shadow:
        0 0 0 1px var(--blue),
        0 18px 36px -16px rgba(0, 58, 121, 0.55),
        inset 0 -6px 14px rgba(0, 0, 0, 0.18),
        inset 0 6px 12px rgba(255, 255, 255, 0.22);
    cursor: pointer;
    display: grid;
    place-items: center;
    transition: background 0.2s, box-shadow 0.2s, filter 0.2s;
    transform: scale(calc(1 + var(--amp) * 0.07));
}
/* Hover: il pulsante si "solleva" verso di te — più luce + ombra portata.
   Uso filter (non transform) per non interferire con la scala audio-reattiva. */
.mic-btn:hover:not(:disabled) {
    filter: brightness(1.08) drop-shadow(0 12px 20px rgba(0, 58, 121, 0.42));
}
.mic-btn:active { transform: scale(0.96); }
.mic-btn:disabled { cursor: wait; opacity: 0.65; }
.stage[data-phase="live"]     .mic-btn { background: var(--blue); box-shadow: 0 0 0 1px var(--blue), 0 0 0 4px rgba(31,153,102,0.18), 0 18px 36px -16px rgba(0,58,121,0.5), inset 0 -6px 14px rgba(0,0,0,0.16); }
.stage[data-phase="speaking"] .mic-btn { background: var(--elettron); box-shadow: 0 0 0 1px var(--elettron), 0 18px 36px -16px rgba(29,124,204,0.5), inset 0 -6px 14px rgba(0,0,0,0.16); }
.stage[data-phase="closed"]   .mic-btn { background: radial-gradient(circle at 38% 30%, color-mix(in srgb, var(--fog) 68%, #ffffff) 0%, var(--fog) 55%, color-mix(in srgb, var(--fog) 78%, #000000) 100%); box-shadow: 0 0 0 1px var(--fog), 0 14px 28px -14px rgba(15,30,51,0.4), inset 0 -6px 14px rgba(0,0,0,0.12), inset 0 6px 12px rgba(255,255,255,0.18); }
.stage[data-phase="err"]      .mic-btn { background: var(--rosso); box-shadow: 0 0 0 1px var(--rosso), 0 18px 36px -16px rgba(200,16,46,0.5), inset 0 -6px 14px rgba(0,0,0,0.16); }

.mic-btn svg { width: 36px; height: 36px; stroke: #fff; fill: none; stroke-width: 2; }
.mic-btn .icon-stop { display: none; }
.stage:not([data-phase="idle"]):not([data-phase="closed"]):not([data-phase="err"]) .mic-btn .icon-mic  { display: none; }
.stage:not([data-phase="idle"]):not([data-phase="closed"]):not([data-phase="err"]) .mic-btn .icon-stop { display: block; }

.mic-cta {
    font-family: var(--mono);
    font-size: 10.5px;
    font-weight: 600;
    color: var(--ink-dim);
    letter-spacing: 0.16em;
    text-transform: uppercase;
    text-align: center;
}

.dock-r {
    display: flex; flex-direction: column;
    gap: 8px;
    min-width: 0;
}
.dock-r-head {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
}
.dock-r-head .eyebrow { color: var(--ink); }
.dock-r-head .chunks {
    font-family: var(--mono);
    font-size: 10.5px;
    color: var(--fog);
    letter-spacing: 0.06em;
    text-transform: uppercase;
}

.shortcut-card {
    background: var(--paper-2);
    border: 1px solid var(--rule);
    height: 64px;
    padding: 0 18px;
    display: flex;
    align-items: center;
    gap: 14px;
}
.shortcut-card kbd {
    display: inline-block;
    font-family: var(--mono);
    font-size: 11px;
    font-weight: 600;
    color: var(--ink);
    background: var(--paper);
    border: 1px solid var(--rule);
    box-shadow: 0 1px 0 var(--paper-3);
    padding: 4px 10px;
    letter-spacing: 0.06em;
    text-transform: uppercase;
}
.shortcut-label {
    font-family: var(--mono);
    font-size: 11px;
    color: var(--ink-dim);
    letter-spacing: 0.04em;
    line-height: 1.35;
}

/* ESITO card — slot fisso fuori dal transcript */
.esito-slot {
    padding: 18px 0 0;
    /* Tetto d'altezza + scroll interno: un esito lungo (diagnostica espansa)
       scorre dentro di sé invece di rubare l'altezza alla trascrizione. Con la
       diagnostica collassata di default il box resta corto e il tetto non si
       attiva quasi mai. */
    max-height: 46vh;
    overflow-y: auto;
}
.esito-slot.hidden { display: none; }
.esito-slot::-webkit-scrollbar { width: 6px; }
.esito-slot::-webkit-scrollbar-thumb { background: var(--rule); border-radius: 3px; }

/* ======================================================
   STATO "esito-open" — chiamata conclusa, focus per fase
   La griglia .shell si ribalta: l'esito diventa l'area focale (1fr), la
   trascrizione si comprime sotto un toggle e il dock si ritira a barra.
   Pensato per il singolo schermo (mobile-first): una cosa importante alla
   volta, niente doppio scroll. La fase live resta invariata.
   ====================================================== */
.shell.esito-open {
    /* top · hero · panel · transcript(auto) · ESITO(1fr) · dock */
    grid-template-rows: auto auto auto auto 1fr auto;
}

/* L'esito riempie la riga focale: niente più tetto a 46vh, scrolla dentro di sé
   solo se davvero lungo (diagnostica espansa). */
.shell.esito-open .esito-slot {
    max-height: none;
    min-height: 0;
    /* Stessa riga d'attacco della trascrizione: border-top + header (esito-head)
       a pari altezza del toggle → i due box partono allineati. */
    border-top: 1px solid var(--rule);
    padding-top: 0;
}

/* Trascrizione compressa: il toggle compare, la chat è nascosta finché non
   la si apre. Aperta, è limitata e scrolla internamente — non ruba il focus. */
.shell.esito-open .transcript-region { border-top: 1px solid var(--rule); }
.shell.esito-open .transcript-toggle {
    display: flex;
    justify-content: space-between;
    align-items: center;
    width: 100%;
    padding: 14px 2px;
    background: none;
    border: none;
    cursor: pointer;
    text-align: left;
}
.shell.esito-open .transcript-toggle .eyebrow { color: var(--ink); }
.transcript-toggle-meta {
    display: flex; align-items: center; gap: 10px;
    font-family: var(--mono);
    font-size: 11px;
    font-weight: 500;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--fog);
}
.tt-chev { font-size: 12px; line-height: 1; transition: transform 0.2s ease; }

/* A chiamata conclusa la trascrizione è sempre visibile (niente overlay).
   Il toggle diventa un'intestazione statica. */
.shell.esito-open .transcript-toggle { pointer-events: none; }
.shell.esito-open .transcript-toggle .tt-chev { display: none; }
.shell.esito-open .transcript-region .chat {
    display: flex;
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
}

/* ===== Layout revisione a due colonne (desktop) ===== */
@media (min-width: 860px) {
    .shell.esito-open {
        grid-template-columns: 1fr 1fr;
        grid-template-rows: auto auto auto 1fr auto;
        grid-template-areas:
            "top    top"
            "hero   hero"
            "panel  panel"
            "trans  esito"
            "dock   dock";
        column-gap: 28px;
    }
    .shell.esito-open .top           { grid-area: top; }
    .shell.esito-open .impianto-hero { grid-area: hero; }
    .shell.esito-open .panel         { grid-area: panel; }
    .shell.esito-open .transcript-region { grid-area: trans; min-height: 0; }
    .shell.esito-open .esito-slot    { grid-area: esito; min-height: 0; overflow-y: auto; max-height: none; }
    .shell.esito-open .dock          { grid-area: dock; }
}

/* ===== Mobile concluso: pagina scrollabile (stack) ===== */
@media (max-width: 859px) {
    .shell.esito-open { height: auto; min-height: 100dvh; }
    .shell.esito-open .transcript-region .chat { max-height: 50vh; }
}

/* ===== Card feedback (collaudo) ===== */
.feedback-card {
    margin-top: 16px;
    padding: 18px 20px 20px;
    border: 1px solid var(--rule);
    border-radius: var(--radius-md);
    background: var(--paper);
    box-shadow: var(--elev-1);
}
.feedback-q { font-weight: 700; font-size: 15px; color: var(--ink); margin: 6px 0 12px; }
.feedback-vote { display: flex; gap: 10px; margin-bottom: 12px; }
.fb-btn {
    flex: 1;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    padding: 11px 14px;
    border-radius: var(--radius-sm);
    border: 1px solid var(--rule);
    background: var(--paper);
    color: var(--ink-dim);
    font: inherit;
    font-weight: 600;
    cursor: pointer;
    transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}
.fb-btn svg { width: 17px; height: 17px; flex-shrink: 0; }
.fb-btn:hover { border-color: var(--blue); color: var(--blue); }
.fb-btn.selected { background: var(--blue); border-color: var(--blue); color: #fff; }
.feedback-note {
    width: 100%;
    border: 1px solid var(--rule);
    border-radius: var(--radius-sm);
    padding: 8px 10px;
    font: inherit;
    resize: vertical;
    outline: none;
    margin-bottom: 12px;
}
.fb-save {
    padding: 9px 20px;
    border-radius: var(--radius-sm);
    border: none;
    background: var(--blue);
    color: #fff;
    font: inherit;
    font-weight: 600;
    cursor: pointer;
}
.fb-save:disabled { opacity: 0.6; cursor: default; }
.fb-confirm {
    margin-top: 10px;
    font-family: var(--mono);
    font-size: 11px;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--verde, #008c45);
}

/* ===== Collaudo nel pannello Storico: scenario (read-only) + feedback (editabile) ===== */
.pane-collaudo {
    flex-shrink: 0;
    border-top: 1px solid var(--rule);
    background: var(--paper);
    padding: 16px 20px 18px;
    overflow-y: auto;
    max-height: 44vh;
}
.pane-collaudo > .eyebrow { color: var(--ink-dim); display: block; margin-bottom: 12px; }
.collaudo-scenario { display: grid; gap: 7px; margin-bottom: 16px; }
.collaudo-scenario .cs-line { display: flex; gap: 12px; align-items: baseline; }
.collaudo-scenario .cs-k {
    flex-shrink: 0;
    min-width: 84px;
    font-family: var(--mono);
    font-size: 10px;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--fog);
}
.collaudo-scenario .cs-v { color: var(--ink); font-size: 14px; line-height: 1.45; }
.pc-feedback .fb-confirm { margin-top: 0; margin-left: 12px; }

/* Dock ritirato: l'oscilloscopio è morto a chiamata conclusa, il mic diventa
   il pulsante "nuova chiamata" — compatto, centrato. */
.shell.esito-open .dock { padding-top: 14px; }
.shell.esito-open .dock-l { display: none; }
.shell.esito-open .mic-wrap { width: 76px; height: 76px; }
.shell.esito-open .mic-btn { width: 56px; height: 56px; }
.shell.esito-open .mic-btn svg { width: 24px; height: 24px; }

.esito-card {
    background: var(--paper);
    color: var(--ink);
    padding: 22px 24px 24px 26px;
    border: 1px solid var(--rule);
    border-radius: var(--radius-lg);
    box-shadow: var(--elev-2);
    position: relative;
    overflow: hidden;
    animation: esitoIn 0.45s cubic-bezier(0.22, 1, 0.36, 1) both;
    align-self: stretch;
    max-width: none;
}
@keyframes esitoIn {
    from { opacity: 0; transform: translateY(12px); }
    to   { opacity: 1; transform: translateY(0); }
}
/* Rail verticale blu Unitec sul lato della card. */
.esito-card::before {
    content: '';
    position: absolute;
    inset: 0 auto 0 0;
    width: 4px;
    background: var(--blue);
}
/* Header gemello del toggle trascrizione: stessa altezza/padding così la card
   esito e il box chat partono allineati. */
.esito-head {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 14px 2px;
    /* Resta ancorato in cima come l'header trascrizione mentre la card scorre.
       Lo slot (.esito-slot) è il contenitore di scroll; lo sfondo opaco copre
       il contenuto che gli scorre sotto. */
    position: sticky;
    top: 0;
    z-index: 2;
    background: var(--paper);
}
.esito-head .eyebrow { color: var(--ink); }
.esito-head-meta {
    display: flex; align-items: center; gap: 8px;
    font-family: var(--mono);
    font-size: 11px;
    font-weight: 500;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--fog);
}
.esito-dot {
    display: inline-block;
    width: 7px; height: 7px;
    border-radius: 50%;
    background: var(--blue);
}
.esito-area { margin-bottom: 18px; }
.esito-area-k {
    display: block;
    font-family: var(--mono);
    font-size: 11px;
    font-weight: 500;
    text-transform: uppercase;
    letter-spacing: 0.14em;
    color: var(--ink-dim);
    margin-bottom: 6px;
}
.esito-area-name {
    display: block;
    font-weight: 800;
    font-size: 30px;
    line-height: 1.05;
    letter-spacing: -0.03em;
    color: var(--blue);
}
.esito-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
    gap: 16px 28px;
    padding-top: 18px;
    border-top: 1px solid var(--rule);
}
.esito-cell .eyebrow {
    color: var(--ink-dim);
    margin-bottom: 4px;
    display: block;
}
.esito-cell-val {
    font-weight: 600;
    font-size: 14.5px;
    line-height: 1.35;
    color: var(--ink);
}

/* Error bar */
.err-bar {
    background: rgba(200, 16, 46, 0.10);
    border-left: 2px solid var(--rosso);
    color: var(--rosso);
    font-family: var(--mono);
    font-size: 12px;
    padding: 8px 12px;
    margin-top: 8px;
    display: none;
    grid-column: 1 / -1;
}
.err-bar.visible { display: block; }

/* ====================================================== */
/* RESPONSIVE                                              */
/* ====================================================== */
@media (max-width: 1080px) {
    .shell .impianto-hero .imp-cell:nth-of-type(3) { display: none; }
    .mode-block .mode-desc { display: none; }
}

@media (max-width: 960px) {
    /* Mobile: sblocca l'altezza del documento E lo scroll del body (il body base
       ha overflow:hidden, che bloccava lo scroll); le schermate crescono col
       contenuto, così la pagina scorre e i bottoni in fondo restano raggiungibili. */
    html, body { height: auto; }
    body { overflow: visible; }
    /* Clip orizzontale a livello viewport: niente sbordo/scroll laterale,
       ma lo scroll verticale resta (html diventa il contenitore di scroll). */
    html { overflow-x: hidden; }
    .start { padding: 28px 32px; height: auto; min-height: 100dvh; }
    .start-main { grid-template-columns: 1fr; gap: 40px; padding: 40px 0; }
    .chat-shell { padding: 20px 24px; }
    .display { font-size: clamp(32px, 7vw, 48px); }
    .impianto-hero { gap: 24px; }
    .history-shell { grid-template-columns: 320px 1fr; }
}

@media (max-width: 860px) {
    .shell { padding: 14px 22px 16px; }
    .shell .top .build { display: none; }
    .mode-block { padding-left: 14px; }
    .shell .impianto-hero { gap: 18px; flex-wrap: wrap; }
    .meters { grid-template-columns: repeat(2, 1fr); gap: 14px; }
    .dock { grid-template-columns: 1fr; gap: 16px; }
    .dock-r { text-align: left; }
}

@media (max-width: 720px) {
    .history-shell { grid-template-columns: 1fr; }
    .hist-side { border-right: none; }
    .history-shell.show-pane .hist-side { display: none; }
    .history-shell:not(.show-pane) .hist-pane { display: none; }
    .pane-msgs { padding: 20px 14px; }
    .bubble { max-width: 85%; }
    .pane-head {
        padding: 14px 16px;
        grid-template-columns: auto 40px 1fr auto;
    }
    .pane-back { display: inline-flex; }
    .pane-avatar { width: 40px; height: 40px; font-size: 14px; }
}

@media (max-width: 640px) {
    .start { padding: 24px 20px; }
    .chat-shell { padding: 18px 16px; }
    .message { max-width: 88%; }
    .mode-picker-row { grid-template-columns: 1fr; }
    .chat-top-meta { gap: 12px; }
    .chat-top-meta .eyebrow { font-size: 10px; }
    .impianto-hero {
        grid-template-columns: 1fr;
        gap: 14px;
        padding: 16px 0 18px;
    }
    .imp-secondary {
        padding-left: 0;
        border-left: none;
        border-top: 1px solid var(--rule);
        padding-top: 14px;
        flex-direction: row;
        justify-content: space-between;
        align-items: center;
    }
    .imp-code { font-size: 38px; }
    .esito-area-name { font-size: 26px; }
    .meter .meter-val { font-size: 18px; }
    .meter .meter-val .mono { font-size: 14px; }
}

/* ====================================================== */
/* DASHBOARD SEGNALAZIONI                                  */
/* ====================================================== */
/* Altezza LIMITATA (non minima): con `body{overflow:hidden}` (riga 66, serve
   alla chat/voce a schermo intero) uno shell che può crescere oltre la
   finestra (`min-height`) non ha mai niente da far scrollare al proprio
   `overflow-y:auto` — cresce e basta, e il contenuto sotto il fold diventa
   irraggiungibile. Con `height` fissa a `100dvh`, lo shell resta alto quanto
   la finestra e lo scroll interno torna reale. Stesso schema già in uso per
   `.chat-shell`/`.shell` (altrove in questo file).
   Un SOLO contenitore scrolla: questo. Le liste figlie (`.cc-list`,
   `.disp-list`) non hanno un'altezza propria, quindi restano normali
   elementi di flusso dentro la colonna — nessuno scroll annidato. Non dargli
   un'altezza/`overflow` propri senza togliere quello dello shell, o si crea
   un doppio scrollbar (comportamento peggiore dell'originale: la rotella fa
   cose diverse a seconda di dove sta il puntatore). #casesScreen fa
   un'eccezione dichiarata più sotto: lì lo scroll è sulla lista, non sullo
   shell — anche in quel caso ne scorre uno solo. */
.dash-shell {
    max-width: 1080px;
    margin: 0 auto;
    height: 100dvh;
    padding: 26px 30px 48px;
    background: var(--paper);
    border-left: 1px solid var(--rule);
    border-right: 1px solid var(--rule);
    display: flex;
    flex-direction: column;
    gap: 22px;
    overflow-y: auto;
}
.dash-shell .hist-head {
    display: flex;
    align-items: center;
    gap: 16px;
    margin: 0;
    padding: 0;
    border: 0;
}
.dash-shell .hist-head h2 {
    font-family: var(--sans);
    font-size: 26px;
    font-weight: 700;
    letter-spacing: -0.01em;
    color: var(--ink);
    margin: 0;
}

/* Toolbar filtri — controlli squadrati, label mono come il resto dell'app */
.dash-filters { display: flex; gap: 10px; flex-wrap: wrap; }
.dash-filters select {
    font-family: var(--mono);
    font-size: 12px;
    letter-spacing: 0.02em;
    color: var(--ink);
    background: var(--paper);
    border: 1px solid var(--rule);
    border-radius: var(--radius-sm);
    box-shadow: var(--elev-1);
    height: 38px;
    /* Freccia nativa rimossa → chevron SVG coerente con gli altri controlli,
       allineato a destra e centrato verticalmente. */
    appearance: none;
    -webkit-appearance: none;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%2348576e' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 12px center;
    background-size: 14px;
    padding: 0 36px 0 14px;
    cursor: pointer;
    transition: border-color 0.15s, box-shadow 0.15s, transform 0.15s;
}
.dash-filters select:hover { border-color: rgba(0, 58, 121, 0.30); box-shadow: var(--elev-2); }
.dash-filters select:focus { outline: none; border-color: var(--blue); }
.dash-filters input[type="text"] {
    font-family: var(--mono);
    font-size: 12px;
    letter-spacing: 0.02em;
    color: var(--ink);
    background: var(--paper);
    border: 1px solid var(--rule);
    border-radius: var(--radius-sm);
    box-shadow: var(--elev-1);
    height: 38px;
    padding: 0 14px;
    min-width: 160px;
    transition: border-color 0.15s, box-shadow 0.15s;
}
.dash-filters input[type="text"]:hover { border-color: rgba(0, 58, 121, 0.30); box-shadow: var(--elev-2); }
.dash-filters input[type="text"]:focus { outline: none; border-color: var(--blue); }
.dash-filters button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    font-family: var(--mono);
    font-size: 12px;
    letter-spacing: 0.02em;
    color: var(--ink);
    background: var(--paper);
    border: 1px solid var(--rule);
    border-radius: var(--radius-sm);
    box-shadow: var(--elev-1);
    height: 38px;
    padding: 0 16px;
    cursor: pointer;
    transition: border-color 0.15s, color 0.15s, box-shadow 0.15s, transform 0.15s;
}
.dash-filters button svg { width: 15px; height: 15px; flex-shrink: 0; }
.dash-filters button:hover { border-color: rgba(0, 58, 121, 0.30); color: var(--blue); box-shadow: var(--elev-2); transform: translateY(-1px); }
.dash-filters button:active { transform: translateY(0); }
.dash-filters button:focus-visible { outline: none; border-color: var(--blue); }

/* KPI strip — 4 celle, numero Archivo blu + label mono maiuscola */
.dash-kpi { display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px; }
.dash-kpi .kpi-cell {
    border: 1px solid var(--rule);
    border-radius: var(--radius-md);
    background: var(--paper);
    box-shadow: var(--elev-1);
    padding: 16px 18px;
    display: flex;
    flex-direction: column;
    gap: 6px;
    transition: box-shadow 0.18s, transform 0.18s;
}
.dash-kpi .kpi-cell:hover { box-shadow: var(--elev-2); transform: translateY(-2px); }
.dash-kpi .kpi-cell b {
    font-family: var(--sans);
    font-size: 28px;
    font-weight: 700;
    line-height: 1;
    letter-spacing: -0.02em;
    color: var(--blue);
}
.dash-kpi .kpi-cell span {
    font-family: var(--mono);
    font-size: 10px;
    letter-spacing: 0.09em;
    text-transform: uppercase;
    color: var(--fog);
}

/* ⚠️ `.dash-tabs` / `.dash-tab` / `.dash-panel` sono state rimosse il
   2026-08-25. I due tab «Distribuzione» e «Andamento» nascondevano metà
   schermata, e il pannello serviva al canvas Chart.js dell'andamento: adesso
   la Dashboard è un flusso unico di riquadri come l'Analisi, e l'andamento è
   il grafico a colonne condiviso. Nessun markup le usava più. */

@media (max-width: 760px) {
    .dash-shell { padding: 20px 16px 40px; }
}

/* ====================================================== */
/* TIER TELEFONO (≤480px) — rifinitura mobile             */
/* In fondo al file: vince la cascata sui breakpoint      */
/* superiori e sul blocco dashboard @760.                 */
/* ====================================================== */
@media (max-width: 480px) {
    /* Chat e voce: su telefono scorrono come pagina invece di restare bloccate
       a 100dvh (il contenuto impilato eccede lo schermo). */
    .chat-shell, .shell { height: auto; min-height: 100dvh; }

    /* --- Touch target ≥44px sui controlli piccoli --- */
    .btn-reset { padding: 10px 14px; min-height: 40px; }
    .hist-back, .pane-back { width: 42px; height: 42px; }
    /* ⚠️ `flex: 1 1 0` con `min-width: 0` DISATTIVA il ritorno a capo: i
       controlli possono restringersi all'infinito, quindi non vanno mai a capo
       e restano tutti su una riga. Su 420 px i sei filtri si leggevano
       «Tu / Tu / Pe / Tu» più due caselle vuote — e nessun errore da nessuna
       parte, né a schermo né nei test.

       Qui si passa a **griglia** invece di aggiustare il flex: due colonne con
       un gap sono esattamente ciò che `repeat(2, 1fr)` sa fare, mentre in flex
       la stessa cosa si scrive `calc(50% - 4px)` — aritmeticamente esatta e
       quindi fragile: basta un pixel di arrotondamento e i due elementi non
       ci stanno più, così vanno a capo tutti e se ne vede uno per riga.
       Provato: succede davvero a 420 px.

       Sopra i 480 px comanda la base in flex, che era già a posto. */
    .dash-filters {
        display: grid;
        grid-template-columns: repeat(2, 1fr);
        gap: 8px;
    }
    .dash-filters select, .dash-filters button,
    .dash-filters input[type="text"] {
        height: 44px;
        width: 100%;
        min-width: 0;
    }

    /* --- Start (flusso operatore) --- */
    .start { padding: 22px 16px; }
    /* Header: su telefono non entra in una riga (logo+brand+stato+orologio+esci).
       Lascio wrappare, riduco il brand e nascondo l'orologio (rumore su mobile). */
    .start-head { flex-wrap: wrap; gap: 10px 12px; padding-bottom: 16px; }
    .brand { gap: 10px; min-width: 0; }
    .brand-mark { height: 32px; }
    .brand-txt { font-size: 13px; }
    .start-meta { gap: 12px; flex-wrap: wrap; }
    .start-meta .eyebrow { font-size: 10px; }
    #startClock { display: none; }
    .access-input input { font-size: 18px; padding: 16px 16px; }
    .display { font-size: clamp(30px, 8vw, 40px); }

    /* --- Chat: banner aree 4→2 colonne, code più piccolo --- */
    .chat-shell { padding: 16px 14px; }
    .area-banners { grid-template-columns: repeat(2, 1fr); }
    .imp-code { font-size: 28px; }

    /* --- Voice: padding compatti, niente overflow celle hero --- */
    .shell { padding: 14px 16px 16px; }
    .imp-cell { min-width: 72px; }
    .imp-cell-val { font-size: 20px; }
    .esito-area { font-size: 24px; }
    /* Niente sbordo orizzontale: i figli flex/grid possono restringersi e i
       contenitori/canvas non superano la larghezza schermo. */
    .panel, .dock, .impianto-hero, .chat, .esito-slot { max-width: 100%; }
    .meters .meter, .dock-l, .dock-r, .imp-primary { min-width: 0; }
    .wave-wrap, .wave-wrap canvas, #wave { max-width: 100%; }
    .meter-val .mono { word-break: break-word; }
    /* Hero voce: è `display:flex` con `.shell .imp-primary{margin-right:auto}`
       (specificità 0,2,0) → la regola di collasso generica non la batte. Qui la
       impilo con la STESSA specificità: impianto a piena riga, livello/paese sotto. */
    .shell .impianto-hero { flex-wrap: wrap; gap: 14px 16px; }
    .shell .imp-primary { margin-right: 0; flex: 1 1 100%; }
    .shell .imp-sub { flex-wrap: wrap; }
    .shell .meters { grid-template-columns: 1fr 1fr; }
    /* Header voce: anche `.top` non deve sbordare */
    .shell .top { flex-wrap: wrap; gap: 10px; }
    .shell .top .mode-block { display: none; }

    /* --- Dashboard --- */
    .dash-shell { padding: 18px 14px 36px; }
    .dash-kpi { gap: 8px; }
    .dash-kpi .kpi-cell { padding: 13px 12px; }
    .dash-kpi .kpi-cell b { font-size: 22px; }
}

/* Telefoni molto stretti (≤360px) */
@media (max-width: 360px) {
    .imp-code { font-size: 24px; }
    .display { font-size: 28px; }
    .access-input input { font-size: 17px; }

    /* ⚠️ Queste due regole erano finite nel blocco ≤480 qui sopra, dove
       vincono per ordine su quelle dello stesso blocco: i filtri restavano a
       una colonna anche a 420 px, cioè il difetto che dovevano risolvere.
       Un `@media` non aumenta la specificità — a parità, comanda chi viene
       dopo, e «dopo» non vuol dire «più stretto». */
    .dash-filters { grid-template-columns: 1fr; }
    /* 53 mensilità su 360 px non stanno con gli spazi da 2 px. */
    .an-colonne.fitte, .an-colonne-x.fitte { gap: 1px; }
}

/* --- Consulta CASE --- */
.cases-head-row, .cases-row {
    display: grid;
    grid-template-columns: 152px 110px 90px 90px 1fr 18px;
    gap: 8px;
    align-items: center;
}
.cases-head-row {
    padding: 6px 12px;
    font: 600 11px/1.4 ui-monospace, monospace;
    text-transform: uppercase;
    letter-spacing: .04em;
    color: var(--fog, #888);
    border-bottom: 1px solid var(--rule, #e3e3e3);
}
.cases-list { display: flex; flex-direction: column; overflow: auto; }
.cases-row {
    width: 100%;
    text-align: left;
    background: none;
    border: none;
    border-bottom: 1px solid var(--rule, #eee);
    padding: 10px 12px;
    cursor: pointer;
    font: inherit;
}
.cases-row:hover { background: var(--paper, #f6f6f6); }
/* Nessuna cella deve sbordare su quella accanto: in una griglia un elemento non
   si stringe sotto la larghezza del suo contenuto finche' non gli si dice
   `min-width:0`. Senza, un valore lungo ("Teleassistenza") scavalca la colonna
   successiva invece di troncarsi. */
.cases-row > span, .cases-head-row > span {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
/* Storico dal gestionale: i valori del CRM sono piu' lunghi dei nostri
   ("Teleassistenza" contro "voice", la data completa con l'anno), quindi le
   prime colonne respirano di piu'. */
.cases-list.gestionale .cases-row,
.cases-head-row.gestionale {
    grid-template-columns: 152px 128px 90px 132px 1fr 18px;
}
/* «I miei case»: stessa tabella dello Storico interno, una colonna in più
   (Macchina) e una sola data senza ora — al cliente serve il giorno, non il
   minuto. Le classi sono le stesse di proposito: due fogli di stile per la
   stessa tabella sono due tabelle che col tempo smettono di somigliarsi. */
/* ⚠️ **Colonne tutte uguali, e l'avanzo si spartisce fra tutte.**
   Storia breve di due difetti opposti, perché il prossimo che tocca queste
   larghezze non li rifaccia:
   1. un `1fr` sulla sola AREA — la colonna col contenuto più CORTO — le faceva
      assorbire tutto l'avanzo, aprendo un buco prima di STATO, mentre MACCHINA
      aveva 118px fissi e troncava i codici a metà (`MM0510981-…`);
   2. larghezze tutte fisse tagliate sul contenuto: niente più troncamenti, ma
      il buco si è solo spostato fra MACCHINA e AREA, perché 300px di colonna
      per un codice da 15 caratteri restano 180px vuoti.
   Il difetto comune è che l'avanzo finiva tutto in UN punto. Sei frazioni
   uguali lo distribuiscono, e ogni colonna si adatta alla larghezza dello
   schermo senza numeri da ritoccare.
   `minmax(0, 1fr)` e non `1fr`: senza il minimo a zero una cella non può
   scendere sotto il proprio contenuto, e una descrizione lunga allargherebbe
   la sua colonna a spese delle altre invece di troncarsi. */
.cases-list.cliente .cases-row,
.cases-head-row.cliente {
    grid-template-columns: repeat(6, minmax(0, 1fr)) 18px;
}
/* ⚠️ Lo scroll interno NO: nella schermata cliente a scorrere è lo shell
   (`.dash-shell`), un solo contenitore. Ereditandolo si otterrebbero due
   aree che scorrono una dentro l'altra, e la lista si schiaccerebbe. */
.cases-list.cliente { overflow: visible; }
.cases-caseid { font-family: var(--mono, ui-monospace, monospace); font-weight: 600; font-size: 12.5px; color: var(--blue); letter-spacing: .01em; white-space: nowrap; }
/* Nell'elenco del cliente il numero porta accanto il segno «c'è la
   conversazione»: serve una riga flex, o il badge va a capo. */
.cases-list.cliente .cases-caseid { display: inline-flex; align-items: center; gap: .35rem; }
/* La macchina è contesto, non il fatto: sta un gradino sotto le altre celle. */
.cases-macchina { opacity: .75; }
.cases-area { font-weight: 600; }
/* Affordance "clicca per espandere": chevron a destra, hover marcato, riga aperta */
.cases-chev {
    justify-self: end;
    color: var(--fog, #aaa);
    font-size: 18px;
    line-height: 1;
    transition: transform .15s ease, color .15s ease;
}
.cases-row:hover { background: var(--paper, #eef2fb); }
.cases-row:hover .cases-chev { color: var(--blue, #6b8cce); transform: translateX(2px); }
/* La lista è un flex column scrollabile: le righe non devono MAI restringersi
   (con overflow:hidden sull'item aperto il flex lo comprimerebbe a 0, nascondendo
   il dettaglio su schermi bassi). Deve scrollare il contenitore, non la riga. */
.case-item { flex-shrink: 0; }

/* Riga espansa = card raggruppata Apple-style: arrotondata, sollevata, niente
   barra blu dura a sinistra. Il bordo-divisore della riga sparisce dentro la card. */
.case-item.open {
    border-radius: var(--radius-md);
    background: var(--paper-2);
    box-shadow: var(--elev-2);
    overflow: hidden;
    margin: 6px 0;
}
.case-item.open .cases-row { background: transparent; border-bottom: 1px solid var(--rule); }
.case-item.open .cases-chev { transform: rotate(90deg); color: var(--blue, #6b8cce); }
.cases-empty { padding: 20px; color: var(--fog, #888); text-align: center; }

/* Dettaglio INLINE: si espande sotto la riga, dentro la lista (le righe sotto
   scorrono giù). Niente pannello che copre la lista. Visibile solo da aperto. */
.case-inline {
    display: none;
    padding: 12px 16px 18px;
    background: var(--paper-2);
}
.case-item.open .case-inline { display: block; }
.case-detail-title {
    font-family: var(--mono);
    font-size: 11px;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--fog);
}
.case-detail-head {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 10px;
}
.case-dl {
    text-decoration: none;
    font-weight: 600;
    border: 1px solid var(--blue, #6b8cce);
    color: var(--blue, #6b8cce);
    border-radius: var(--radius-sm);
    padding: 7px 12px;
    box-shadow: var(--elev-1);
    transition: background 0.15s, color 0.15s, box-shadow 0.15s, transform 0.15s;
}
.case-dl:hover {
    background: var(--blue);
    color: #fff;
    box-shadow: var(--elev-2);
    transform: translateY(-1px);
}
.case-field {
    display: grid;
    grid-template-columns: 160px 1fr;
    gap: 10px;
    padding: 5px 0;
    border-bottom: 1px solid var(--rule, #f0f0f0);
}
.case-field-k { color: var(--fog, #888); font-size: 13px; }
.case-field-v { white-space: pre-wrap; }

/* Layout Consulta CASE: qui a scrollare non è lo shell ma la lista, con
   l'intestazione filtri sopra che resta ferma — eccezione dichiarata al
   "un solo contenitore scrolla" di .dash-shell (vedi il commento lì): qui il
   contenitore che scorre è .cases-list, quindi lo shell smette di farlo. */
#casesScreen {
    height: 100dvh;
    min-height: 0;
    overflow: hidden;
}
#casesScreen .cases-list {
    flex: 1 1 auto;
    min-height: 0;        /* indispensabile perché overflow:auto scrolli in flex */
    overflow-y: auto;
}

/* --- Consulta CASE su telefono ---
   Il grid a 6 colonne fisse (~620px) non entra in uno schermo da ~345px → le
   colonne collassano e i valori si disallineano dall'intestazione. Su mobile
   passo a una riga IMPILATA (card): l'intestazione tabellare sparisce, ogni CASE
   mostra ID + area sulla prima riga e data · impianto · canale come meta sotto. */
@media (max-width: 600px) {
    .cases-head-row { display: none; }
    .cases-head-row, .cases-row {
        grid-template-columns: auto auto auto 1fr auto;
        grid-template-areas:
            "caseid caseid caseid area chev"
            "date   imp    canale .    .";
        column-gap: 8px;
        row-gap: 5px;
        align-items: center;
    }
    .cases-row { padding: 14px 16px; }
    .cases-caseid { grid-area: caseid; font-size: 13.5px; }
    .cases-area   { grid-area: area; justify-self: end; text-align: right; font-size: 13px; }
    .cases-chev   { grid-area: chev; align-self: center; }
    .cases-date   { grid-area: date; }
    .cases-imp    { grid-area: imp; }
    .cases-canale { grid-area: canale; }
    .cases-date, .cases-imp, .cases-canale {
        font-size: 12px;
        color: var(--fog);
        white-space: nowrap;
    }
    /* L'area aperta resta una card raggruppata: ok così. */
}

/* ===== Collaudo: scenario pre-chiamata ===== */
/* ===== Collaudo: scenario pre-chiamata (sezione di test nel pannello blu) =====
   Vive dentro .access-panel (testo bianco su blu). Staccata dalla scelta
   impianto con una hairline, con respiro verticale tra label, campo, area e chip. */
.collaudo-pre {
    margin-top: 24px;
    padding-top: 22px;
    border-top: 1px solid rgba(255, 255, 255, 0.16);
}
.collaudo-pre .access-field-label { margin-bottom: 10px; }
.collaudo-pre .access-input { margin-bottom: 20px; }
.collaudo-pre textarea {
    width: 100%;
    border: none;
    background: transparent;
    padding: 14px 16px;
    min-height: 62px;
    font-family: var(--sans);
    font-size: 15px;
    line-height: 1.5;
    color: #ffffff;
    resize: vertical;
    outline: none;
}
.collaudo-pre textarea::placeholder { color: rgba(255, 255, 255, 0.4); }
/* "Area attesa" eyebrow: respiro prima dei chip */
.collaudo-pre .eyebrow { margin-bottom: 11px; }
.area-chips { display: flex; gap: 9px; flex-wrap: wrap; }
.area-chip {
    font-family: var(--mono);
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.06em;
    padding: 8px 17px;
    border-radius: 999px;
    border: 1px solid rgba(255, 255, 255, 0.28);
    background: rgba(255, 255, 255, 0.06);
    color: rgba(255, 255, 255, 0.85);
    cursor: pointer;
    transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}
.area-chip:hover:not(.disabled) {
    border-color: #ffffff;
    background: rgba(255, 255, 255, 0.14);
    color: #ffffff;
}
.area-chip.selected {
    background: #ffffff;
    border-color: #ffffff;
    color: var(--blue);
}
.area-chip.disabled {
    opacity: 0.32;
    cursor: not-allowed;
    background: transparent;
}

.case-scenario {
    font-family: var(--mono);
    font-size: 10px;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--fog);
    border: 1px solid var(--rule);
    border-radius: 999px;
    padding: 1px 6px;
}

#credClienti, #credInterne { max-height: var(--finestra-elenco-alta); }

/* ===== Credenziali: stato dell'utenza =====
   Solo due stati, e si leggono anche senza colore: la parola c'è scritta.
   ⚠️ Token del progetto, niente letterali: `--ink-dim` e `--fog` esistono già,
   e il rosso è quello che la vigilanza usa per le righe bloccate. */
.cred-stato-attiva,
.cred-stato-ritirata {
    font-family: var(--mono);
    font-size: 10px;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    border-radius: 999px;
    padding: 2px 8px;
}
.cred-stato-attiva { color: var(--ink-dim); border: 1px solid var(--rule); }
.cred-stato-ritirata {
    color: var(--rosso);
    border: 1px solid currentColor;
}
/* La riga ritirata resta leggibile: si smorza, non sparisce — serve poterla
   ritrovare per ripristinarla. */
.cred-ritirata .vig-utente { color: var(--fog); }

/* ======================================================================
   Visibilità per ruolo + vista "I miei case" (cliente)
   ---------------------------------------------------------------------
   Nascondere in CSS NON è un controllo di sicurezza: è ergonomia. Le
   difese vere stanno nel backend (api/auth_http.py per l'accesso,
   api/tenant.py per il perimetro, la whitelist di api/client_dashboard.py
   per i campi). Qui si evita solo di proporre porte che si aprirebbero
   con un 404.
   ====================================================================== */

body:not(.role-cliente) .only-cliente { display: none; }
body.role-cliente .only-staff { display: none; }
/* "Registro accessi": solo admin. Come sopra, il nascondere qui non è la
   protezione — quella è il 404 di solo_admin lato server. */
body:not(.role-admin) .only-admin { display: none; }

.pilot-option-empty {
    padding: 14px 16px;
    color: var(--fog);
    font-size: 13px;
}

/* --- sintesi in testa --- */
.cc-summary {
    display: flex;
    flex-wrap: wrap;
    gap: 12px;
    padding: 16px 20px 4px;
}
.cc-tile {
    min-width: 150px;
    padding: 14px 16px;
    border: 1px solid rgba(255, 255, 255, .08);
    border-radius: 10px;
    background: rgba(255, 255, 255, .03);
}
.cc-tile-valore { display: block; font-size: 26px; font-weight: 600; line-height: 1.1; }
.cc-tile-label { display: block; margin-top: 4px; font-size: 12px; opacity: .65; }
.cc-tile-aree { min-width: 220px; }
.cc-area-riga { display: flex; justify-content: space-between; gap: 12px; margin-top: 6px; font-size: 13px; }
.cc-area-nome { opacity: .85; }
.cc-area-n { font-variant-numeric: tabular-nums; opacity: .65; }

/* --- elenco e dettaglio ---
   Dal 2026-09-08 «I miei case» usa la STESSA tabella di «Consulta CASE»
   (`.cases-head-row.cliente`, `.cases-list.cliente`, `.case-item`): qui sotto
   restano solo le due cose che sono davvero sue. Le vecchie regole `.cc-riga`
   / `.cc-detail*` sono state tolte, non lasciate scollegate: un foglio di
   stile con dentro due tabelle per la stessa schermata è il modo in cui le
   due, col tempo, smettono di somigliarsi. */

/* «Sunto della conversazione» è un campo come gli altri — stessa etichetta,
   stessa colonna — ma il contenuto è un paragrafo, non una frase sola:
   respiro e a capo naturale anche su parole lunghe, mai scroll orizzontale. */
.case-field-v.cc-detail-riassunto {
    padding: 10px 12px;
    border-radius: 8px;
    background: rgba(0, 0, 0, .03);
    line-height: 1.5;
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}

/* Il segno che un case porta con sé la conversazione. */
.cc-badge-conv { flex-shrink: 0; font-size: .85em; opacity: .75; }

/* ======================================================================
   "Ricordami" + Dispositivi collegati
   ====================================================================== */

.ricordami {
    display: flex;
    align-items: center;
    gap: 9px;
    margin: 4px 0 10px;
    font-size: 13px;
    opacity: .8;
    cursor: pointer;
    user-select: none;
}
.ricordami input { width: 15px; height: 15px; accent-color: #cfa15a; cursor: pointer; }

.disp-nota {
    margin: 4px 20px 14px;
    max-width: 58ch;
    font-size: 13px;
    line-height: 1.5;
    opacity: .65;
}
/* ⚠️ Fino al 2026-09-01 qui c'era scritto «nessun overflow proprio: scrolla lo
   shell», ed era una scelta. L'ha rovesciata lui: con quattro elenchi in una
   pagina, far scorrere lo shell vuol dire scorrere tutto per arrivare al
   quarto. Ora ogni elenco è una finestra a sé (`.elenco-finestra`), e lo shell
   scorre solo fra un elenco e l'altro. */
.disp-list { padding: 0 20px 20px; }
.disp-riga {
    display: grid;
    grid-template-columns: 1fr auto;
    grid-template-areas: "testa bottone" "meta bottone";
    gap: 4px 16px;
    align-items: center;
    padding: 14px 16px;
    margin-bottom: 10px;
    border: 1px solid rgba(255, 255, 255, .08);
    border-radius: 10px;
    background: rgba(255, 255, 255, .03);
}
.disp-corrente { border-color: rgba(207, 161, 90, .45); }
.disp-testa { grid-area: testa; display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.disp-nome { font-size: 15px; font-weight: 600; }
.disp-badge {
    padding: 2px 8px;
    border-radius: 999px;
    background: rgba(207, 161, 90, .18);
    color: #cfa15a;
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: .05em;
}
.disp-badge-lieve {
    padding: 2px 8px;
    border-radius: 999px;
    background: rgba(255, 255, 255, .07);
    font-size: 11px;
    opacity: .7;
}
.disp-meta {
    grid-area: meta;
    display: flex;
    flex-wrap: wrap;
    gap: 4px 18px;
    font-size: 12px;
    opacity: .6;
}
.disp-stacca {
    grid-area: bottone;
    padding: 8px 14px;
    border: 1px solid rgba(255, 255, 255, .18);
    border-radius: 8px;
    background: none;
    color: inherit;
    font: inherit;
    font-size: 13px;
    cursor: pointer;
}
.disp-stacca:hover:not(:disabled) { background: rgba(255, 255, 255, .07); }
.disp-stacca:disabled { opacity: .4; cursor: default; }
.disp-vuoto { display: block; padding: 20px 0; opacity: .6; font-size: 13px; }

@media (max-width: 620px) {
    .disp-riga {
        grid-template-columns: 1fr;
        grid-template-areas: "testa" "meta" "bottone";
        gap: 8px;
    }
    .disp-stacca { justify-self: start; }
}

/* ====================================================== */
/* VIGILANZA — Accessi e sessioni / Registro accessi        */
/* Stesso pattern di .disp-riga (righe con azioni) esteso   */
/* con una seconda azione (Disattiva) e righe di log a       */
/* larghezza piena (tentativi, eventi, registro). Un solo    */
/* contenitore scrolla: lo shell (.dash-shell); queste liste  */
/* sono flusso normale, nessun overflow proprio.              */
/* ====================================================== */
.vig-section-titolo {
    font-family: var(--mono);
    font-size: 11px;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--fog);
    margin: 22px 0 10px;
}
.vig-section-titolo:first-child { margin-top: 0; }

/* Glossario Cliente / Utente / Dispositivo in testa alle schermate accessi:
   termine a sinistra, definizione a destra, un riquadro solo. */
.glossario-accessi {
    display: grid;
    grid-template-columns: max-content 1fr;
    gap: 8px 18px;
    max-width: 82ch;
    margin: 0 0 16px;
    padding: 12px 16px;
    font-size: 13px;
    line-height: 1.5;
    color: var(--ink-dim);
    background: var(--paper-2);
    border: 1px solid var(--rule);
    border-radius: var(--radius-md);
}
.glossario-accessi dt {
    font-size: 11px;
    font-weight: 700;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--ink);
    padding-top: 2px;
}
.glossario-accessi dd { margin: 0; }
.glossario-accessi strong { color: var(--ink); font-weight: 600; }
.glossario-accessi code { font-size: 12px; color: var(--ink); }
.glossario-accessi--cliente { margin: 4px 20px 14px; }

.vig-nota {
    max-width: 62ch;
    font-size: 13px;
    line-height: 1.5;
    opacity: .65;
    margin: 0 0 10px;
}

/* --- sessioni attive: card, come .disp-riga con un'azione in più --- */
.vig-riga {
    display: grid;
    grid-template-columns: 1fr auto;
    grid-template-areas: "testa azioni" "meta azioni";
    gap: 4px 16px;
    align-items: center;
    padding: 14px 16px;
    margin-bottom: 10px;
    border: 1px solid rgba(255, 255, 255, .08);
    border-radius: 10px;
    background: rgba(255, 255, 255, .03);
}
.vig-riga-testa { grid-area: testa; display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }

/* --- il dispositivo, e dentro le sue sessioni ---
   Un `<details>`: apre e chiude senza JS, va da tastiera, e lo legge una
   sintesi vocale. Il capo ha la stessa griglia di `.vig-riga` — è la stessa
   riga, con dentro le sue sessioni invece che una sola. */
.vig-dispositivo { margin-bottom: 10px; }
.vig-dispositivo-capo {
    display: grid;
    grid-template-columns: 1fr auto;
    grid-template-areas: "testa azioni" "meta azioni";
    gap: 4px 16px;
    align-items: center;
    padding: 14px 16px;
    border: 1px solid var(--rule);
    border-radius: var(--radius-md);
    background: var(--paper-2);
    cursor: pointer;
    /* Il triangolino di serie sfonderebbe la griglia: il verso lo dà il nostro,
       disegnato nel `::after` del capo. */
    list-style: none;
}
.vig-dispositivo-capo::-webkit-details-marker { display: none; }
/* Il verso sta IN TESTA alla riga, non in coda ai metadati: là si leggeva
   come una coda della frase «Ultimo accesso: …», non come un comando. */
.vig-dispositivo-capo .vig-riga-testa::before {
    content: '▸';
    color: var(--fog);
    font-size: 11px;
}
.vig-dispositivo[open] .vig-dispositivo-capo .vig-riga-testa::before { content: '▾'; }
.vig-dispositivo-dentro {
    padding: 10px 0 2px 16px;
    border-left: 2px solid var(--rule);
    margin: 8px 0 0 16px;
}
.vig-dispositivo-dentro .vig-riga:last-child { margin-bottom: 0; }
.vig-utente { font-size: 15px; font-weight: 600; }
.vig-riga-meta {
    grid-area: meta;
    display: flex;
    flex-wrap: wrap;
    gap: 4px 18px;
    font-size: 12px;
    opacity: .6;
}
.vig-riga-azioni {
    grid-area: azioni;
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 6px;
}

.vig-badge {
    padding: 2px 8px;
    border-radius: 999px;
    background: rgba(0, 58, 121, .12);
    color: var(--blue);
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: .05em;
}
.vig-badge-lieve {
    padding: 2px 8px;
    border-radius: 999px;
    background: rgba(255, 255, 255, .07);
    font-size: 11px;
    opacity: .7;
}
.vig-badge-bloccato {
    padding: 2px 8px;
    border-radius: 999px;
    background: rgba(200, 16, 46, .16);
    color: var(--rosso);
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: .05em;
}

/* --- azione con conferma inline (mai confirm()/alert(), vietati qui) --- */
/* `position: relative` è il gancio del pannello di conferma qui sotto: senza,
   il pannello si aggancerebbe al primo antenato posizionato — che è la
   schermata — e finirebbe dall'altra parte della pagina. */
.vig-azione { display: inline-flex; align-items: center; flex-wrap: wrap; gap: 6px; position: relative; }

/* ⛔ Il pannello della conferma sta SOPRA la riga, non dentro il flusso.

   Misurato: in flusso, aprire la conferma faceva crescere la riga da 67 a 86
   pixel e spingeva giù di 19px tutto quello che seguiva. È il meccanismo con
   cui il 2026-09-01 due utenze vere sono state disattivate: il secondo clic è
   atterrato su una riga diversa da quella che si stava guardando. Fuori dal
   flusso la riga non cambia altezza, e niente si muove.

   ⛔ `white-space: nowrap` + `max-width` sul testo è la coppia che il 2026-09-07
   ha prodotto il difetto visibile a schermo: la domanda NON andava a capo e non
   veniva troncata — **traboccava in silenzio** dal proprio riquadro da 34ch,
   mentre i bottoni venivano disposti *dopo* quel riquadro. Risultato:
   «Uscirà immedia**Conferma**te», con il bottone sopra le parole.
   🔑 Un limite di larghezza tiene solo se il contenuto può cedere: o va a capo,
   o si tronca. Con `nowrap` non fa né l'uno né l'altro, e nessuno protesta.

   Adesso il pannello va a capo (`white-space: normal`) e la larghezza la
   decide il contenuto fino a un tetto: una domanda corta resta su una riga
   come prima, una lunga diventa un pannellino di due righe.
   ⚠️ Che cresca in altezza è accettabile, e non contraddice la nota qui sopra:
   quello che deve restare fermo è **la riga**, non il pannello. Il pannello è
   fuori dal flusso, opaco e sopra: se copre la riga vicina, un clic finito
   lungo atterra su di lui — che è il modo giusto di sbagliare.

   ⚠️ Fondo OPACO e ombra: è un piano sopra, e deve leggersi come tale. Un
   pannello semitrasparente sopra un elenco di nomi si legge come parte della
   riga sotto — cioè come il bersaglio sbagliato. */
.vig-conferma {
    position: absolute;
    right: 0;
    top: 50%;
    transform: translateY(-50%);
    z-index: 4;
    display: flex;
    align-items: center;
    gap: 8px;
    white-space: normal;
    width: max-content;
    max-width: min(34rem, calc(100vw - 48px));
    padding: 7px 10px;
    background: var(--paper);
    border: 1px solid var(--rosso);
    border-radius: var(--radius-md);
    box-shadow: var(--elev-2);
}
.vig-btn {
    padding: 7px 13px;
    border: 1px solid rgba(255, 255, 255, .18);
    border-radius: 8px;
    background: none;
    color: inherit;
    font: inherit;
    font-size: 13px;
    cursor: pointer;
}
.vig-btn:hover:not(:disabled) { background: rgba(255, 255, 255, .07); }
.vig-btn:disabled { opacity: .5; cursor: default; }
.vig-btn-disattiva { border-color: rgba(200, 16, 46, .4); color: var(--rosso); }
.vig-conferma-testo { font-size: 12px; opacity: .8; line-height: 1.4; }
.vig-conferma .vig-btn { flex: 0 0 auto; }
.vig-btn-conferma { border-color: var(--rosso); color: var(--rosso); font-weight: 600; }
.vig-btn-annulla { opacity: .7; }
.vig-errore { display: block; width: 100%; font-size: 11px; color: var(--rosso); margin-top: 4px; }

/* --- bloccati ora --- */
.vig-bloccati-ok { display: block; font-size: 13px; opacity: .6; padding: 6px 0 16px; }
.vig-bloccato-riga {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 10px;
    padding: 8px 12px;
    margin-bottom: 6px;
    border-left: 2px solid var(--rosso);
    background: rgba(200, 16, 46, .06);
    font-size: 13px;
}

/* --- righe di log a larghezza piena: tentativi, eventi, registro --- */
.vig-log-riga {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 4px 16px;
    padding: 9px 12px;
    font-size: 12.5px;
    border-bottom: 1px solid var(--rule);
}
.vig-log-riga:hover { background: rgba(0, 0, 0, .02); }
.vig-log-fallito { color: var(--rosso-dim); }
.vig-log-bloccato { border-left: 2px solid var(--rosso); background: rgba(200, 16, 46, .05); }
.vig-log-quando, .vig-log-ip { font-family: var(--mono); opacity: .7; white-space: nowrap; }
/* Il dispositivo è un'informazione di contorno: si legge se la cerchi,
   non compete con l'evento e con l'utente. `overflow-wrap` perché uno
   user-agent non riconosciuto si mostra grezzo e può essere lungo. */
.vig-log-disp { font-family: var(--mono); font-size: 11.5px; opacity: .55; overflow-wrap: anywhere; }
.vig-log-utente { font-weight: 600; overflow-wrap: anywhere; }
.vig-log-evento { opacity: .85; }
.vig-log-esito { font-family: var(--mono); font-size: 11px; }
.vig-reg-riga1, .vig-log-riga2 { display: flex; flex-wrap: wrap; gap: 4px 14px; width: 100%; }
.vig-reg-metodo { font-family: var(--mono); font-weight: 700; }
.vig-reg-percorso { font-family: var(--mono); opacity: .85; overflow-wrap: anywhere; }
.vig-reg-azione { font-weight: 600; overflow-wrap: anywhere; cursor: help; }
.vig-reg-query { opacity: .55; font-size: 11px; overflow-wrap: anywhere; }

/* --- riepilogo per cliente --- */
.vig-riep-riga {
    display: flex;
    flex-wrap: wrap;
    gap: 4px 18px;
    padding: 10px 12px;
    font-size: 12.5px;
    border-bottom: 1px solid var(--rule);
}
.vig-riep-cliente { font-weight: 600; min-width: 160px; }

.vig-vuoto { display: block; padding: 20px 0; opacity: .6; font-size: 13px; }

@media (max-width: 620px) {
    .vig-riga {
        grid-template-columns: 1fr;
        grid-template-areas: "testa" "meta" "azioni";
        gap: 8px;
    }
    .vig-riga-azioni { align-items: flex-start; flex-direction: row; flex-wrap: wrap; }
}

/* ===== Ex stili inline =====================================================
   Stavano come attributo `style=` nell'HTML. Un solo attributo inline obbliga
   la CSP a concedere `style-src 'unsafe-inline'`, e quella concessione non è
   per attributo: vale per tutta la pagina. Il `display` non è qui di proposito
   — lo governa il JS (`showPaneView`/`showPaneEmpty`) insieme alla classe
   `.hidden`, e riportarlo nel foglio cambierebbe chi comanda. */
#paneView {
    flex: 1;
    flex-direction: column;
    min-height: 0;
}

/* ===== Viste analitiche (Analisi e Dashboard) =============================
   Le due schermate sono la stessa vista con una misura diversa (vedi
   js/vista-analitica.js): queste regole valgono per tutte e due.

   ⚠️ Niente qui dentro va ancorato a #dashboardScreen. È già
   costato una volta: la palette dati stava sulla schermata analitica e dentro la
   Dashboard `var(--dato-gestionale)` non risolveva — barre della larghezza
   giusta e sfondo trasparente. Una var() che non risolve NON è un errore per
   il browser: la dichiarazione sparisce in silenzio. */

/* Le colonne le detta il NUMERO DI TESSERE, e lo scrive `renderKpi()`.

   Prima erano `auto-fit, minmax(160px, 1fr)`, con in testa il commento «le
   tessere KPI sono 3 o 4». Dal 2026-09-01 all'admin sono **sei** — la
   Dashboard ha assorbito l'Analisi e i costi sono due tessere in più — e
   auto-fit ne metteva cinque in fila lasciando la sesta a capo, da sola.
   Nessun valore fisso di `minmax` risolve i due casi insieme: quello che fa
   tre colonne con sei tessere ne farebbe tre anche con quattro, rimettendo
   l'orfana dall'altra parte.

   ⚠️ Il fallback nel `var()` non è cortesia. Una `var()` che non risolve **non
   è un errore per il browser**: la dichiarazione sparisce in silenzio e la
   griglia resta senza colonne dichiarate. Se il JS non scrive la proprietà —
   uno stato di partenza, un errore prima di `renderKpi()` — si torna alle
   quattro colonne di prima, che è un difetto di impaginazione e non una
   pagina rotta. */
.dash-kpi { grid-template-columns: repeat(var(--kpi-colonne, 4), 1fr); }

/* La cella KPI porta anche una nota sotto l'etichetta (che cosa c'è nel numero,
   o perché è un trattino). ⚠️ Era `#anKpi .kpi-cell em`, cioè legata a un id:
   sulla Dashboard la nota c'era nel DOM e non si vedeva. Stessa famiglia di
   difetto della palette qui sopra — una regola che vale per una schermata sola
   perché è stata scritta quando la schermata era una sola. */
.dash-kpi .kpi-cell em {
    display: block; font-style: normal; font-size: 12px; line-height: 1.35;
    color: var(--ink-dim); margin-top: 6px;
}

.an-tabella-wrap { overflow-x: auto; }
.an-tabella { width: 100%; border-collapse: collapse; margin-top: 1rem; }
.an-tabella th, .an-tabella td { padding: .4rem .6rem; text-align: left; border-bottom: 1px solid var(--rule); }
.an-tabella td:not(:first-child), .an-tabella th:not(:first-child) { text-align: right; font-variant-numeric: tabular-nums; }
/* §6 del piano: l'impianto resta leggibile a sinistra come il resto del
   testo — solo le colonne numeriche vanno a destra. Classe, non uno
   `style=` inline: la CSP lo bloccherebbe comunque. */
.an-tabella td.an-col-testo, .an-tabella th.an-col-testo { text-align: left; font-variant-numeric: normal; }
/* La tabella delle chiamate ha 16 colonne: senza `nowrap` data, case e macchina
   si spezzano su tre righe prima che il contenitore cominci a scorrere. */
#dashChiamate th, #dashChiamate td { white-space: nowrap; }
.an-tabella tr.riga-buco td { color: var(--fog); font-style: italic; }
.an-nota { opacity: .7; font-size: .85rem; margin-top: .5rem; }

/* Pannello «Come si calcola»: chiuso di default, i tre passaggi della
   formula in un carattere monospaziato per allineare gli operatori — è una
   formula, non un paragrafo. */
.an-dettagli { margin: 6px 0 10px; font-size: 12.5px; color: var(--ink-dim); }
.an-dettagli summary { cursor: pointer; font-weight: 700; color: var(--ink); }
.an-dettagli .an-formula {
    font-family: ui-monospace, monospace;
    white-space: pre;
    margin: 8px 0;
    padding: 8px 10px;
    border-radius: var(--radius-sm);
    background: var(--paper-2);
    overflow-x: auto;
}
.an-dettagli p { margin: 6px 0; line-height: 1.45; }

/* «Mostra tutte le voci» sotto la tabella. Discreto per costruzione: la
   tabella corta è la vista normale, aprirla è l'eccezione — un bottone pieno
   la farebbe sembrare incompleta. Stessa famiglia dei controlli dei filtri
   (mono, maiuscoletto), senza il riempimento. */
.an-espandi {
    /* `.dash-shell` è una colonna flex che stira i figli: senza questo il
       bottone diventa largo quanto la pagina e sembra una barra, non un
       comando. */
    align-self: flex-start;
    margin-top: .6rem;
    font-family: var(--mono);
    font-size: 11.5px;
    letter-spacing: .04em;
    color: var(--blue);
    background: transparent;
    border: 1px solid var(--rule);
    border-radius: var(--radius-sm);
    padding: 8px 14px;
    cursor: pointer;
    transition: border-color .15s, box-shadow .15s;
}
.an-espandi:hover { border-color: var(--blue); box-shadow: var(--elev-1); }
.an-espandi:focus-visible { outline: none; border-color: var(--blue); }

/* ---- Palette dei dati ----------------------------------------------------
   Validata con lo script della skill dataviz (`validate_palette.js`) contro
   la superficie bianca di questa app, non scelta a occhio:

   • serie/rampa in blu Unitec. #2a6ba8 è un passo più chiaro di --blue
     (#003a79): il brand resta alle cromature, ma come riempimento #003a79
     esce dalla banda di luminosità e i passi vicini non si distinguono più.
   • la coppia serie (#2a6ba8 gestionale, --verde #1f9966 agente) passa i
     controlli su daltonismo: ΔE 18,4 deutan, 19,7 a vista normale.
   • la rampa a 5 passi passa anche il gate ORDINALE, più severo di quello che
     servirebbe a una mappa di calore: luminosità monotòna, salti ≥ 0,06, e il
     passo più chiaro sta comunque a 2,07:1 dal bianco (non sparisce nella
     pagina).
   Cambiando un valore, rilanciare lo script: sono cinque controlli, non
   un'opinione. */
/* ⚠️ Su :root, non su #dashboardScreen. Ci sono state finché la palette dati
   serviva a una schermata sola; quando la classifica è diventata condivisa,
   dentro #dashboardScreen queste variabili semplicemente non esistevano e
   `var(--dato-gestionale)` non risolveva: le barre avevano la larghezza
   giusta e sfondo TRASPARENTE. Un valore che non risolve non è un errore per
   il browser — è una dichiarazione che sparisce, e a schermo si vede solo
   l'assenza. */
:root {
    --dato-gestionale: #2a6ba8;
    --dato-agente: var(--verde);
    --dato-altri: #c3c8d0;      /* de-enfasi: non è un colore di serie */
    --seq-1: #93b8dc; --seq-2: #6b9ecd; --seq-3: #4382bc;
    --seq-4: #2166a4; --seq-5: #0d4c86;
}

/* ⚠️ `flex-shrink: 0` non è cosmetica. `.dash-shell` è un flex a colonna alto
   `100dvh`: i suoi figli si comprimono per starci dentro, e chi ha un
   `overflow` proprio — come `.an-tabella-wrap` — si lascia schiacciare fino a
   **zero**. Con i due canvas ad altezza fissa di prima non poteva capitare;
   con questi riquadri sì, e infatti la tabella era nel DOM con le sue 54
   righe, alta 1.803 px, dentro un contenitore alto 0. Un elemento che c'è ma
   non si vede è peggio di uno che manca: non lo cerchi. */
.an-riquadro, .an-tabella-wrap, .an-nota { flex-shrink: 0; }

.an-riquadro {
    background: var(--paper); border: 1px solid var(--rule);
    border-radius: var(--radius-lg); padding: 18px 20px 16px;
    box-shadow: var(--elev-1); margin-top: 14px;
}
.an-riquadro h3 { font-size: 15px; font-weight: 900; letter-spacing: -.005em; }
.an-cap { font-size: 12.5px; color: var(--ink-dim); margin: 3px 0 14px; line-height: 1.45; }
.an-cap b { color: var(--ink); font-weight: 800; }

/* ---- Mappa di stagionalità (anno × mese) --------------------------------- */
.an-heatmap { display: grid; grid-template-columns: 46px repeat(12, 1fr); gap: 3px; align-items: center; }
.an-heatmap .hm-mese, .an-heatmap .hm-anno {
    font-size: 11px; color: var(--fog); font-weight: 700; letter-spacing: .03em;
}
.an-heatmap .hm-mese { text-align: center; padding-bottom: 2px; }
.an-heatmap .hm-anno { font-variant-numeric: tabular-nums; }
/* ⚠️ Nessun `background` di base qui. Ce l'aveva, e vinceva per specificità
   (0,2,0) su `.hm-b1…5` (0,1,0): la mappa restava tutta grigia mentre la
   legenda accanto mostrava i cinque passi. Ogni casella disegnata porta già
   la sua classe — un passo della rampa, il tratteggio del mese parziale o
   `.hm-assente` — quindi il colore di riserva non serviva a niente. */
.an-heatmap .hm-cella { height: 30px; border-radius: 5px; }
.an-heatmap .hm-cella:hover, .an-heatmap .hm-cella:focus-visible {
    outline: 2px solid var(--ink); outline-offset: 1px;
}
.hm-b1 { background: var(--seq-1); } .hm-b2 { background: var(--seq-2); }
.hm-b3 { background: var(--seq-3); } .hm-b4 { background: var(--seq-4); }
.hm-b5 { background: var(--seq-5); }
/* Il mese senza dati non è "zero case": è una casella che non c'è. */
.an-heatmap .hm-assente { background: transparent; border: 1px dashed var(--paper-3); }
/* Il mese troncato si distingue per TESSITURA, non per colore: un passo più
   chiaro direbbe "meno segnalazioni", che è esattamente la lettura sbagliata. */
.hm-parziale {
    background: repeating-linear-gradient(135deg, var(--seq-1) 0 4px, var(--paper) 4px 8px);
    outline: 1px solid var(--seq-2); outline-offset: -1px;
}
.an-scala {
    display: flex; align-items: center; gap: 6px; margin-top: 12px;
    font-size: 11.5px; color: var(--ink-dim); flex-wrap: wrap;
}
.an-scala i { width: 26px; height: 11px; border-radius: 3px; display: inline-block; }
.an-scala .hm-sp { flex: 1; }
.an-scala .hm-nota { display: inline-flex; align-items: center; gap: 6px; }
.an-scala .hm-nota i { width: 14px; }

/* ---- Colonne degli andamenti ---------------------------------------------
   Lo stesso grafico serve due serie — il gestionale e l'agente — che NON
   stanno mai sullo stesso asse (zero mesi in comune, 224 volte di differenza
   in volume). Il colore viene dalla classe di serie, non da un valore scritto
   nel markup: `serie-gestionale` / `serie-agente`. */
.an-colonne {
    display: flex; align-items: flex-end; gap: 8px; height: 160px;
    border-bottom: 1px solid var(--rule);
}
/* Cinquantatré mensilità con `gap: 8px` spendono 416 px di soli spazi vuoti:
   sopra le venti colonne lo spazio si stringe, o le barre si assottigliano
   fino a sparire mentre il vuoto resta. */
.an-colonne.fitte { gap: 2px; }
.an-colonne-x.fitte { gap: 2px; }
.an-colonne .col-c {
    flex: 1; display: flex; flex-direction: column; justify-content: flex-end;
    align-items: center; height: 100%; min-width: 0;
}
/* ⚠️ La barra è alta in percentuale di QUESTA pista, non dell'intera colonna:
   sopra c'è il numero, e misurare la barra sul contenitore che contiene anche
   il numero faceva sforare la colonna più alta oltre il bordo del riquadro,
   trascinandosi dietro le etichette dell'asse. */
.an-colonne .col-track {
    flex: 1; min-height: 0; width: 100%; display: flex; align-items: flex-end;
    padding-top: 18px;   /* la riga riservata al numero, sopra la barra piena */
}
.an-colonne .col-bar {
    width: 100%; background: var(--dato-agente);
    border-radius: 4px 4px 0 0; min-height: 2px; position: relative;
}
.an-colonne.serie-gestionale .col-bar { background: var(--dato-gestionale); }
.an-colonne.serie-agente .col-bar { background: var(--dato-agente); }
/* Il mese troncato si distingue per TESSITURA, non per altezza né per colore:
   una colonna più bassa e basta si legge «meno segnalazioni», che è la
   conclusione sbagliata — maggio 2026 ha 9 case perché l'export si ferma il 4,
   non perché le segnalazioni siano crollate. Stessa scelta della heatmap. */
.an-colonne .col-bar.col-parziale {
    background: repeating-linear-gradient(135deg,
        var(--dato-gestionale) 0 4px, var(--paper) 4px 8px);
    outline: 1px solid var(--dato-gestionale); outline-offset: -1px;
}
/* Sulla serie dell'agente il tratteggio è nel SUO colore: è il periodo in cui
   il costo è noto solo per una parte delle chiamate (vedi `renderCosti`). */
.an-colonne.serie-agente .col-bar.col-parziale {
    background: repeating-linear-gradient(135deg,
        var(--dato-agente) 0 4px, var(--paper) 4px 8px);
    outline-color: var(--dato-agente);
}
/* ⛔ «Non registrato» NON è «zero», e non deve poterlo sembrare.

   Una settimana senza costo non si disegna come una colonna bassa — si
   leggerebbe «quella settimana abbiamo speso pochissimo», che è falso: il
   costo si scrive a fine telefonata dal 2026-08-24, e le chiamate precedenti
   non ne hanno e non ne avranno mai uno.

   Quindi non una barra ma un TRATTINO al piede, alto quanto un bordo, in
   grigio di sistema e non nel colore della serie: non è un valore piccolo, è
   l'assenza di un valore. Il tratteggio lo lega visivamente al mese parziale,
   che è l'altro caso «questo dato non è quello che sembra». Il titolo della
   colonna lo dice a parole, e la didascalia conta quanti sono. */
.an-colonne .col-bar.col-ignoto {
    height: 4px;
    min-height: 4px;
    border-radius: 0;
    background: repeating-linear-gradient(135deg,
        var(--fog) 0 3px, var(--paper) 3px 6px);
    opacity: .55;
}

/* Il numero sta attaccato alla SUA barra, non in cima al riquadro: appeso al
   bordo alto della barra, sale e scende con lei. */
.an-colonne .col-n {
    position: absolute; bottom: 100%; left: 0; right: 0; text-align: center;
    font-size: 12px; font-weight: 800; margin-bottom: 3px;
    font-variant-numeric: tabular-nums;
}

/* ---- Istogramma impilato «Segnalazioni nel tempo» (§3, 2026-09-02) -------
   `.col-stack` è il SOLO figlio di `.col-track` (stessa altezza percentuale
   che prima aveva `.col-bar`, assegnata via CSSOM): dentro, i due segmenti si
   dividono per intero l'altezza dello stack, in proporzione fra loro — non
   rispetto al massimo della serie, quello lo fa già `.col-stack`.
   ⚠️ `column-reverse` + ordine nel markup [storico, agente]: il primo figlio
   sta al MAIN-START (il basso, in colonna invertita), quindi il gestionale
   resta sotto e l'agente sopra senza bisogno di invertire l'ordine nel DOM. */
.an-colonne.impilate .col-stack {
    position: relative; width: 100%; min-height: 2px;
    display: flex; flex-direction: column-reverse;
}
.an-colonne.impilate .col-seg { width: 100%; min-height: 0; }
.an-colonne.impilate .col-seg-storico { background: var(--dato-gestionale); }
/* Il segmento dell'agente è SEMPRE quello più in alto nello stack (ordine nel
   markup + `column-reverse`): l'angolo arrotondato va a lui. Quando è a zero
   collassa a un filo invisibile e l'angolo del gestionale sotto resta vivo,
   caso raro (un mese senza nessuna chiamata) e cosmetico, non un errore di
   lettura del grafico. */
.an-colonne.impilate .col-seg-agente {
    background: var(--dato-agente); border-radius: 4px 4px 0 0;
}
/* Il mese troncato (l'export del gestionale si ferma a metà) si distingue
   per TESSITURA sull'intero stack, non per colore né altezza — stessa regola
   dell'andamento a serie singola. Un overlay a righe, non un secondo sfondo
   per segmento: i due colori sotto restano quelli veri. */
.an-colonne.impilate .col-stack.col-parziale::after {
    content: ''; position: absolute; inset: 0; pointer-events: none;
    background: repeating-linear-gradient(135deg,
        rgba(255, 255, 255, .5) 0 4px, transparent 4px 8px);
    outline: 1px solid var(--dato-gestionale); outline-offset: -1px;
}

/* ---- Legenda a due voci (gestionale/agente) -------------------------------
   Stessi due colori del grafico impilato e della barra del Top impianti:
   uno swatch, non una parola in più — il colore già dice quale fetta è quale. */
.an-legenda {
    display: flex; flex-wrap: wrap; gap: 14px; margin: 2px 0 8px;
    font-size: 12px; color: var(--ink-dim);
}
.legenda-voce { display: inline-flex; align-items: center; gap: 6px; }
.legenda-swatch {
    display: inline-block; width: 12px; height: 12px; border-radius: 3px;
    flex-shrink: 0;
}
.legenda-gestionale { background: var(--dato-gestionale); }
.legenda-agente { background: var(--dato-agente); }

.an-colonne-x { display: flex; gap: 8px; margin-top: 6px; }
.an-colonne-x span {
    flex: 1; text-align: center; font-size: 10.5px; color: var(--fog);
    font-variant-numeric: tabular-nums;
}

/* ---- Barre orizzontali della classifica ---------------------------------- */
.an-barre { display: flex; flex-direction: column; gap: 7px; }
.an-barre .bar-row {
    display: grid; grid-template-columns: minmax(90px, 200px) 1fr 72px;
    gap: 10px; align-items: center; font-size: 12.5px;
}
.an-barre .bar-lab {
    color: var(--ink-dim); text-align: right;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.an-barre .bar-track { display: block; background: var(--paper-2); border-radius: 4px; height: 14px; }
/* La traccia divisa nelle due fonti — stessi colori del «Top impianti» e delle
   «Segnalazioni nel tempo»: un colore vuol dire la stessa cosa in tutta la
   Dashboard. ⚠️ `overflow: hidden` o il segmento arrotonda fuori dalla traccia. */
.an-barre .bar-track-divisa { display: flex; overflow: hidden; }
.an-barre .bar-seg { display: block; height: 14px; min-width: 2px; }
.an-barre .bar-seg-storico { background: var(--dato-gestionale); }
.an-barre .bar-seg-agente { background: var(--dato-agente); }
/* Il quadratino accanto all'intestazione è la legenda: la colonna e il pezzo
   di barra che la riguarda si riconoscono senza una riga di testo in più. */
.bar-head .bar-col-agente::before,
.bar-head .bar-col-gestionale::before {
    content: '';
    display: inline-block;
    width: 8px; height: 8px;
    margin-right: 5px;
    border-radius: 2px;
    vertical-align: baseline;
}
.bar-head .bar-col-agente::before { background: var(--dato-agente); }
.bar-head .bar-col-gestionale::before { background: var(--dato-gestionale); }
.an-barre .bar-fill { display: block; height: 14px; border-radius: 4px; background: var(--dato-gestionale); min-width: 2px; }
.an-barre .bar-altre .bar-fill { background: var(--dato-altri); }
.an-barre .bar-altre .bar-lab { font-style: italic; }
/* La chiosa dell'etichetta — oggi il frutto dell'impianto. Più chiara del
   codice perché è un complemento: si legge dopo, non al posto.
   ⚠️ Il separatore ` · ` sta nel TESTO (js/classifica.js), non in un
   `::before` qui: il contenuto generato dal CSS non finisce negli appunti,
   quindi copiando la riga si leggeva `22X228ACiliegie`. A schermo era giusto e
   fuori dallo schermo no — e non lo si scopre guardando lo schermo. */
.an-barre .bar-dett { color: var(--fog); }
.an-barre .bar-val { text-align: right; font-weight: 700; font-variant-numeric: tabular-nums; }

/* ---- Le colonne accanto alle barre (2026-09-07) --------------------------
   Erano una tabella sotto il grafico, con le stesse voci: leggere il costo di
   MECCANICO voleva dire scendere e ricercare la riga. Adesso i numeri stanno
   sulla barra a cui appartengono.
   ⚠️ Le colonne si dichiarano UNA volta, su `.an-barre:has(...)`, e valgono
   sia per l'intestazione che per le righe: due griglie definite a parte
   scivolano l'una rispetto all'altra al primo cambio, e il disallineamento fra
   un'intestazione e la sua colonna non lo segnala nessuno. */
.an-barre .bar-col,
.bar-head .bar-col {
    text-align: right;
    font-variant-numeric: tabular-nums;
}
/* I numeri non vanno mai a capo: una cifra spezzata non si legge. */
.an-barre .bar-col { white-space: nowrap; }
/* ⛔ Le INTESTAZIONI sì. Con `nowrap` «Medio a chiamata» usciva di 22px dalla
   propria colonna — non andava a capo e non si troncava, quindi sfondava in
   silenzio sopra la colonna accanto. È lo stesso difetto del pannello di
   conferma corretto stamattina, e l'ha trovato il presidio scritto per quello. */
.bar-head .bar-col { white-space: normal; line-height: 1.2; }
.an-barre .bar-col { color: var(--ink-dim); }
.bar-head {
    display: grid;
    gap: 10px;
    align-items: end;
    color: var(--fog);
    font-size: 10.5px;
    font-weight: 800;
    text-transform: uppercase;
    letter-spacing: .04em;
    padding-bottom: 6px;
}
/* Colonne: etichetta · barra · Case · quante ne porta `colonneDellaClassifica`.
   ⛔ Il numero arriva da `--bar-colonne`, che il JS scrive su entrambi gli
   elementi. La prima stesura usava `repeat(auto-fit, minmax(56px, 76px))`
   dopo l'`1fr` della barra: `auto-fit` non ha una larghezza da distribuire
   dopo una traccia flessibile, e le colonne sono finite **a capo** — le
   intestazioni una sotto l'altra e i numeri su una seconda riga. A schermo
   sembrava una tabella impazzita, e nessun errore da nessuna parte.
   Il minimo sulla riga impedisce che, stringendo, le cifre si accavallino:
   sotto quella soglia scorre `.an-tabella-wrap`, che l'`overflow-x` ce l'ha. */
/* Il valore predefinito sta QUI e non solo nel `var(…, 1)` di sotto: un token
   che esiste unicamente perché il JS lo scrive è fuori dal sistema, e non si
   trova più leggendo il foglio di stile. Il JS lo sovrascrive col numero vero. */
.an-barre, .bar-head { --bar-colonne: 1; }
.bar-head.con-colonne,
.an-barre .bar-row.con-colonne {
    grid-template-columns:
        minmax(80px, 170px) 1fr 56px repeat(var(--bar-colonne, 1), minmax(56px, 88px));
    /* ⚠️ Il minimo cresce COL NUMERO DI COLONNE. Fisso a 560px, su una finestra
       stretta le colonne si prendevano tutto e la barra — la cosa che il
       riquadro esiste per mostrare — restava lunga trenta pixel: un grafico
       ridotto a decorazione accanto ai suoi stessi numeri. Sotto questa
       soglia scorre `.an-tabella-wrap`, non la pagina. */
    min-width: calc(420px + var(--bar-colonne, 1) * 66px);
}

/* La riga «non classificata»: i suoi numeri contano, la sua lunghezza no —
   è la somma di due vuoti diversi, e una barra le darebbe una grandezza
   confrontabile che non ha. Traccia vuota, testo in grigio. */
.an-barre .bar-buco .bar-lab,
.an-barre .bar-buco .bar-val,
.an-barre .bar-buco .bar-col { color: var(--fog); font-style: italic; }
.an-barre .bar-buco .bar-fill { display: none; }

/* ---- Top impianti (§5, 2026-09-02) ---------------------------------------
   Stessa forma della classifica (etichetta · barra · valore), estesa con le
   colonne che il Top impianti porta in più: case del gestionale e chiamate
   dell'agente separati, e — solo `con_costi` — costo e costo medio. La barra
   è divisa in DUE segmenti, gestionale e agente, negli stessi due colori
   della classifica e del futuro istogramma impilato (§3): stesso linguaggio
   visivo, stesso significato dei colori in tutta la Dashboard. */
.top-imp-tabella-wrap { overflow-x: auto; }
.top-imp-barre { display: flex; flex-direction: column; gap: 7px; }
.top-imp-row {
    display: grid;
    grid-template-columns: minmax(110px, 220px) 1fr 64px 72px;
    gap: 10px; align-items: center; font-size: 12.5px; min-width: 460px;
}
.top-imp-row.con-costi {
    grid-template-columns: minmax(110px, 200px) 1fr 56px 64px 74px 84px;
    min-width: 600px;
}
.top-imp-row[data-valore] { cursor: pointer; border-radius: 6px; }
.top-imp-row[data-valore]:hover { background: var(--paper-2); }
.top-imp-row[data-valore]:hover .bar-lab { color: var(--blue); }
.top-imp-row[data-valore]:focus-visible { outline: 2px solid var(--blue); outline-offset: 2px; }
.top-imp-row .bar-lab {
    color: var(--ink-dim); text-align: right;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.top-imp-row .bar-dett { color: var(--fog); }
.top-imp-row .bar-track {
    display: flex; background: var(--paper-2); border-radius: 4px; height: 14px;
    overflow: hidden;
}
/* ⚠️ `min-width: 2px` come `.bar-fill`, e non 0: su una finestra stretta un
   segmento con un valore vero scendeva sotto il pixel e spariva — un dato
   disegnato come niente. Zero e «quasi zero» devono restare distinguibili;
   il segmento che vale davvero zero non viene proprio emesso (vista-analitica.js). */
.top-imp-row .bar-seg { display: block; height: 14px; min-width: 2px; }
.top-imp-row .bar-seg-storico { background: var(--dato-gestionale); }
.top-imp-row .bar-seg-agente { background: var(--dato-agente); }
.top-imp-row .top-imp-case, .top-imp-row .top-imp-chiamate,
.top-imp-row .top-imp-costo, .top-imp-row .top-imp-medio {
    text-align: right; font-weight: 700; font-variant-numeric: tabular-nums;
}
.top-imp-head {
    color: var(--fog); font-size: 10.5px; font-weight: 800;
    text-transform: uppercase; letter-spacing: .04em; padding-bottom: 2px;
}
.top-imp-head .top-imp-th { text-align: right; }

/* La stagionalità chiusa dietro un dettaglio (§5): stesso trattamento visivo
   di «Come si calcola», ma dentro un `.an-riquadro` che porta già il suo
   bordo/ombra — la `summary` fa da titolo della sezione finché è chiusa. */
#dashStagionalita details summary {
    font-size: 15px; font-weight: 900; letter-spacing: -.005em;
    cursor: pointer; color: var(--ink); list-style: none;
}
#dashStagionalita details summary::-webkit-details-marker { display: none; }
#dashStagionalita details[open] summary { margin-bottom: 10px; }

@media (max-width: 640px) {
    .an-heatmap { grid-template-columns: 34px repeat(12, 1fr); gap: 2px; }
    .an-heatmap .hm-cella { height: 22px; border-radius: 4px; }
    .an-heatmap .hm-mese { font-size: 9px; }
    .an-barre .bar-row { grid-template-columns: minmax(70px, 120px) 1fr 60px; }
}

/* ---- Etichette dei filtri attivi ----------------------------------------
   Un filtro applicato dev'essere visibile e togliibile: senza, chi guarda
   vede numeri piccoli e non sa perché — soprattutto quelli che arrivano dal
   drill down (macchina, categoria), che un campo in schermata non ce l'hanno.
   Il × non è un'icona a parte: la chip intera è il pulsante che lo toglie. */
.filtri-attivi {
    display: flex; flex-wrap: wrap; gap: 8px; margin-top: 10px; flex-shrink: 0;
}
.filtro-chip {
    display: inline-flex; align-items: center; gap: 8px;
    font-family: var(--sans); font-size: 12px; line-height: 1;
    padding: 7px 10px; border: 1px solid var(--rule); border-radius: 999px;
    background: var(--paper); color: var(--ink); cursor: pointer;
    box-shadow: var(--elev-1);
}
.filtro-chip:hover { border-color: var(--rosso); color: var(--rosso); }
.filtro-chip:focus-visible { outline: none; border-color: var(--blue); }
.filtro-chip .chip-dim {
    text-transform: uppercase; letter-spacing: .06em; font-weight: 800;
    font-size: 10px; color: var(--fog);
}
.filtro-chip .chip-val { font-weight: 700; max-width: 22ch; overflow: hidden;
    text-overflow: ellipsis; white-space: nowrap; }
.filtro-chip .chip-x { font-size: 15px; color: var(--fog); margin-left: 2px; }
.filtro-chip:hover .chip-x { color: var(--rosso); }

/* La riga della classifica è cliccabile solo quando c'è un drill down da
   fare: il puntatore lo dice prima del clic. */
.an-barre .bar-drill { cursor: pointer; border-radius: 6px; }
.an-barre .bar-drill:hover { background: var(--paper-2); }
.an-barre .bar-drill:hover .bar-lab { color: var(--blue); }
.an-barre .bar-drill:focus-visible { outline: 2px solid var(--blue); outline-offset: 2px; }


/* Storico degli accessi dentro «Dispositivi collegati» (2026-08-31). */
.disp-storico { margin: 28px 0 4px; font-size: 1.05rem; }
.disp-filtri { display: flex; flex-wrap: wrap; gap: 8px; margin: 12px 0 14px; align-items: center; }
.disp-filtri select, .disp-filtri input { padding: 6px 10px; }
.reg-riga { display: flex; flex-wrap: wrap; gap: 6px 16px; align-items: baseline; padding: 9px 0; border-bottom: 1px solid var(--rule); }
.reg-quando { font-variant-numeric: tabular-nums; min-width: 132px; }
.reg-cosa { font-weight: 600; }
.reg-negata .reg-cosa { font-weight: 400; }
.reg-esito { font-size: .9em; }
.reg-dove { margin-left: auto; font-size: .88em; opacity: .75; }


/* --- ogni elenco nella sua finestra scorrevole -------------------------------
   Chiesto il 2026-09-01: «vorrei che ogni elenco fosse in una finestra
   scorrevole a parte, in modo che nella pagina la navigazione fosse comoda».
   Il problema misurato: 85 sessioni attive + 100 tentativi + 100 eventi in una
   pagina sola, e il quarto elenco si raggiunge solo scorrendo i primi tre.

   La barra riusa il pattern che il prodotto ha già in `.conv-list` — thin,
   `var(--rule)` su trasparente, 6px — invece di inventarne uno secondo.

   ⚠️ `overscroll-behavior: contain`: senza, arrivati in fondo a un elenco il
   gesto prosegue sulla pagina, e con undici finestre annidate si perde il
   segno a ogni giro. */
.elenco-finestra {
    /* ⛔ `flex: 0 0 auto` NON è ornamentale: `.dash-shell` è un flex in colonna
       alto `100dvh`, e un flex item ha `flex-shrink: 1` di default. Con
       `overflow: auto` il minimo automatico dell'elemento è ~zero, quindi i
       riquadri venivano SCHIACCIATI a 80px, 30px, e uno a 2px — con dentro
       9504px di contenuto. A colpo d'occhio sembravano riquadri veri: l'ha
       trovato la misura, non lo sguardo. «Non cresce, non si stringe, si
       dimensiona sul contenuto», e il tetto lo mette `max-height`. */
    flex: 0 0 auto;
    max-height: var(--finestra-elenco);
    overflow-y: auto;
    padding: 12px;
    overscroll-behavior: contain;
    scrollbar-width: thin;
    scrollbar-color: var(--rule) transparent;
    border: 1px solid var(--rule);
    border-radius: var(--radius-md);
}
.elenco-finestra::-webkit-scrollbar { width: 6px; }
.elenco-finestra::-webkit-scrollbar-thumb {
    background: var(--rule);
    border-radius: 3px;
}
/* Gli elenchi che avevano un padding laterale da pagina lo perdono dentro la
   cornice: venti pixel di aria contro un bordo si leggono come un errore. */
.elenco-finestra.disp-list { padding: 12px; }


/* ======================================================================
   SICUREZZA E ACCESSI — tre sezioni in una schermata sola (2026-09-01)

   Erano tre schermate: «Accessi e sessioni», «Registro accessi»,
   «Credenziali». Qui c'è solo ciò che le tiene separate a schermo ORA che
   condividono una pagina — dentro, ogni sezione usa gli stili che aveva
   (`vig-*`, `cred-*`, `.elenco-finestra`), che non sono stati toccati.
   ====================================================================== */

/* La barra delle ancore. Ancore e non schede: la pagina resta una sola e si
   scorre; questa è una scorciatoia, non uno stato. `sticky` perché su una
   pagina lunga il modo di risalire deve restare a portata — senza, per tornare
   da «Credenziali» a «Sessioni» si scorre all'indietro tutto il registro. */
.sic-ancore {
    position: sticky;
    top: 0;
    z-index: 2;
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    /* ⛔ Come `.elenco-finestra`: dentro `.dash-shell`, che è un flex in
       colonna alto 100dvh, un item ha `flex-shrink: 1` e si lascia schiacciare.
       Su una barra di 34px non si nota subito — si nota che i testi si
       tagliano. */
    flex: 0 0 auto;
    /* Opaca, o il contenuto che le scorre sotto si legge attraverso. */
    background: var(--paper);
    padding: 10px 0;
    border-bottom: 1px solid var(--rule);
}
.sic-ancore a {
    font-family: var(--mono);
    font-size: 11px;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    text-decoration: none;
    color: var(--ink-dim);
    background: var(--paper-2);
    border: 1px solid var(--rule);
    border-radius: var(--radius-sm);
    padding: 6px 12px;
}
.sic-ancore a:hover { color: var(--blue); border-color: var(--rule-ink); }

/* Le due pagine della Dashboard: «Andamento» e «Stato del servizio».
   Stessa forma di `.sic-ancore` — è la barra sorella — ma qui sono BOTTONI e
   non ancore, perché non portano a una sezione più in basso: cambiano
   schermata. La pagina in cui sei si riconosce da `aria-current="page"`, che
   e' anche cio' che la sintesi vocale legge: lo stato non e' solo un colore. */
.dash-pagine {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    /* ⛔ Come `.sic-ancore` e `.elenco-finestra`: dentro `.dash-shell`, flex in
       colonna alto 100dvh, un item si lascia schiacciare fino a sparire. */
    flex: 0 0 auto;
    margin-bottom: 14px;
}
.dash-pagina {
    font-family: var(--mono);
    font-size: 11px;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--ink-dim);
    background: var(--paper-2);
    border: 1px solid var(--rule);
    border-radius: var(--radius-sm);
    padding: 6px 12px;
    cursor: pointer;
}
.dash-pagina:hover { color: var(--blue); border-color: var(--rule-ink); }
.dash-pagina[aria-current="page"] {
    color: var(--paper);
    background: var(--blue);
    border-color: var(--blue);
    cursor: default;
}

/* Ogni sezione è un riquadro, non un tratto di elenco continuo: sotto due
   titoli ci sono due righe di filtri che comandano cose diverse, e senza una
   cornice si legge come se la seconda rifiltrasse la prima. */
.sic-sezione {
    /* ⛔ Vedi `.elenco-finestra`: senza questo le tre sezioni diventano flex
       item comprimibili e si schiacciano l'una sull'altra, con dentro migliaia
       di pixel di contenuto — e nello scatto sembrano riquadri veri. */
    flex: 0 0 auto;
    display: flex;
    flex-direction: column;
    gap: 12px;
    padding: 20px 22px 22px;
    background: var(--paper);
    border: 1px solid var(--rule);
    border-radius: var(--radius-lg);
    /* Lo stacco fra una sezione e la successiva quando si arriva per ancora:
       senza, il titolo finisce incollato sotto la barra sticky. */
    scroll-margin-top: 60px;
}
.sic-titolo {
    font-family: var(--sans);
    font-size: 18px;
    font-weight: 700;
    letter-spacing: -0.01em;
    color: var(--ink);
    margin: 0;
}
.sic-cap {
    max-width: 62ch;
    font-size: 13px;
    line-height: 1.5;
    color: var(--ink-dim);
    margin: 0;
}
/* Il primo titolo di ogni sezione non ha bisogno del margine che lo staccava
   dal blocco precedente: adesso il blocco precedente è la cornice. */
.sic-sezione .vig-section-titolo:first-of-type { margin-top: 0; }

/* ⛔ «Credenziali» è l'ultima e si vede che è un'altra cosa. Non è
   decorazione: qui si RITIRANO le credenziali di un'azienda, mentre in cima
   alla stessa pagina si staccano dispositivi — due azioni di peso
   incomparabile che fino a ieri stavano in due schermate diverse, e per una
   ragione precisa (due utenze vere disattivate con dei clic ciechi il
   2026-09-01). L'ordine mette la distanza, questo bordo dice che si è passato
   un confine. */
.sic-sezione-grave {
    border-color: var(--rosso);
    border-top-width: 3px;
}

/* ======================================================================
   Stato del servizio — schermata `statoScreen` (staff)

   ⚠️ I colori delle fasce sono ESPLICITI, con bordo, non `rgba` su fondo
   chiaro: una fascia «non misurata» semitrasparente su una card bianca è
   invisibile, e una timeline con dei buchi invisibili dice «tutto bene»
   proprio dove non sa niente.
   ====================================================================== */

.stato-card {
    background: var(--paper);
    border: 1px solid var(--rule);
    border-radius: 14px;
    padding: 18px 20px;
    margin-bottom: 14px;
}

.stato-titolo {
    font: 600 13px/1.2 var(--sans);
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--ink-dim);
    margin-bottom: 12px;
}

/* --- semaforo --- */
.stato-card--semaforo { display: flex; flex-direction: column; gap: 6px; }

.stato-pill {
    display: inline-block;
    align-self: flex-start;
    padding: 6px 16px;
    border-radius: 999px;
    font: 700 15px/1.2 var(--sans);
    letter-spacing: .02em;
    color: var(--paper);
    background: var(--fog);
}
.stato-pill--ok { background: var(--verde); }
.stato-pill--degradato { background: var(--ambra); }
.stato-pill--guasto { background: var(--rosso); }

.stato-sottotitolo { font: 400 14px/1.5 var(--sans); color: var(--ink); }
.stato-dettaglio { font: 400 13px/1.5 var(--sans); color: var(--fog); }
.stato-vuoto { font: 400 13px/1.5 var(--sans); color: var(--fog); padding: 8px 2px; }

/* --- timeline --- */
.stato-tl { display: flex; flex-direction: column; gap: 4px; }

.stato-tl-riga { display: flex; align-items: center; gap: 10px; }

.stato-tl-giorno {
    flex: 0 0 auto;
    width: 82px;
    font: 500 11px/1.2 var(--sans);
    color: var(--fog);
    text-align: right;
}

/* `min-width: 0` sul CONTENITORE: senza, la minimum size automatica di questo
   elemento flex è quella dei suoi 48 blocchi e la barra esce dalla card senza
   far scorrere niente — le fasce ai bordi si vedrebbero solo tagliate. */
.stato-tl-barra { display: flex; gap: 2px; flex: 1 1 auto; min-width: 0; }

.stato-tl-fascia {
    flex: 1 1 0;
    min-width: 0;
    height: 16px;
    border-radius: 2px;
    background: var(--paper-3);
    border: 1px solid var(--rule);
}
.stato-tl-fascia--ok { background: var(--verde); border-color: var(--verde); }
.stato-tl-fascia--attenzione { background: var(--ambra); border-color: var(--ambra); }
.stato-tl-fascia--errore { background: var(--rosso); border-color: var(--rosso); }
.stato-tl-fascia--giu { background: var(--ink-dim); border-color: var(--ink-dim); }
.stato-tl-fascia--nessuna { background: var(--paper-3); border-color: var(--rule); }

.stato-legenda {
    display: flex;
    flex-wrap: wrap;
    gap: 6px 18px;
    margin-top: 12px;
    list-style: none;
    font: 400 12px/1.2 var(--sans);
    color: var(--ink-dim);
}
.stato-legenda li { display: flex; align-items: center; gap: 6px; }
.stato-legenda .stato-tl-fascia { flex: 0 0 auto; width: 14px; height: 14px; }

/* «Da dove viene ogni colore»: chiuso di default. La legenda basta a chi
   guarda, l'elenco dei casi serve a chi sta indagando — stessa famiglia di
   `.an-dettagli` («Come si calcola»), che è già l'idioma del prodotto per una
   spiegazione a richiesta.
   ⚠️ I selettori sono discendenti di `.stato-spiega` di proposito: `.an-dettagli p`
   pesa 0-1-1 e vincerebbe su una classe sola, comunque la si scriva dopo. */
.stato-spiega { margin-top: 10px; }
.stato-spiega .stato-spiega-nome {
    display: flex;
    align-items: center;
    gap: 8px;
    margin: 14px 0 4px;
    color: var(--ink);
}
.stato-spiega .stato-spiega-nome:first-child { margin-top: 2px; }
/* ⛔ La misura della pastiglia stava solo sotto `.stato-legenda`: qui dentro
   `.stato-tl-fascia` è un figlio flex senza base, e si allargava a tutta riga
   spingendo il nome a destra. Stessa famiglia della regola appesa a un #id. */
.stato-spiega .stato-spiega-nome .stato-tl-fascia {
    flex: 0 0 auto;
    width: 14px;
    height: 14px;
}
.stato-spiega .stato-spiega-casi {
    margin: 0 0 0 24px;
    padding: 0 0 0 12px;
    list-style: disc;
}
.stato-spiega .stato-spiega-casi li {
    margin: 3px 0;
    line-height: 1.5;
    color: var(--ink-dim);
}
.stato-spiega .stato-spiega-nota {
    margin: 6px 0 0 24px;
    color: var(--fog);
    line-height: 1.5;
}

/* --- riquadri --- */
.stato-kpi-riga {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
    gap: 12px;
    margin-bottom: 14px;
}
.stato-kpi-card {
    background: var(--paper);
    border: 1px solid var(--rule);
    border-radius: 14px;
    padding: 16px 18px;
    display: flex;
    flex-direction: column;
    gap: 4px;
}
.stato-kpi-valore { font: 700 26px/1.1 var(--sans); color: var(--blue); }
.stato-kpi-etichetta {
    font: 500 11px/1.2 var(--sans);
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--fog);
}
.stato-kpi-nota { font: 400 12px/1.3 var(--sans); color: var(--ink-dim); }

/* --- fermi --- */
.stato-fermi-lista { list-style: none; display: flex; flex-direction: column; gap: 8px; }
.stato-fermo {
    display: grid;
    grid-template-columns: 130px 130px 1fr;
    gap: 10px;
    align-items: baseline;
    font: 400 13px/1.4 var(--sans);
    color: var(--ink);
    padding-bottom: 8px;
    border-bottom: 1px solid var(--rule);
}
.stato-fermo:last-child { border-bottom: 0; padding-bottom: 0; }
.stato-fermo-quando { color: var(--ink-dim); }
.stato-fermo-durata { font-weight: 600; }
.stato-fermo--in-corso .stato-fermo-durata { color: var(--rosso); }
.stato-fermo-motivo { color: var(--fog); }

/* --- registro --- */
.stato-filtri { display: flex; flex-wrap: wrap; gap: 10px 20px; margin-bottom: 12px; }
.stato-filtro-gruppo { display: flex; gap: 6px; }
.stato-filtro-gruppo button {
    border: 1px solid var(--rule);
    background: var(--paper);
    color: var(--ink-dim);
    border-radius: 999px;
    padding: 5px 14px;
    font: 500 12px/1.2 var(--sans);
    cursor: pointer;
}
.stato-filtro-gruppo button:hover { border-color: var(--blue); color: var(--blue); }
.stato-filtro-gruppo button.attivo {
    background: var(--blue);
    border-color: var(--blue);
    color: var(--paper);
}

.stato-eventi-tab { width: 100%; border-collapse: collapse; font: 400 13px/1.4 var(--sans); }
.stato-eventi-tab th {
    text-align: left;
    font: 600 11px/1.2 var(--sans);
    letter-spacing: .05em;
    text-transform: uppercase;
    color: var(--fog);
    padding: 0 10px 8px 0;
    position: sticky;
    top: 0;
    background: var(--paper);
}
.stato-eventi-tab td { padding: 7px 10px 7px 0; border-top: 1px solid var(--rule); vertical-align: top; }
.stato-ev-ora { color: var(--ink-dim); white-space: nowrap; }
.stato-ev-livello { white-space: nowrap; font-weight: 600; }
.stato-ev-livello[data-livello="ok"] { color: var(--verde); }
.stato-ev-livello[data-livello="attenzione"] { color: var(--ambra); }
.stato-ev-livello[data-livello="errore"] { color: var(--rosso); }
.stato-ev-sorgente { color: var(--fog); white-space: nowrap; }

.stato-altri {
    margin-top: 10px;
    border: 1px solid var(--rule);
    background: var(--paper);
    color: var(--blue);
    border-radius: 8px;
    padding: 7px 16px;
    font: 500 13px/1.2 var(--sans);
    cursor: pointer;
}

.btn-verifica {
    margin-left: auto;
    border: 1px solid var(--blue);
    background: var(--blue);
    color: var(--paper);
    border-radius: 8px;
    padding: 8px 18px;
    font: 600 13px/1.2 var(--sans);
    cursor: pointer;
}
.btn-verifica:hover { background: var(--blue-dim); border-color: var(--blue-dim); }
.btn-verifica:disabled { opacity: .6; cursor: progress; }

@media (max-width: 640px) {
    .stato-tl-giorno { width: 58px; font-size: 10px; }
    .stato-fermo { grid-template-columns: 1fr; gap: 2px; }
    .stato-ev-sorgente { display: none; }
}

/* ---------------- Chi sono, e come esco ----------------
   Targhetta fissa in basso a sinistra, fuori da ogni schermata.

   ⛔ Prima «Esci» era un bottone nell'intestazione della sola schermata
   d'avvio: dalla Dashboard, dallo Storico o durante una chiamata non c'era
   modo di uscire — bisognava tornare indietro per trovarlo. E non si vedeva
   mai con quale utente si stava lavorando, che su una postazione condivisa a
   bordo macchina è la prima cosa da sapere.

   ⚠️ `position: fixed` e non un elemento in fondo al flusso: le schermate
   scorrono ognuna per conto suo (`.dash-shell` ha il suo scroll), e una
   targhetta nel flusso sparirebbe scorrendo proprio nelle pagine lunghe, che
   sono quelle in cui ci si dimentica di chi si è.

   ⚠️ **Le misure non sono inventate: sono quelle di `.entry-tool`**, le schede
   «Storico conversazioni / Dashboard» che stanno nella stessa schermata —
   fondo `--paper-2`, bordo `--rule`, raggio medio, `--elev-1`, e la stessa
   disciplina sul passaggio del mouse (niente riempimenti forti, un cambio di
   bordo e un sollevamento). Un componente nuovo che si inventa le proprie
   misure è il modo in cui un'interfaccia comincia a sembrare montata a pezzi. */
.utente-box {
    position: fixed;
    left: 20px;
    bottom: 20px;
    z-index: 40;
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 8px 10px 8px 8px;
    background: var(--paper-2);
    border: 1px solid var(--rule);
    border-radius: var(--radius-md);
    box-shadow: var(--elev-1);
    transition: border-color .18s, background .18s, box-shadow .18s;
}
.utente-box:hover {
    background: var(--paper);
    border-color: rgba(0, 58, 121, 0.30);
    box-shadow: var(--elev-2);
}

/* L'iniziale in un tondo blu. Non è decorazione: è la cosa che si riconosce
   con la coda dell'occhio quando su una postazione condivisa ci si chiede «con
   che utente sto guardando». Il tondo pieno in `--blue` è già il vocabolario
   della schermata (`.pulse-dot`, il bottone del microfono). */
.utente-segno {
    flex: none;
    width: 30px;
    height: 30px;
    border-radius: 50%;
    background: var(--blue);
    color: #fff;
    display: grid;
    place-items: center;
    font-family: var(--sans);
    font-size: 13px;
    font-weight: 700;
    text-transform: uppercase;
    line-height: 1;
}

.utente-chi { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.utente-nome {
    font-family: var(--sans);
    font-size: 13px;
    font-weight: 600;
    color: var(--ink);
    line-height: 1.15;
    max-width: 168px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
/* Stessa resa di `.entry-tool-sub`: maiuscoletto spaziato, 10px, colore tenue.
   È l'etichetta di servizio di questa interfaccia, e il ruolo è esattamente
   quello — un'informazione di contorno, non un secondo nome. */
.utente-ruolo {
    font-family: var(--mono);
    font-size: 10px;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--fog);
    line-height: 1.15;
}
/* Vuoto per il cliente: senza questo la riga del nome resterebbe disallineata
   verso l'alto per un elemento che non si vede. */
.utente-ruolo:empty { display: none; }

/* ⛔ Questo bottone NON usa `.btn-reset`, e non è una svista.
   `.btn-reset` porta `border: 1px solid var(--ink)` su tutti e quattro i lati:
   ridefinendo qui il solo `border-left` gli altri tre restavano, e con
   `border-radius` a destra ne usciva un mezzo riquadro scuro aperto a
   sinistra. Combattere a colpi di specificità con una classe pensata per
   un'altra famiglia di bottoni lascia sempre qualche lato indietro: questa
   classe si azzera da sé e non eredita niente.

   Separatore prima dell'azione: la stessa riga da 1px con cui questa
   interfaccia separa ovunque il contenuto dai comandi. */
.utente-esci {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    margin-left: 2px;
    padding: 7px 10px 7px 12px;
    border: 0;
    /* Una linea sola, e chiara (`--rule`, non `--ink`): un separatore, non il
       contorno di un bottone. Il raggio è solo a destra, perché è da quel lato
       che la tinta del passaggio del mouse tocca il bordo della targhetta. */
    border-left: 1px solid var(--rule);
    border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
    cursor: pointer;
    font-family: var(--mono);
    font-size: 10px;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--fog);
    background: transparent;
    transition: color .18s, background .18s;
}
.utente-esci svg { width: 15px; height: 15px; }
/* Il rosso solo al passaggio del mouse: uscire è un gesto reversibile, non un
   pericolo da segnalare in permanenza — ma nel momento in cui stai per farlo
   il colore te lo dice. */
.utente-esci:hover { color: var(--rosso); background: rgba(200, 16, 46, 0.06); }
.utente-esci:focus-visible {
    outline: 2px solid var(--blue);
    outline-offset: 2px;
    color: var(--rosso);
}

/* Su schermo stretto resta la sostanza: chi sono e come esco. Il ruolo e la
   parola «Esci» cadono, l'iniziale e l'icona bastano. */
@media (max-width: 640px) {
    .utente-box { left: 12px; bottom: 12px; padding: 6px; gap: 8px; }
    .utente-ruolo, .utente-esci span { display: none; }
    .utente-esci { padding: 7px 8px; }
    .utente-nome { max-width: 110px; }
}
