﻿/* ============================================================
   Chat dell'assistente (M3) - pannello laterale della shell e pagina
   del modulo. Copre Templates/NexusAssistantDock.razor (widget dello
   Smart Panel, doc 13 par. 28) e i tre componenti
   Components/AgentChat{Surface,Notes,Workspace}.razor. L'interruttore
   e' sul rail dello Smart Panel (NexusSmartRail, nexus-shell.css).

   Caricato da _Host.cshtml dopo site.css: il pannello vive nella shell
   e va disegnato su qualunque vista, non solo sulla pagina della chat
   (taskwork.css e worker-dashboard.css restano caricati dal componente,
   perche' quelli vivono dentro una vista sola).

   Come gli altri fogli Nexus: nessun selettore .dxbl-*, solo classi
   .nx-*, e ogni colore da un token semantico - cosi' il tema scuro si
   deriva da solo (doc 13 par. 12).
   ============================================================ */

/* ---- pannello laterale (dock) ------------------------------
   Un FOGLIO accanto a quello della vista, dentro .nx-stage: stessa
   superficie, stesso raggio, stesso canale navy che separa i due.

   Dal 2026-08-09 .nx-dock non e' piu' solo la chat: e' la meccanica di
   larghezza COMUNE dei widget dello Smart Panel (telaio
   NexusSmartPanelShell) — la veste anche il widget Notifiche, con la
   stessa base e la stessa maniglia (richiesta dell'utente).

   La larghezza va a GRADINI (doc 13 par. 25): 1x la colonna di lettura,
   poi 2x e 3x, e l'ultimo gradino e' tutta la pagina. I gradini
   intermedi sono limitati con min(..., 100%), quindi su uno schermo
   stretto saturano da soli invece di sfondare il telaio. */
.nx-dock {
  --nx-dock-w: 400px;

  position: relative;                  /* ancora della maniglia di divisione */
  flex: 0 0 auto;
  width: min(var(--nx-dock-w), 100%);
  min-width: 0;
  display: flex;
  flex-direction: column;
  min-height: 0;
  overflow: hidden;                    /* il raggio del foglio taglia il thread */
  /* La larghezza cambia a scatti dichiarati: l'animazione dice che e' lo
     stesso pannello che cresce, non un altro che compare. */
  transition: width var(--nexus-transition-base);
}

/* Il primo gradino ripete la larghezza base: ridondante per il browser,
   non per chi legge — la scala si vede tutta in quattro righe. */
.nx-dock--step-1 { width: min(var(--nx-dock-w), 100%); }
.nx-dock--step-2 { width: min(calc(var(--nx-dock-w) * 2), 100%); }
.nx-dock--step-3 { width: min(calc(var(--nx-dock-w) * 3), 100%); }
.nx-dock--step-4 { width: 100%; }

/* Ultimo gradino: la chat prende il palcoscenico. Il foglio della vista
   esce dal flusso (non si stringe a una fessura di pochi pixel, che la
   griglia DevExpress ridisegnerebbe per niente) e il canale fra i due
   fogli sparisce, altrimenti resterebbero 16px di telaio a destra.
   Senza :has() (browser vecchi) il degrado e' innocuo: il pannello resta
   largo quanto il palcoscenico e il contenuto si comprime a zero. */
.nx-stage:has(.nx-dock--step-4) { gap: 0; }
.nx-stage:has(.nx-dock--step-4) > .nx-content { display: none; }

@media (prefers-reduced-motion: reduce) {
  .nx-dock { transition: none; }
}

/* ---- maniglia di divisione (trascinamento col mouse) -------
   Sta DENTRO il pannello, sul suo bordo sinistro, e non nel canale del
   telaio: il pannello ha overflow hidden per il raggio del foglio, e una
   maniglia che sporge verrebbe tagliata. Otto pixel bastano a prenderla
   col mouse; a riposo non si vede — e' il cursore a dire che si puo'
   trascinare, come in ogni divisione a due riquadri. */
.nx-dock__grip {
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 8px;
  z-index: 2;
  display: grid;
  place-items: center;
  cursor: col-resize;
  touch-action: none;                  /* il pointermove non deve scrollare */
  background: transparent;
  transition: background-color var(--nexus-transition-fast);
}

.nx-dock__grip-line {
  width: 2px;
  height: 28px;
  border-radius: var(--nexus-radius-pill);
  background: transparent;
  transition: background-color var(--nexus-transition-fast);
}

.nx-dock__grip:hover .nx-dock__grip-line,
.nx-dock__grip:focus-visible .nx-dock__grip-line { background: var(--nx-teal); }

.nx-dock__grip:focus-visible {
  outline: none;
  background: color-mix(in srgb, var(--nx-teal) 10%, transparent);
}

/* Durante il trascinamento il puntatore comanda tutta la finestra: senza
   questo, il testo sotto si seleziona e il cursore torna a freccia appena
   esce dagli otto pixel della maniglia. */
body.nx-resizing { cursor: col-resize; user-select: none; }

/* L'intestazione del dock (marchio, titolo, pin, chiudi) e' il telaio
   comune dello Smart Panel: .nx-smart-panel__* in nexus-shell.css.
   Qui restano solo i due estremi di larghezza, che sono del dock. */
.nx-dock__resize:disabled {
  opacity: var(--nexus-opacity-disabled);
  cursor: default;
  background: transparent;
}

/* Le indicazioni permanenti sono un piede, non un'intestazione: il loro
   comando sta in fondo al pannello. Sopra il nome dell'agente erano la prima
   cosa che si leggeva aprendo il pannello — e la meno urgente di tutte.
   Dal 2026-08-09 il comando APRE UN PANNELLO su tutto il widget (come sulla
   pagina), al posto della fisarmonica che si apriva in una striscia. */
.nx-dock > .nx-chat,
.nx-dock > .nx-chat-notes-panel { order: 2; }
.nx-dock > .nx-chat-notes-btn { order: 3; }

/* Sotto i 1200px il pannello si stringe. */
@media (max-width: 1200px) {
  .nx-dock { --nx-dock-w: 340px; }
}

/* Sotto i 900px non c'e' spazio per due fogli affiancati — ma "non c'e'
   spazio per affiancarli" non vuol dire "non c'e' l'assistente": fino al
   2026-08-11 il pannello spariva e basta, e su un portatile in trasferta la
   chat semplicemente non esisteva.

   Ora prende tutto il palcoscenico, come fanno i pannelli su schermo
   stretto ovunque: copre il foglio della vista invece di stringerlo, e si
   chiude con la X che ha gia'. La maniglia di trascinamento sparisce — a
   tutta larghezza non c'e' niente da trascinare — e con lei i gradini, che
   a quel punto sono tutti lo stesso gradino. */
@media (max-width: 900px) {
  .nx-dock,
  .nx-dock.nx-dock--step-1,
  .nx-dock.nx-dock--step-2,
  .nx-dock.nx-dock--step-3,
  .nx-dock.nx-dock--step-4 {
    position: absolute;
    inset: 0;
    width: 100%;
    max-width: 100%;
    z-index: 40;
    box-shadow: var(--nx-shadow-float);
  }

  .nx-dock__resize { display: none; }

  /* Il pin non ha piu' significato: affiancato e in sorvolo sono la stessa
     cosa quando il pannello copre tutto. */
  .nx-smart-panel__pin { display: none; }
}

/* ---- pagina del modulo -------------------------------------
   Due colonne: le proprie conversazioni a sinistra, la chat a destra.
   Altezza vincolata e non "a scorrere con la pagina": il thread deve
   avere il PROPRIO scroll, altrimenti il compositore scende sotto il
   bordo e per scrivere bisogna prima scorrere. */
.nx-chat-workspace {
  display: grid;
  grid-template-columns: 280px minmax(0, 1fr);
  gap: var(--nexus-space-4);
  /* Altezza misurata sul foglio, non "a scorrere con la pagina": il
     compositore deve restare sopra il bordo, col thread che scorre da se'.
     RIMISURATA il 2026-08-25 dopo la rimozione della topbar (doc 13
     par. 51): l'offset e' cio' che sta sopra il workspace (108px: telaio,
     striscia schede, padding) piu' padding del foglio (24) e margine del
     telaio (16) = 148 — il bordo inferiore cade sulla linea del padding
     del foglio. La taratura storica 250 (2026-08-01) scontava anche la
     topbar e ingombri poi rimossi. */
  /* 137 dal 2026-08-28: RIMISURATA sul DOM dopo che la fascia sotto il
     contenuto si e' ristretta (nexus-shell.css). Non e' il solo -24: la
     taratura vecchia (148) sforava gia' di 13px e la pagina tornava a
     scorrere — il workspace parte a 108 e l'area utile finisce a 29px dal
     fondo della finestra. */
  height: clamp(420px, calc(100vh - 137px), 1100px);
  min-height: 0;
}

/* Schermo intero (richiesta dell'utente 2026-08-09): la pagina esce dal
   foglio della vista e copre la finestra. Un overlay a posizione fissa, non
   una manomissione della shell — top bar, rail e striscia delle schede
   restano intatti sotto e tornano appena si esce.

   z-index 900: sopra ogni strato della shell (il piu' alto e' 50, i
   popup della colonna delle azioni; vedi la scala z in nexus-shell.css,
   commento di .nx-account__menu) e sotto i layer dei dropdown
   DevExpress e il pannello d'errore Blazor, che devono restare visibili
   anche a schermo intero.

   L'altezza NON e' piu' la formula del foglio (100vh - 250): qui sopra non
   c'e' piu' niente da scontare, e il calcolo di prima lascerebbe 250px di
   telaio vuoto in fondo. */
.nx-chat-workspace--full {
  position: fixed;
  inset: 0;
  z-index: 900;
  height: 100vh;
  max-height: 100vh;
  padding: var(--nexus-space-3);
  gap: var(--nexus-space-3);
  background: var(--nx-bg);
}

/* Il contenitore prende il focus per ricevere Esc: e' un espediente
   tecnico, non uno stato da mostrare — l'anello di focus qui direbbe il
   falso (non e' un comando). Gli elementi dentro conservano il loro. */
.nx-chat-workspace:focus { outline: none; }

/* Il comando sta in fondo all'intestazione della chat, dove nella suite
   stanno i comandi di finestra. */
.nx-chat__fullscreen { flex: 0 0 auto; }

.nx-chat-side {
  display: flex;
  flex-direction: column;
  min-height: 0;
  gap: var(--nexus-space-2);
  padding: var(--nexus-space-3);
  border-radius: var(--nx-radius-card);
  background: var(--nx-surface);
  box-shadow: var(--nx-shadow-card);
}

.nx-chat-side__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--nexus-space-2);
}

.nx-chat-side__title {
  margin: 0;
  font-size: var(--nexus-fs-label);
  font-weight: var(--nexus-fw-semibold);
  color: var(--nx-text);
}

/* ---- elenco delle conversazioni ----------------------------
   Un solo componente per due superfici (2026-08-09): la colonna della
   pagina, dove sta sempre aperto, e il pannello dell'assistente, dove si
   apre da un'icona. Le regole sono le stesse; cambia solo il contenitore. */
/* min-width: 0 su TUTTA la catena, non solo qui: i titoli sono `nowrap`,
   quindi la larghezza minima di un elemento e' la riga INTERA finche' un
   discendente non dichiara di potersi stringere. Senza, l'elenco imponeva la
   sua larghezza al pannello e la ricerca usciva dal bordo (visto dall'utente
   il 2026-08-09: 56px fuori dal widget). */
.nx-conv-list {
  flex: 1 1 auto;
  min-width: 0;
  min-height: 0;
  display: flex;
  flex-direction: column;
  gap: var(--nexus-space-2);
}

/* Ricerca e archivio (2026-08-09): la ricerca interroga il database, il
   toggle mostra le conversazioni archiviate — rileggibili e ripristinabili. */
.nx-conv-list__filter {
  display: flex;
  flex-direction: column;
  gap: var(--nexus-space-1);
}

.nx-conv-list__search {
  /* box-sizing esplicito: i fogli Nexus non hanno un reset globale, e senza
     questa riga "width: 100%" e' la larghezza del CONTENUTO — padding e
     bordo si aggiungono fuori, e il campo esce dal pannello (visto
     dall'utente il 2026-08-09, widget dell'assistente). */
  box-sizing: border-box;
  width: 100%;
  min-width: 0;
  padding: var(--nexus-space-1) var(--nexus-space-2);
  border: 1px solid var(--nx-border);
  border-radius: var(--nexus-radius-md);
  background: var(--nx-surface);
  color: var(--nx-text);
  font-family: inherit;
  font-size: var(--nexus-fs-body-sm);
}

/* Interruttore "mostra archiviate": un CHIP, non una casella di spunta
   (richiesta dell'utente 2026-08-09). La casella nativa era l'unico elemento
   della chat disegnato dal sistema operativo — spenta in tema chiaro,
   stonata in tema scuro. Spento: un contorno appena accennato. Acceso: la
   velatura teal degli stati attivi della suite, la stessa della bolla della
   domanda e della riga selezionata. */
.nx-conv-list__chip {
  align-self: flex-start;
  display: inline-flex;
  align-items: center;
  gap: var(--nexus-space-1);
  height: 26px;
  padding: 0 var(--nexus-space-2);
  border: 1px solid var(--nx-border);
  border-radius: var(--nexus-radius-pill);
  background: transparent;
  color: var(--nx-text-muted);
  font-family: inherit;
  font-size: var(--nexus-fs-caption);
  cursor: pointer;
  transition: background-color var(--nexus-transition-fast),
              border-color var(--nexus-transition-fast),
              color var(--nexus-transition-fast);
}

.nx-conv-list__chip:hover:not(:disabled) { background: var(--nexus-hover-surface); color: var(--nx-text); }
.nx-conv-list__chip:disabled { opacity: var(--nexus-opacity-disabled); cursor: default; }
.nx-conv-list__chip:focus-visible { outline: none; box-shadow: var(--nexus-focus-ring); }

/* Lo stato acceso vale ANCHE sotto il puntatore: la regola di hover ha una
   specificita' piu' alta (`:hover:not(:disabled)` = tre elementi contro
   due), e senza questa seconda riga il chip perdeva la velatura teal proprio
   mentre lo si stava cliccando — misurato su TEST, fondo #EEF3F8 invece del
   teal. */
.nx-conv-list__chip.nx-active,
.nx-conv-list__chip.nx-active:hover:not(:disabled) {
  border-color: transparent;
  background: color-mix(in srgb, var(--nx-teal) 22%, var(--nx-surface));
  color: var(--nx-text);
}

/* L'icona segue il testo: spenta e' un accenno, accesa e' inchiostro pieno. */
.nx-conv-list__chip-icon { display: grid; place-items: center; opacity: .75; }
.nx-conv-list__chip.nx-active .nx-conv-list__chip-icon { opacity: 1; }

.nx-conv-list__badge {
  margin-left: var(--nexus-space-1);
  padding: 0 var(--nexus-space-1);
  border-radius: var(--nexus-radius-sm);
  background: var(--nexus-hover-surface);
  font-size: var(--nexus-fs-caption);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.nx-conv-list__item--archived .nx-conv-list__title { opacity: 0.7; }

.nx-conv-list__items {
  flex: 1 1 auto;
  min-width: 0;
  min-height: 0;
  overflow-y: auto;
  margin: 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.nx-conv-list__item {
  display: flex;
  min-width: 0;
  align-items: center;
  gap: var(--nexus-space-1);
  border-radius: var(--nexus-radius-md);
}

.nx-conv-list__item:hover { background: var(--nexus-hover-surface); }

/* La conversazione aperta porta la parentesi del marchio, come il tile
   attivo del rail: lo stato attivo nella suite si dice cosi'. */
.nx-conv-list__item--current {
  background: var(--nx-row-selected);
  box-shadow: inset var(--nx-bracket-w) 0 0 var(--nx-bracket-color);
}

.nx-conv-list__open {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 1px;
  padding: var(--nexus-space-2);
  border: 0;
  background: none;
  font-family: inherit;
  text-align: left;
  cursor: pointer;
}

/* La conversazione non ancora iniziata ha la stessa forma delle altre ma
   non si apre: e' gia' quella davanti. */
.nx-conv-list__open--static { cursor: default; }

.nx-conv-list__title {
  display: block;
  font-size: var(--nexus-fs-body-sm);
  color: var(--nx-text);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.nx-conv-list__meta {
  display: block;
  font-size: var(--nexus-fs-caption);
  color: var(--nx-text-faint);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Il pulsante di archiviazione compare all'hover: e' un'azione rara e
   distruttiva quanto basta per non stare sempre sotto il pollice. */
.nx-conv-list__archive {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: 26px;
  height: 26px;
  margin-right: var(--nexus-space-1);
  padding: 0;
  border: 0;
  border-radius: var(--nexus-radius-sm);
  background: none;
  color: var(--nx-text-faint);
  cursor: pointer;
  opacity: 0;
  transition: opacity var(--nexus-transition-fast), color var(--nexus-transition-fast);
}

.nx-conv-list__item:hover .nx-conv-list__archive,
.nx-conv-list__archive:focus-visible { opacity: 1; }
.nx-conv-list__archive:hover { color: var(--nx-danger-ink); }

.nx-conv-list__empty {
  padding: var(--nexus-space-3) var(--nexus-space-2);
  font-size: var(--nexus-fs-caption);
  color: var(--nx-text-faint);
}

/* Nel pannello l'elenco ha meno respiro: e' un passaggio, non una colonna
   dove si sosta. */
.nx-conv-list--compact { gap: var(--nexus-space-1); }
.nx-conv-list--compact .nx-conv-list__open { padding: var(--nexus-space-1) var(--nexus-space-2); }

/* ---- comandi di piede --------------------------------------
   I comandi che chiudono la superficie e CAMBIANO CIO' CHE SI GUARDA: le
   indicazioni permanenti aprono un pannello al posto della chat (nella pagina
   a destra, nel widget su tutto il widget — 2026-08-09), l'archivio sostituisce
   le conversazioni attive con quelle archiviate (2026-08-10). Sulla pagina
   stanno in coppia nel piede della colonna, e per questo hanno una BASE SOLA:
   due comandi affiancati che facessero la stessa cosa con due facce diverse si
   leggerebbero come due cose diverse. */
.nx-chat-notes-btn,
.nx-chat-side-btn {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: var(--nexus-space-2);
  padding: var(--nexus-space-2);
  border: 0;
  border-radius: var(--nexus-radius-md);
  background: none;
  color: var(--nx-text-muted);
  font-family: inherit;
  font-size: var(--nexus-fs-caption);
  font-weight: var(--nexus-fw-medium);
  text-align: left;
  cursor: pointer;
  transition: background-color var(--nexus-transition-fast), color var(--nexus-transition-fast);
}

/* Nel widget il comando e' a filo del bordo inferiore: li' serve la linea di
   separazione dalla chat e l'angolo del foglio. Nella pagina no — sta dentro
   una colonna con il suo respiro, e la linea la porta gia' il piede. */
.nx-dock > .nx-chat-notes-btn {
  border-top: 1px solid var(--nx-line-soft);
  border-radius: 0 0 var(--nx-radius-card) var(--nx-radius-card);
}

/* Il comando occupa tutta la larghezza del foglio: con il solo padding di base
   la targhetta e il conteggio restavano a filo dei due bordi (segnalato sul
   widget il 2026-08-28). Qui il respiro orizzontale e' piu' largo di quello
   verticale, e il numero si stacca anche dalla targhetta. */
.nx-chat-notes-btn {
  padding-inline: var(--nexus-space-3);
  gap: var(--nexus-space-3);
}

.nx-chat-notes-btn:hover:not(:disabled),
.nx-chat-side-btn:hover:not(:disabled) { background: var(--nexus-hover-surface); color: var(--nx-text); }
.nx-chat-notes-btn:focus-visible,
.nx-chat-side-btn:focus-visible { outline: none; box-shadow: var(--nexus-focus-ring); }
.nx-chat-side-btn:disabled { opacity: var(--nexus-opacity-disabled); cursor: default; }

/* Aperto: la parentesi del marchio, come ogni stato attivo della suite.
   Vale ANCHE sotto il puntatore — la regola di hover ha specificita' piu'
   alta, e senza questa seconda riga lo stato si perdeva proprio mentre lo si
   cliccava (stessa trappola del chip d'archivio, misurata su TEST). */
.nx-chat-notes-btn.nx-active,
.nx-chat-side-btn.nx-active,
.nx-chat-notes-btn.nx-active:hover:not(:disabled),
.nx-chat-side-btn.nx-active:hover:not(:disabled) {
  background: var(--nx-row-selected);
  color: var(--nx-text);
  box-shadow: inset var(--nx-bracket-w) 0 0 var(--nx-bracket-color);
}

/* L'icona segue il testo: spenta e' un accenno, accesa e' inchiostro pieno. */
.nx-chat-side-btn__icon { flex: 0 0 auto; display: grid; place-items: center; opacity: .75; }
.nx-chat-side-btn.nx-active .nx-chat-side-btn__icon { opacity: 1; }

/* La targhetta prende la riga e spinge il conteggio a destra. */
.nx-chat-notes-btn__label,
.nx-chat-side-btn__label { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.nx-chat-notes-btn__count,
.nx-chat-side-btn__count {
  flex: 0 0 auto;
  display: inline-grid;
  place-items: center;
  min-width: 18px;
  height: 18px;
  padding: 0 5px;
  border-radius: var(--nexus-radius-pill);
  background: var(--nexus-hover-surface);
  font-size: var(--nexus-fs-caption);
}

/* Il piede della colonna: sta in fondo perche' l'elenco sopra si prende tutto
   lo spazio che avanza (flex: 1), non per un margine calcolato a mano. */
.nx-chat-side__foot {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  gap: var(--nexus-space-1);
  padding-top: var(--nexus-space-2);
  border-top: 1px solid var(--nx-line-soft);
}

/* ---- pannello delle indicazioni (nello stage della pagina) --
   Le indicazioni prendono il posto della chat: sono regole che si leggono
   e si riscrivono, e in una colonna da 280px si leggevano una parola per
   riga (richiesta dell'utente 2026-08-09). */
.nx-chat-notes-panel {
  flex: 1 1 auto;
  min-width: 0;
  min-height: 0;
  display: flex;
  flex-direction: column;
  overflow-y: auto;
}

.nx-chat-notes-panel__head {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: var(--nexus-space-2);
  padding: var(--nexus-space-3) var(--nexus-space-4);
  border-bottom: 1px solid var(--nx-line-soft);
}

.nx-chat-notes-panel__title {
  flex: 1 1 auto;
  margin: 0;
  font-size: var(--nexus-fs-label);
  font-weight: var(--nexus-fw-semibold);
  color: var(--nx-text);
}

/* Il pannello prende TUTTO il corpo, come la chat che sostituisce
   (utente 2026-08-24). Fino a qui il contenuto si fermava a una colonna
   di lettura da 70ch: nata per non far leggere una regola lunga quanto
   una pagina, a video lasciava mezza finestra bianca accanto al campo, e
   accanto al thread della chat — che il corpo lo riempie — sembrava una
   maschera non finita. La riga lunga resta un problema di leggibilita'
   solo per il TESTO delle indicazioni: quello si tiene entro una colonna
   larga, i comandi no. */
.nx-chat-notes__help,
.nx-chat-notes__item { max-width: 110ch; }

/* Nel widget il pannello ha il respiro del widget, non quello della pagina. */
.nx-dock .nx-chat-notes-panel__head { padding: var(--nexus-space-3); }

.nx-chat-stage {
  display: flex;
  min-height: 0;
  border-radius: var(--nx-radius-card);
  background: var(--nx-surface);
  box-shadow: var(--nx-shadow-card);
  overflow: hidden;
}

@media (max-width: 1100px) {
  .nx-chat-workspace { grid-template-columns: 240px minmax(0, 1fr); }
}

/* Sotto gli 860px l'elenco passa sopra la chat e smette di rubarle
   larghezza: due colonne strette non si leggono. */
@media (max-width: 860px) {
  .nx-chat-workspace {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: auto minmax(0, 1fr);
    /* Stessa formula del desktop (l'ingombro sopra il workspace non
       cambia sotto gli 860px): rimisurata il 2026-08-25. */
    height: calc(100vh - 137px);
  }
  .nx-chat-side { max-height: 220px; }
}

/* ---- nucleo della chat ------------------------------------- */
.nx-chat {
  position: relative;                  /* ancora dell'elenco assistenti */
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  min-height: 0;
  min-width: 0;
}

.nx-chat__head {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: var(--nexus-space-2);
  padding: var(--nexus-space-3);
}

/* Sulla pagina c'e' spazio: il thread e il compositore respirano di piu'
   e la colonna di lettura non arriva ai bordi del foglio. Nel pannello
   ogni pixel orizzontale e' una parola in piu' per riga, e resta stretto. */
.nx-chat--page .nx-chat__head,
.nx-chat--page .nx-chat__thread { padding-inline: var(--nexus-space-4); }

.nx-chat--page .nx-chat__composer,
.nx-chat--page .nx-chat__banner { margin-inline: var(--nexus-space-4); }

.nx-chat__agent {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  align-items: baseline;
  gap: var(--nexus-space-2);
}

.nx-chat__agent-label {
  flex: 0 0 auto;
  font-size: var(--nexus-fs-caption);
  color: var(--nx-text-faint);
}

.nx-chat__agent-select { flex: 1 1 auto; min-width: 0; max-width: 320px; }

.nx-chat__agent-name {
  font-size: var(--nexus-fs-label);
  font-weight: var(--nexus-fw-semibold);
  color: var(--nx-text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.nx-chat__agent-name--none { color: var(--nx-text-faint); font-weight: var(--nexus-fw-regular); }

.nx-chat__agent-desc {
  min-width: 0;
  font-size: var(--nexus-fs-caption);
  color: var(--nx-text-faint);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Pulsante di servizio: testo e icona, nessuna superficie finche' non
   lo si tocca. I pulsanti pieni della chat sono uno solo (Invia). */
.nx-chat__ghost-btn {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  gap: var(--nexus-space-1);
  height: 30px;
  padding: 0 var(--nexus-space-2);
  border: 0;
  border-radius: var(--nexus-radius-md);
  background: transparent;
  color: var(--nx-text-muted);
  font-family: inherit;
  font-size: var(--nexus-fs-caption);
  cursor: pointer;
  transition: background-color var(--nexus-transition-fast), color var(--nexus-transition-fast);
}

.nx-chat__ghost-btn:hover:not(:disabled) { background: var(--nexus-hover-surface); color: var(--nx-text); }
.nx-chat__ghost-btn:disabled { opacity: var(--nexus-opacity-disabled); cursor: default; }
.nx-chat__ghost-btn:focus-visible { outline: none; box-shadow: var(--nexus-focus-ring); }
.nx-chat__btn-icon { display: grid; place-items: center; }

/* Nel pannello stretto il pulsante resta la sola icona. */
.nx-chat--compact .nx-chat__btn-text { display: none; }

/* ---- scelta dell'assistente: pulsante + elenco --------------
   Al posto della tendina sempre a video (richiesta dell'utente 2026-08-09):
   l'assistente si cambia di rado, e una tendina accanto al titolo pesava
   quanto un comando che si usa a ogni turno. Il pulsante porta il nome di
   chi risponde — che e' l'informazione — e l'elenco arriva al clic. */
.nx-chat__agent-btn {
  flex: 1 1 auto;
  min-width: 0;
  display: inline-flex;
  align-items: center;
  gap: var(--nexus-space-1);
  height: 30px;
  padding: 0 var(--nexus-space-2);
  border: 0;
  border-radius: var(--nexus-radius-md);
  background: transparent;
  color: var(--nx-text);
  font-family: inherit;
  cursor: pointer;
  transition: background-color var(--nexus-transition-fast);
}

.nx-chat__agent-btn:hover:not(:disabled) { background: var(--nexus-hover-surface); }
.nx-chat__agent-btn:disabled { opacity: var(--nexus-opacity-disabled); cursor: default; }
.nx-chat__agent-btn:focus-visible { outline: none; box-shadow: var(--nexus-focus-ring); }

/* Sipario trasparente: un clic fuori chiude, senza listener globali ne'
   interop — lo stesso del menu account e della campanella. */
.nx-chat__scrim {
  position: fixed;
  inset: 0;
  z-index: 45;
}

.nx-chat__pop {
  position: absolute;
  top: 44px;
  left: var(--nexus-space-3);
  z-index: 46;
  width: min(340px, calc(100% - var(--nexus-space-3) * 2));
  max-height: 320px;
  overflow-y: auto;
  padding: var(--nexus-space-1);
  border: 1px solid var(--nx-line);
  border-radius: var(--nx-radius-card);
  background: var(--nx-surface);
  box-shadow: var(--nx-shadow-float);
}

.nx-chat__pop-item {
  width: 100%;
  display: flex;
  flex-direction: column;
  gap: 1px;
  padding: var(--nexus-space-2);
  border: 0;
  border-radius: var(--nexus-radius-md);
  background: none;
  font-family: inherit;
  text-align: left;
  cursor: pointer;
}

.nx-chat__pop-item:hover { background: var(--nexus-hover-surface); }
.nx-chat__pop-item:focus-visible { outline: none; box-shadow: var(--nexus-focus-ring); }

.nx-chat__pop-item--current {
  background: var(--nx-row-selected);
  box-shadow: inset var(--nx-bracket-w) 0 0 var(--nx-bracket-color);
}

.nx-chat__pop-name {
  font-size: var(--nexus-fs-body-sm);
  font-weight: var(--nexus-fw-medium);
  color: var(--nx-text);
}

.nx-chat__pop-desc {
  font-size: var(--nexus-fs-caption);
  line-height: 1.4;
  color: var(--nx-text-faint);
}

/* ---- focus e agenti nell'elenco (D131, doc 14 par. 5g) --------------
   L'elenco non sceglie piu' UN assistente: ha sezioni (Focus, Agenti
   singoli, Agenti esterni) e voci che si accendono e si spengono. La
   spunta e' un quadratino disegnato in CSS, cosi' la voce spenta e quella
   accesa hanno la stessa altezza e il testo non balla. */
.nx-chat__pop-head {
  padding: var(--nexus-space-2) var(--nexus-space-2) var(--nexus-space-1);
  font-size: var(--nexus-fs-caption);
  font-weight: var(--nexus-fw-medium);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--nx-text-faint);
}

.nx-chat__pop-item--toggle .nx-chat__pop-name {
  display: flex;
  align-items: center;
  gap: var(--nexus-space-2);
}

.nx-chat__pop-check {
  flex: 0 0 auto;
  width: 14px;
  height: 14px;
  border: 1px solid var(--nx-line-strong, var(--nx-line));
  border-radius: 3px;
  background: var(--nx-surface);
}

.nx-chat__pop-item--checked .nx-chat__pop-check {
  border-color: var(--nx-bracket-color);
  background: var(--nx-bracket-color);
  box-shadow: inset 0 0 0 2px var(--nx-surface);
}

.nx-chat__pop-item--checked {
  background: var(--nx-row-selected);
}

/* ---- i partecipanti come BADGE (richiesta dell'utente 2026-09-08) ------
   Con tanti focus e tanti agenti l'elenco a spunte non si leggeva piu': ora
   ogni partecipante e' un badge in testata con la sua x, e l'elenco serve
   solo ad AGGIUNGERE, con la ricerca in cima. I badge vanno a capo quando
   non ci stanno: la testata cresce, il menu resta agganciato sotto. */
/* Con i badge la testata resta ALTA UNA RIGA: i partecipanti scorrono in
   orizzontale dentro .nx-chat__chips e il "+" sta fuori dalla striscia
   (richiesta dell'utente 2026-09-09). Andando a capo, cinque partecipanti
   si prendevano meta' dello schermo del telefono. */
.nx-chat__agent--chips {
  flex-wrap: nowrap;
  align-items: center;
}

.nx-chat__chips {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-wrap: nowrap;
  align-items: center;
  gap: var(--nexus-space-1);
  overflow-x: auto;
  overflow-y: hidden;
  /* Il dito scorre la striscia, la pagina resta ferma. */
  overscroll-behavior-x: contain;
  -webkit-overflow-scrolling: touch;
  scroll-snap-type: x proximity;
  /* La barra non si vede: lo dice la sfumatura, come nella striscia delle
     dashboard sul telefono (.nx-mboards) — stessa tecnica, stesso gesto. */
  scrollbar-width: none;
  -ms-overflow-style: none;
  -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 20px), transparent 100%);
  mask-image: linear-gradient(to right, #000 calc(100% - 20px), transparent 100%);
}

.nx-chat__chips::-webkit-scrollbar { width: 0; height: 0; }

/* Un respiro in coda: senza, a fine corsa l'ultimo badge resta mezzo spento
   sotto la sfumatura anche quando non c'e' piu' niente da scorrere. Uno
   pseudo-elemento e non un padding, che in overflow non tutti i motori
   contano. */
.nx-chat__chips::after {
  content: "";
  flex: 0 0 20px;
}

.nx-chat__chips > .nx-chat__chip { scroll-snap-align: start; }

/* A fine corsa la sfumatura si spegne da sola: se non c'e' altro da vedere,
   non deve esserci nulla che lo suggerisca. */
@supports (animation-timeline: scroll(x)) {
  .nx-chat__chips {
    animation: nx-chat-chips-fade linear;
    /* `self`: la striscia e' essa stessa lo scorritore (con `scroll(x)`
       nudo Chrome cerca l'antenato che scorre e la sfumatura non si spegne
       mai — pagata sulla striscia delle dashboard). */
    animation-timeline: scroll(self x);
  }

  @keyframes nx-chat-chips-fade {
    to {
      -webkit-mask-image: linear-gradient(to right, #000 100%, #000 100%);
      mask-image: linear-gradient(to right, #000 100%, #000 100%);
    }
  }
}

.nx-chat__chip {
  flex: 0 0 auto;
  min-width: 0;
  max-width: 220px;
  display: inline-flex;
  align-items: center;
  gap: var(--nexus-space-1);
  height: 26px;
  padding: 0 var(--nexus-space-1) 0 var(--nexus-space-2);
  border: 1px solid var(--nx-line);
  border-radius: 999px;
  background: var(--nx-surface);
  color: var(--nx-text);
  font-size: var(--nexus-fs-caption);
  font-weight: var(--nexus-fw-medium);
}

/* Il focus e' il perimetro: prende il colore degli stati attivi della
   suite. L'agente singolo resta neutro: e' una persona in piu' al tavolo. */
.nx-chat__chip--focus {
  border-color: var(--nx-bracket-color);
  background: var(--nx-row-selected);
  color: var(--nx-bracket-color);
}

/* L'agente singolo: dichiarato anche se neutro — la guardia
   AssistantChatUiTests vuole ogni classe del markup in un foglio, e una
   regola vuota qui e' il posto dove dargli un colore domani. */
.nx-chat__chip--agent {
  border-color: var(--nx-line);
  background: var(--nx-surface);
  color: var(--nx-text);
}

.nx-chat__chip-icon { display: grid; place-items: center; flex: 0 0 auto; }

.nx-chat__chip-name {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.nx-chat__chip-x {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: 18px;
  height: 18px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: transparent;
  color: inherit;
  font-family: inherit;
  font-size: 15px;
  line-height: 1;
  cursor: pointer;
  opacity: 0.7;
  transition: background-color var(--nexus-transition-fast), opacity var(--nexus-transition-fast);
}

.nx-chat__chip-x:hover:not(:disabled) { opacity: 1; background: var(--nexus-hover-surface); }
.nx-chat__chip-x:disabled { opacity: var(--nexus-opacity-disabled); cursor: default; }
.nx-chat__chip-x:focus-visible { outline: none; box-shadow: var(--nexus-focus-ring); }

/* Il "+" accanto ai badge: la sola icona, tonda, senza nome. */
.nx-chat__agent-btn--add {
  flex: 0 0 auto;
  width: 26px;
  height: 26px;
  padding: 0;
  justify-content: center;
  border: 1px dashed var(--nx-line);
  border-radius: 50%;
  color: var(--nx-text-muted);
}

.nx-chat__agent-btn--add:hover:not(:disabled) { color: var(--nx-text); border-color: var(--nx-line-strong, var(--nx-line)); }

/* La ricerca in cima all'elenco: resta ferma mentre le voci scorrono. */
.nx-chat__pop--picker { max-height: 380px; }

.nx-chat__pop-search {
  position: sticky;
  top: calc(-1 * var(--nexus-space-1));
  z-index: 1;
  margin: calc(-1 * var(--nexus-space-1)) calc(-1 * var(--nexus-space-1)) var(--nexus-space-1);
  padding: var(--nexus-space-2);
  background: var(--nx-surface);
  border-bottom: 1px solid var(--nx-line);
}

.nx-chat__pop-input {
  box-sizing: border-box;
  width: 100%;
  min-width: 0;
  padding: var(--nexus-space-1) var(--nexus-space-2);
  border: 1px solid var(--nx-border);
  border-radius: var(--nexus-radius-md);
  background: var(--nx-surface);
  color: var(--nx-text);
  font-family: inherit;
  font-size: var(--nexus-fs-body-sm);
}

.nx-chat__pop-input:focus-visible { outline: none; box-shadow: var(--nexus-focus-ring); }

.nx-chat__pop-item--add .nx-chat__pop-name {
  display: flex;
  align-items: center;
  gap: var(--nexus-space-2);
}

.nx-chat__pop-kind { flex: 0 0 auto; display: grid; place-items: center; color: var(--nx-text-faint); }

.nx-chat__pop-empty {
  padding: var(--nexus-space-3) var(--nexus-space-2);
  font-size: var(--nexus-fs-caption);
  color: var(--nx-text-faint);
  text-align: center;
}

/* ---- elenco conversazioni dentro il pannello ----------------
   Prende il posto del thread: nel pannello non c'e' spazio per due colonne,
   e il thread torna appena si sceglie (richiesta dell'utente 2026-08-09). */
.nx-chat__list-panel {
  flex: 1 1 auto;
  min-width: 0;
  min-height: 0;
  display: flex;
  padding: 0 var(--nexus-space-3) var(--nexus-space-2);
}

/* L'icona dell'elenco e quella dello schermo intero non si allargano. */
.nx-chat__convs { flex: 0 0 auto; }

/* Le indicazioni permanenti dentro la chat (superfici senza un piede dove
   mettere il comando: il telefono). Il numero addosso all'icona e' l'unica
   cosa che dice che una memoria ESISTE: senza, un'icona muta invita a non
   aprirla mai. */
.nx-chat__notes-toggle {
  flex: 0 0 auto;
  position: relative;
}

.nx-chat__notes-count {
  position: absolute;
  top: 0;
  inset-inline-end: 0;
  min-width: 15px;
  padding: 0 3px;
  border-radius: 999px;
  /* Stessi colori del badge dei non letti in topbar (nexus-shell.css): un
     numero addosso a un'icona nella suite si legge sempre allo stesso modo. */
  background: var(--nx-bracket-color, #14b8a6);
  color: #06202a;
  font-size: 10px;
  line-height: 15px;
  font-weight: 700;
  text-align: center;
  pointer-events: none;
}

/* Il pannello sta nel posto del thread e SCORRE da solo: il telaio mobile
   non scorre (nx-mfull), quindi un elenco di regole piu' alto dello schermo
   sarebbe irraggiungibile in fondo. */
.nx-chat__notes-panel { padding: 0; }

.nx-chat__notes-panel > .nx-chat-notes-panel {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
}

/* Nella colonna stretta il respiro e' quello del pannello, non della pagina. */
.nx-chat--compact .nx-chat-notes-panel__head { padding: var(--nexus-space-3); }

/* ---- avvisi ------------------------------------------------ */
.nx-chat__banner {
  flex: 0 0 auto;
  display: flex;
  align-items: flex-start;
  gap: var(--nexus-space-2);
  margin: 0 var(--nexus-space-3) var(--nexus-space-2);
  padding: var(--nexus-space-2) var(--nexus-space-3);
  border-radius: var(--nexus-radius-md);
  font-size: var(--nexus-fs-body-sm);
}

.nx-chat__banner--error { background: var(--nx-error-bg); color: var(--nx-error-ink); }
.nx-chat__banner--notice { background: var(--nx-warning-bg); color: var(--nx-warning-ink); }

.nx-chat__banner-close {
  margin-left: auto;
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  cursor: pointer;
  opacity: .7;
}

.nx-chat__banner-close:hover { opacity: 1; }

/* ---- thread ------------------------------------------------
   L'unico scroll della chat. Il compositore resta fermo sotto: e' la
   ragione per cui la pagina ha un'altezza vincolata. */
.nx-chat__thread {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: var(--nexus-space-3);
  padding: var(--nexus-space-3);
  scroll-behavior: smooth;
  /* Il thread e' un fondo, le bolle sono superfici: senza questo scalino
     la bolla dell'assistente (superficie chiara) e quella della domanda
     (velatura teal) avevano quasi la stessa luminanza e il turno non si
     distingueva a colpo d'occhio. */
  background: var(--nx-bg);
}

/* Mentre l'elenco delle conversazioni e' aperto il thread sparisce, ma
   resta NEL DOM: il riferimento all'elemento serve a rimettere lo scroll in
   fondo quando si torna. Dichiarata dopo la regola base, che altrimenti
   rimetterebbe il display (stessa specificita', vince l'ultima). */
.nx-chat__thread--hidden { display: none; }

/* ---- freccia "torna in fondo" ------------------------------
   Compare solo quando si e' sganciati dal fondo (richiesta dell'utente
   2026-08-23). Vive DENTRO il thread ed e' appiccicata al suo bordo
   inferiore: cosi' non deve sapere quanto e' alto il compositore, che
   cresce con la domanda che si sta scrivendo.
   Lo slot e' alto zero e non intercetta il puntatore — altrimenti in coda
   alla conversazione ci sarebbe una riga vuota, e una striscia invisibile
   sopra l'ultimo messaggio che ne mangia i clic. */
.nx-chat__jump-slot {
  position: sticky;
  bottom: 0;
  z-index: 3;
  height: 0;
  display: flex;
  justify-content: center;
  pointer-events: none;
  /* Lo slot e' l'ultimo figlio di un flex in colonna con gap: senza questo
     aggiungerebbe uno spazio in coda al thread. */
  margin-top: calc(var(--nexus-space-3) * -1);
}

.nx-chat__jump {
  pointer-events: auto;
  position: relative;
  /* Tutta dentro il thread: la linea dello slot e' il fondo dello scroller, e
     lo scroller TAGLIA quel che sborda (overflow-y: auto porta con se' anche
     l'asse orizzontale) — con un offset piu' piccolo la freccia si vedeva
     mozzata sul bordo del compositore. Altezza del pulsante piu' respiro. */
  bottom: calc(32px + var(--nexus-space-2));
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  padding: 0;
  border: 1px solid var(--nx-line);
  border-radius: 50%;
  /* Galleggia SOPRA il testo della risposta: fondo pieno e ombra staccata,
     o si legge il testo attraverso e non si capisce se sia un pulsante
     (misurato a video su TEST il 23/08, prima versione troppo tenue). */
  background: var(--nx-surface);
  color: var(--nx-text);
  box-shadow: var(--nx-shadow-float);
  cursor: pointer;
  transition: color .12s ease, border-color .12s ease, transform .12s ease;
}

.nx-chat__jump:hover {
  color: var(--nx-teal);
  border-color: var(--nx-teal);
  transform: translateY(1px);
}

@media (prefers-reduced-motion: reduce) {
  .nx-chat__jump { transition: none; }
  .nx-chat__jump:hover { transform: none; }
}

.nx-chat__msg { display: flex; }
.nx-chat__msg--user { justify-content: flex-end; }

/* La risposta puo' portarsi dietro delle ANNOTAZIONI — le fonti (D109) e i
   token spesi (D113) — che sono fratelli della bolla, non suoi figli: senza
   il ritorno a capo il flex le mette a FIANCO, e nel pannello stretto si
   leggeva "355 / token" incolonnato a destra della risposta (visto su TEST
   il 2026-09-03). Vanno sotto, a piena riga, allineate al bordo della bolla. */
.nx-chat__msg--assistant {
  justify-content: flex-start;
  flex-wrap: wrap;
  align-items: flex-start;
}

.nx-chat__msg--assistant > .nx-chat__sources,
.nx-chat__msg--assistant > .nx-chat__trace,
.nx-chat__msg--assistant > .nx-chat__meta { flex: 0 0 100%; }

/* Il messaggio del ruolo tool non arriva alla UI (il servizio lo filtra):
   se un giorno arrivasse, che si veda com'e' - una traccia tecnica. */
.nx-chat__msg--tool { justify-content: center; }

.nx-chat__bubble {
  max-width: 88%;
  padding: var(--nexus-space-2) var(--nexus-space-3);
  border-radius: var(--nx-radius-card);
  font-size: var(--nexus-fs-body-sm);
  line-height: 1.55;
  /* Il modello risponde con a capo ed elenchi: il testo si mostra come
     testo (mai markup interpretato) ma la sua impaginazione si rispetta. */
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

/* Domanda: velatura teal, l'accento della suite. Risposta: superficie
   quieta col bordo appena accennato - il peso visivo sta sul contenuto,
   non sul contenitore. */
.nx-chat__msg--user .nx-chat__bubble {
  background: color-mix(in srgb, var(--nx-teal) 20%, var(--nx-surface));
  color: var(--nx-text);
  border-bottom-right-radius: var(--nexus-radius-sm);
}

.nx-chat__msg--assistant .nx-chat__bubble {
  background: var(--nx-surface);
  color: var(--nx-text);
  border: 1px solid var(--nx-line);
  box-shadow: var(--nx-shadow-card);
  border-bottom-left-radius: var(--nexus-radius-sm);
}

.nx-chat__msg--tool .nx-chat__bubble {
  background: none;
  color: var(--nx-text-faint);
  font-family: var(--nx-font-mono);
  font-size: var(--nexus-fs-caption);
}

.nx-chat__bubble--pending {
  display: flex;
  align-items: center;
  gap: var(--nexus-space-2);
  color: var(--nx-text-muted);
}

/* Tre punti che si RINCORRONO: il turno puo' durare decine di secondi (piu'
   chiamate all'ERP, un agente figlio che lavora) e il movimento e' cio' che
   distingue "sta elaborando" da "si e' piantato". Onda ampia: punti da 7px,
   opacita' .18 -> 1, quattro pixel di salto e una crescita di scala che si
   vede anche di sfuggita; ciclo corto (1.05s) e ritardi brevi perche' si
   legga come un'onda sola, non come tre lampeggi separati. La frase accanto
   dice COSA sta facendo (vedi .nx-chat__pending-text): i punti dicono che
   sta facendo. */
.nx-chat__dots { display: inline-flex; align-items: center; gap: 5px; }

.nx-chat__dots span {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--nx-teal);
  animation: nx-chat-dot 1.05s infinite ease-in-out both;
  will-change: transform, opacity;
}

.nx-chat__dots span:nth-child(2) { animation-delay: .14s; }
.nx-chat__dots span:nth-child(3) { animation-delay: .28s; }

@keyframes nx-chat-dot {
  0%, 62%, 100% { opacity: .18; transform: translateY(0) scale(.8); }
  28% { opacity: 1; transform: translateY(-4px) scale(1.18); }
}

/* Chi ha chiesto meno animazioni non vuole i movimenti AMPI — quelli che
   spostano superfici e danno malessere. Un indicatore di attesa non e'
   decorazione: e' l'unico segnale che il sistema sta lavorando, e se si ferma
   la chat sembra bloccata (e' esattamente cio' che si e' visto il 2026-08-24
   su una macchina con gli effetti di animazione di Windows spenti: Chrome
   riporta reduce, i punti restavano fermi e l'attesa sembrava un errore).
   Resta quindi il movimento, ridotto a un pixel di salto e a un respiro di
   scala: percettibile, ma tanto piccolo da non essere un movimento nel campo
   visivo. Il resto — lo scorrimento del thread — li' si', si spegne. */
@media (prefers-reduced-motion: reduce) {
  .nx-chat__dots span {
    animation: nx-chat-dot-soft 1.4s infinite ease-in-out both;
  }
  .nx-chat__thread { scroll-behavior: auto; }
}

@keyframes nx-chat-dot-soft {
  0%, 62%, 100% { opacity: .22; transform: translateY(0) scale(.85); }
  30% { opacity: 1; transform: translateY(-1px) scale(1.1); }
}

/* La frase dell'attesa: e' un'informazione di servizio, non un messaggio.
   Piccola, smorzata e senza a capo — un nome di strumento lungo si taglia
   invece di far crescere la bolla mentre si guarda. */
.nx-chat__pending-text {
  font-size: var(--nexus-fs-caption);
  color: var(--nx-text-faint);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Il cronometro dell'attesa (2026-09-17): da quanto sta lavorando. Sta in
   coda alla frase e NON si lascia comprimere — la frase puo' accorciarsi con
   i puntini, il numero no, o resterebbe "1 mi...". Cifre tabellari: avanza
   ogni secondo e senza quelle la frase accanto si sposterebbe a ogni
   battito. */
.nx-chat__clock {
  flex: 0 0 auto;
  font-size: var(--nexus-fs-caption);
  color: var(--nx-text-faint);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* ---- risposta formattata (markdown minimale) ---------------
   Il testo lo costruisce AgentReplyMarkdown come elementi Blazor: qui si
   veste, e basta. Margini stretti: dentro una bolla, non su una pagina. */
/* La bolla della risposta NON eredita "pre-wrap" (difetto chiuso il
   2026-08-09, e questa e' la riga che lo chiude). Il pre-wrap serve alla
   bolla della DOMANDA, che e' testo grezzo; qui il testo e' gia' impaginato
   in elementi — gli a capo sono <br> veri e il codice ha `white-space: pre`
   suo — e in piu' faceva danno: dentro il canvas del grafico gli spazi fra i
   tag diventavano righe di testo VISIBILI, il disegno cresceva, il
   componente si ridisegnava per la nuova dimensione e ne generava altre. Il
   grafico "continuava a espandersi", a finestra ferma: misurato su TEST,
   l'SVG passava da 1071 a 3831 px in venti secondi. Provato per esclusione
   in pagina: e' l'unica regola la cui rimozione ferma la crescita. */
.nx-chat__bubble--rich {
  padding: var(--nexus-space-3);
  white-space: normal;
}

/* Bolla in scrittura (2026-08-11): il testo arriva a pezzi e non e' ancora
   passato dal renderer, quindi gli a capo li tiene il CSS. Il cursore
   lampeggiante dice che la risposta sta ancora arrivando — senza, una pausa
   del modello sembra la fine del turno. */
/* Niente pre-wrap da quando il testo in arrivo passa dal renderer del
   markdown (2026-08-15): gli a capo li mettono i blocchi, e tenerli anche
   qui raddoppiava lo spazio fra i paragrafi. */
.nx-chat__bubble--streaming {
  padding: var(--nexus-space-3);
}

/* Cio' che comparira' a turno finito e adesso non si puo' disegnare: il
   grafico. Una riga quieta, non un buco. */
.nx-md__pending {
  margin: var(--nexus-space-2) 0;
  padding: var(--nexus-space-2) var(--nexus-space-3);
  border-radius: var(--nx-radius, 8px);
  background: var(--nx-field);
  color: var(--nx-text-faint);
  font-size: var(--nexus-fs-caption);
}

.nx-chat__bubble--streaming::after {
  content: "";
  display: inline-block;
  width: 0.45em;
  height: 1em;
  margin-left: 2px;
  vertical-align: text-bottom;
  background: currentColor;
  opacity: 0.55;
  animation: nx-chat-caret 1s steps(2, start) infinite;
}

@keyframes nx-chat-caret {
  to { visibility: hidden; }
}

/* Chi ha chiesto meno animazioni non vuole nemmeno questa. */
@media (prefers-reduced-motion: reduce) {
  .nx-chat__bubble--streaming::after { animation: none; }
}

.nx-md > :first-child { margin-top: 0; }
.nx-md > :last-child { margin-bottom: 0; }

.nx-md-p { margin: 0 0 var(--nexus-space-2); }

.nx-md-heading {
  margin: var(--nexus-space-3) 0 var(--nexus-space-1);
  font-size: var(--nexus-fs-body-sm);
  font-weight: var(--nexus-fw-semibold);
  color: var(--nx-text);
}

.nx-md-list {
  margin: 0 0 var(--nexus-space-2);
  padding-left: var(--nexus-space-4);
}

.nx-md-list li { margin: 2px 0; }

.nx-md-inline-code,
.nx-md-code {
  font-family: var(--nx-font-mono);
  font-size: var(--nexus-fs-caption);
}

.nx-md-inline-code {
  padding: 1px 4px;
  border-radius: var(--nexus-radius-sm);
  background: var(--nx-field);
}

.nx-md-code {
  margin: 0 0 var(--nexus-space-2);
  padding: var(--nexus-space-2);
  border-radius: var(--nexus-radius-md);
  background: var(--nx-field);
  overflow-x: auto;                    /* il codice non allarga la bolla */
  white-space: pre;
}

/* La tabella scorre dentro il suo riquadro: una tabella larga non deve
   allargare la bolla ne' il pannello. */
.nx-md-table-wrap {
  margin: 0 0 var(--nexus-space-2);
  overflow-x: auto;
}

.nx-md-table {
  border-collapse: collapse;
  font-size: var(--nexus-fs-caption);
}

.nx-md-table th,
.nx-md-table td {
  padding: 4px var(--nexus-space-2);
  border-bottom: 1px solid var(--nx-line-soft);
  text-align: left;
  white-space: nowrap;
}

.nx-md-table th {
  color: var(--nx-text-faint);
  font-weight: var(--nexus-fw-semibold);
}

/* ---- grafico dichiarato dall'agente ------------------------
   LARGHEZZA IN PIXEL, e non in percentuale. La causa della crescita del
   2026-08-09 era un'altra (il pre-wrap ereditato: vedi
   .nx-chat__bubble--rich), ma la misura in pixel resta, per due ragioni:

   - il grafico ha una dimensione DICHIARATA e prevedibile: a schermo intero
     (doc 13 par. 31) una bolla all'88% di un thread larghissimo darebbe un
     grafico enorme, e un grafico enorme non si legge meglio;
   - toglie di mezzo un anello che con un contenitore fit-content e' sempre
     in agguato: canvas al 100% -> legge la bolla -> disegna -> il disegno
     diventa il contenuto piu' largo -> la bolla cresce -> il canvas rilegge.
     Con i pixel il contenuto non dipende dal contenitore; su un pannello
     stretto e' max-width a riportare dentro, ed e' un limite ESTERNO, che
     non torna indietro a cambiare il contenuto. */
.nx-chart {
  margin: 0;
  padding: var(--nexus-space-2) 0 0;
  width: 560px;
  max-width: 100%;
}

.nx-chart__title {
  margin-bottom: var(--nexus-space-1);
  font-size: var(--nexus-fs-body-sm);
  font-weight: var(--nexus-fw-semibold);
  color: var(--nx-text);
}

/* Il riquadro del disegno: altezza dichiarata e ritaglio. Senza, il canvas
   DevExpress deborda quando gli assi chiedono spazio e la didascalia
   finisce sopra le colonne (visto su TEST il 2026-08-02). */
.nx-chart__plot {
  position: relative;
  width: 100%;
  height: 240px;
  overflow: hidden;
  /* Seconda serratura sullo stesso anello: con il contenimento in linea la
     larghezza del riquadro si calcola SENZA guardare cosa c'e' dentro,
     quindi nemmeno un SVG piu' largo del previsto puo' allargare la bolla.
     Dove non e' supportato, resta la misura in pixel di .nx-chart. */
  contain: inline-size;
}

.nx-chart__canvas { max-width: 100%; }

/* La stessa avvertenza della chat, alla scala del grafico: un disegno
   convince piu' di un paragrafo, e qui serve ricordare da dove viene. */
.nx-chart__source {
  margin-top: var(--nexus-space-1);
  font-size: var(--nexus-fs-caption);
  color: var(--nx-text-faint);
}

/* ---- stato vuoto ------------------------------------------- */
.nx-chat__empty {
  margin: auto;
  max-width: 380px;
  padding: var(--nexus-space-4);
  text-align: center;
}

.nx-chat__empty-mark {
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  margin: 0 auto var(--nexus-space-3);
  border-radius: 50%;
  background: color-mix(in srgb, var(--nx-teal) 12%, transparent);
  color: var(--nx-teal-ink);
}

.nx-chat__empty-title {
  margin: 0 0 var(--nexus-space-1);
  font-size: var(--nexus-fs-label);
  font-weight: var(--nexus-fw-semibold);
  color: var(--nx-text);
}

.nx-chat__empty-text {
  margin: 0;
  font-size: var(--nexus-fs-body-sm);
  color: var(--nx-text-muted);
}

/* L'informazione "risponde un modello di IA" (AI Act art. 50(1), GA-F1 del
   doc 51) vive nella schermata iniziale di ogni conversazione, su tutte le
   superfici: piu' quieta del testo sopra, che e' l'invito a scrivere, e
   sotto un filo di separazione per non sembrare la seconda meta' della
   promessa. */
.nx-chat__empty-note {
  margin: var(--nexus-space-3) auto 0;
  padding-top: var(--nexus-space-2);
  max-width: 34rem;
  border-top: 1px solid var(--nx-border-subtle, var(--nexus-border));
  font-size: var(--nexus-fs-caption, 12px);
  line-height: 1.45;
  color: var(--nx-text-muted);
}
/* ---- compositore -------------------------------------------
   Campo senza bordo su fondo --nx-field, come gli editor del tema v2
   (doc 13 par. v2.5): il contenitore si vede per luminanza, non per
   contorno. L'anello di fuoco arriva sul contenitore intero, non sulla
   sola textarea, cosi' il pulsante Invia non resta fuori dal fuoco. */
.nx-chat__composer {
  flex: 0 0 auto;
  display: flex;
  align-items: flex-end;
  gap: var(--nexus-space-2);
  /* 4px in cima e non 0: l'anello di focus e' un box-shadow che sborda 3px
     su OGNI lato, e sopra il compositore comincia subito il thread — che ha
     uno sfondo opaco e scorre. Con distanza zero il lato ALTO dell'anello
     finiva dentro l'area del thread e spariva: il riquadro sembrava aperto
     in cima (segnalato dall'utente 2026-08-15, visto sul telefono ma vero
     su entrambe le superfici). Il margine da' all'anello dove stare; lo
     z-index qui sotto e' la cintura. */
  margin: 4px var(--nexus-space-3) var(--nexus-space-2);
  /* Respiro verticale maggiore dell'orizzontale: con 8px il bordo alto del
     riquadro cadeva sulla prima riga di testo e sembrava che il campo
     fosse tagliato (segnalato dall'utente 2026-08-02). */
  padding: var(--nexus-space-3) var(--nexus-space-2);
  border-radius: var(--nx-radius-card);
  background: var(--nx-field);
  transition: box-shadow var(--nexus-transition-fast);
  /* Il thread e' il fratello PRECEDENTE e scorre (overflow: auto): su iOS
     si prende un layer di composizione proprio e passa sopra a cio' che
     sborda dal compositore. Alzandolo di un gradino, l'anello resta
     intero. */
  position: relative;
  z-index: 1;
}

.nx-chat__composer:focus-within { box-shadow: var(--nexus-focus-ring); }

/* Altezza del campo (richiesta dell'utente 2026-09-09): la misura di
   partenza e' UNA VOLTA E MEZZO quella di prima (due righe nel pannello
   stretto -> tre; tre nella pagina -> quattro e mezzo), e scrivendo una
   domanda lunga il campo CRESCE da solo fino al doppio di prima (quattro
   righe / sei), poi scorre. Le righe sono variabili: lo script che adatta
   l'altezza (nexusChat._fit) misura il contenuto, e il tetto lo mette
   max-height. `1.5em` e' l'interlinea qui sotto: cambiarne una senza
   l'altra sballa il conto. */
.nx-chat__input {
  --nx-composer-rows: 3;
  --nx-composer-rows-max: 4;
  flex: 1 1 auto;
  min-width: 0;
  border: 0;
  background: none;
  resize: none;
  padding: var(--nexus-space-1) var(--nexus-space-1);
  color: var(--nx-text);
  font-family: inherit;
  font-size: var(--nexus-fs-body-sm);
  line-height: 1.5;
  min-height: calc(var(--nx-composer-rows) * 1.5em + 2 * var(--nexus-space-1));
  max-height: calc(var(--nx-composer-rows-max) * 1.5em + 2 * var(--nexus-space-1));
  overflow-y: auto;
  box-sizing: border-box;
}

.nx-chat--page .nx-chat__input {
  --nx-composer-rows: 4.5;
  --nx-composer-rows-max: 6;
}

.nx-chat__input:focus { outline: none; }
.nx-chat__input::placeholder { color: var(--nx-text-faint); }
.nx-chat__input:disabled { color: var(--nexus-disabled-fg); }

.nx-chat__send {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  /* Anche in orizzontale: quando la parola e' nascosta (pannello stretto,
     telefono) resta la sola icona, e senza questa riga si appoggiava al
     bordo sinistro invece di stare in mezzo — 8px da una parte, 20
     dall'altra sul pulsante da 44px (misurato il 2026-08-15). */
  justify-content: center;
  gap: var(--nexus-space-1);
  height: 32px;
  padding: 0 var(--nexus-space-3);
  border: 0;
  border-radius: var(--nexus-radius-md);
  /* Stessa vernice di .nx-btn-primary (nexus-v2-tokens.css): teal con
     inchiostro navy, non bianco - sul teal chiaro il bianco non tiene il
     contrasto. Qui la geometria e' diversa, quindi si ripete il colore
     invece di ereditare la classe opt-in. */
  background: var(--nx-teal);
  color: var(--nx-navy-deep);
  box-shadow: var(--nx-shadow-cta);
  font-family: inherit;
  font-size: var(--nexus-fs-caption);
  font-weight: var(--nexus-fw-semibold);
  cursor: pointer;
  transition: background-color var(--nexus-transition-fast), box-shadow var(--nexus-transition-fast);
}

.nx-chat__send:hover:not(:disabled) { background: var(--nx-teal-hover); }

/* Ferma la generazione: stesso posto, stessa forma e **stessa vernice** del
   pulsante Invia — cambia solo l'icona (richiesta dell'utente 2026-08-15:
   "non voglio vedere l'icona gialla, solo la X"). Un colore diverso per due
   secondi si nota piu' del comando che offre, e fermare non e' un'azione
   d'allarme: e' un comando ordinario. */
.nx-chat__send--stop:hover { filter: brightness(0.96); }
.nx-chat__send:disabled {
  background: var(--nexus-disabled-bg);
  color: var(--nexus-disabled-fg);
  box-shadow: none;
  cursor: default;
}
.nx-chat__send:focus-visible { outline: none; box-shadow: var(--nexus-focus-ring); }

/* Nel pannello stretto il pulsante resta la sola icona: la parola
   toglierebbe caratteri alla riga di scrittura. */
.nx-chat--compact .nx-chat__send { padding: 0 var(--nexus-space-2); }
.nx-chat--compact .nx-chat__send-text { display: none; }

/* ---- allegati (D77) ----------------------------------------
   La graffetta e' una label che CONTIENE l'input file: il click apre il
   selettore senza interop, e l'input resta nel flusso per l'accessibilita'
   ma invisibile (non display:none, che su alcuni browser spegne il click
   della label). */
.nx-chat__attach {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  border-radius: var(--nexus-radius-md);
  color: var(--nx-text-muted);
  cursor: pointer;
  position: relative;
  overflow: hidden;
  transition: background-color var(--nexus-transition-fast), color var(--nexus-transition-fast);
}

.nx-chat__attach:hover {
  background: color-mix(in srgb, var(--nx-teal) 12%, transparent);
  color: var(--nx-teal-ink);
}

.nx-chat__attach--disabled {
  color: var(--nexus-disabled-fg);
  cursor: default;
  pointer-events: none;
}

.nx-chat__attach input[type="file"] {
  position: absolute;
  inset: 0;
  opacity: 0;
  width: 100%;
  height: 100%;
  cursor: pointer;
}

.nx-chat__attach:focus-within { box-shadow: var(--nexus-focus-ring); }

/* I chip in attesa sopra il compositore: stessa geometria dei chip nella
   bolla, piu' la miniatura e la X di rimozione. */
.nx-chat__pending-files {
  flex: 0 0 auto;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--nexus-space-1);
  margin: 0 var(--nexus-space-3);
  padding: var(--nexus-space-1) 0 0;
}

.nx-chat__file {
  display: inline-flex;
  align-items: center;
  gap: var(--nexus-space-1);
  max-width: 100%;
  padding: 2px var(--nexus-space-2);
  border-radius: var(--nexus-radius-md);
  background: color-mix(in srgb, var(--nx-teal) 10%, transparent);
  color: var(--nx-text);
  font-size: var(--nexus-fs-caption);
  line-height: 1.4;
}

/* Il chip in attesa porta la X di rimozione: il respiro a destra lo mette
   la X stessa, non il padding del chip. */
.nx-chat__file--pending { padding-right: 2px; }

.nx-chat__file-name {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 180px;
}

.nx-chat__file-thumb {
  width: 20px;
  height: 20px;
  border-radius: 4px;
  object-fit: cover;
}

.nx-chat__file-remove {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  border: 0;
  border-radius: 50%;
  background: none;
  color: var(--nx-text-muted);
  cursor: pointer;
}

.nx-chat__file-remove:hover {
  background: color-mix(in srgb, var(--nx-text) 12%, transparent);
  color: var(--nx-text);
}

.nx-chat__file-error {
  font-size: var(--nexus-fs-caption);
  color: var(--nexus-danger, #b3261e);
}

/* I chip DENTRO la bolla utente: sopra il testo, staccati di un rigo.
   La bolla e' pre-wrap, quindi il blocco e' un inline-flex che va a capo
   da solo prima del testo. */
.nx-chat__bubble .nx-chat__files {
  display: flex;
  flex-wrap: wrap;
  gap: var(--nexus-space-1);
  margin-bottom: var(--nexus-space-1);
}

.nx-chat__bubble .nx-chat__file {
  background: color-mix(in srgb, var(--nx-navy-deep) 10%, transparent);
}

/* ---- indicazioni permanenti -------------------------------- */
/* Il blocco e' sempre il contenuto di un pannello (.nx-chat-notes-panel),
   su entrambe le superfici: niente fisarmonica, niente riepilogo — quelli
   servivano finche' viveva in fondo al pannello dell'assistente e si apriva
   in una striscia alta due righe (superato il 2026-08-09). Le regole del
   summary e del contatore sono sparite con lui. */
.nx-chat-notes {
  /* Il rientro del contenuto e' quello dell'INTESTAZIONE del pannello che
     lo ospita: prima erano 20px contro 16px e le due righe non erano
     incolonnate — quattro pixel che si vedono tutti. */
  --nx-notes-pad: var(--nexus-space-4);
  flex: 0 0 auto;
  padding: var(--nexus-space-3) 0;
  font-size: var(--nexus-fs-body-sm);
}

/* Nel widget l'intestazione ha il respiro del widget: il corpo la segue. */
.nx-dock .nx-chat-notes { --nx-notes-pad: var(--nexus-space-3); }

.nx-chat-notes__help {
  margin: 0 var(--nx-notes-pad) var(--nexus-space-2);
  font-size: var(--nexus-fs-caption);
  line-height: 1.45;
  color: var(--nx-text-faint);
}

.nx-chat-notes__list {
  margin: 0 var(--nx-notes-pad) var(--nexus-space-2);
  padding: 0;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: var(--nexus-space-1);
  max-height: 190px;
  overflow-y: auto;
}

.nx-chat-notes__item {
  display: flex;
  align-items: baseline;
  gap: var(--nexus-space-2);
  padding: var(--nexus-space-1) var(--nexus-space-2);
  border-radius: var(--nexus-radius-sm);
  background: var(--nx-surface-alt);
}

.nx-chat-notes__scope {
  flex: 0 0 auto;
  font-family: var(--nx-font-mono);
  font-size: var(--nexus-fs-caption);
  color: var(--nx-text-faint);
}

.nx-chat-notes__text {
  flex: 1 1 auto;
  min-width: 0;
  font-size: var(--nexus-fs-caption);
  color: var(--nx-text);
  overflow-wrap: anywhere;
}

.nx-chat-notes__forget {
  flex: 0 0 auto;
  align-self: center;
  display: grid;
  place-items: center;
  width: 22px;
  height: 22px;
  padding: 0;
  border: 0;
  border-radius: var(--nexus-radius-sm);
  background: none;
  color: var(--nx-text-faint);
  cursor: pointer;
}

.nx-chat-notes__forget:hover { color: var(--nx-danger-ink); }

.nx-chat-notes__add {
  display: flex;
  align-items: center;
  gap: var(--nexus-space-2);
  margin: 0 var(--nx-notes-pad) var(--nexus-space-3);
}

.nx-chat-notes__input {
  flex: 1 1 auto;
  min-width: 0;
  height: 30px;
  padding: 0 var(--nexus-space-2);
  border: 0;
  border-radius: var(--nexus-radius-md);
  background: var(--nx-field);
  color: var(--nx-text);
  font-family: inherit;
  font-size: var(--nexus-fs-caption);
}

.nx-chat-notes__input:focus { outline: none; box-shadow: var(--nexus-focus-ring); }
.nx-chat-notes__input::placeholder { color: var(--nx-text-faint); }

/* ---- finestra sganciata (doc 13 par. 40) --------------------
   La chat fuori dal portale, in una finestra del browser tutta sua: niente
   top bar, niente rail, niente striscia delle schede — quella cornice qui
   non c'e' proprio, non e' nascosta.

   Altezza 100dvh e non 100vh: sui browser con barra dinamica (e su una
   finestra piccola trascinata sul secondo schermo) vh mente di qualche
   decina di pixel, e a pagare e' sempre il compositore, che finisce sotto
   il bordo. Il fondo lo scrive la pagina: qui sotto non c'e' nessuna shell
   da cui ereditarlo. */
.nx-chat-window {
  display: flex;
  flex-direction: column;
  gap: var(--nexus-space-2);
  height: 100dvh;
  padding: var(--nexus-space-3);
  background: var(--nx-bg);
}

.nx-chat-window__head {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: var(--nexus-space-2);
  padding: 0 var(--nexus-space-1);
}

.nx-chat-window__mark {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  color: var(--nx-text-muted);
}

.nx-chat-window__title {
  flex: 1 1 auto;
  min-width: 0;
  margin: 0;
  overflow: hidden;
  color: var(--nx-text);
  font-family: var(--nexus-font-heading);
  font-size: var(--nexus-fs-body);
  font-weight: var(--nexus-fw-semibold);
  text-overflow: ellipsis;
  white-space: nowrap;
}

.nx-chat-window__back { flex: 0 0 auto; }

/* Il corpo e' il foglio: la chat ci vive dentro con il suo scroll, come
   nello stage della pagina. min-height 0 e' quello che permette al thread
   di scorrere invece di spingere il compositore fuori dalla finestra. */
.nx-chat-window__body {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  min-height: 0;
  border-radius: var(--nx-radius-card);
  background: var(--nx-surface);
  box-shadow: var(--nx-shadow-card);
  overflow: hidden;
}

/* Come nel widget: il comando delle indicazioni permanenti sta a filo del
   bordo inferiore, quindi porta lui la linea di separazione e l'angolo. */
.nx-chat-window__body > .nx-chat-notes-btn {
  border-top: 1px solid var(--nx-line-soft);
  border-radius: 0 0 var(--nx-radius-card) var(--nx-radius-card);
}

/* Il comando di sgancio sta fra i comandi di finestra del widget, accanto
   ai due estremi di larghezza. */
.nx-dock__detach { flex: 0 0 auto; }

/* Il microfono della dettatura (doc 38 par. 5.5): stessa forma della
   graffetta, perche' sono due modi di mettere qualcosa nella domanda. */
.nx-chat__mic {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  border: 0;
  border-radius: var(--nexus-radius-md);
  background: none;
  color: var(--nx-text-muted);
  cursor: pointer;
  transition: background-color var(--nexus-transition-fast), color var(--nexus-transition-fast);
}

.nx-chat__mic:disabled {
  opacity: 0.45;
  cursor: default;
}

/* Mentre ascolta si vede: la classe la mette e la toglie il riconoscitore
   nel browser, perche' e' lui a sapere quando si e' fermato davvero — un
   riscontro gestito dal server resterebbe acceso dopo la fine della frase. */
.nx-chat__mic--on {
  background: var(--nx-error-bg);
  color: var(--nx-error-ink);
}

/* Le fonti della risposta (D109, doc 41 par. 8): una riga sotto la bolla,
   calcolata dalla traccia degli strumenti e mai dal testo del modello.
   Stesso chip degli allegati, un tono piu' basso: e' un'annotazione, non
   un contenuto. Compare solo se uno strumento ERP ha risposto. */
.nx-chat__sources {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--nexus-space-1);
  margin: 0 var(--nexus-space-3);
  padding: var(--nexus-space-1) 0 0;
  font-size: var(--nexus-fs-caption);
  color: var(--nx-text-muted, var(--nx-text));
}

.nx-chat__sources-label {
  opacity: 0.75;
}

.nx-chat__sources-label::after {
  content: ":";
}

/* Lo svolgimento della risposta (D133): cosa ha fatto l'assistente per
   arrivarci. Sta SOPRA la bolla (richiesta dell'utente 2026-09-09): e' li'
   che si legge mentre il turno gira, e a turno finito non si sposta — la
   risposta arriva sotto. Si apre e si chiude, chiuso di serie, perche' su un
   turno lungo sono dieci righe che non tutti vogliono sempre a video. */
.nx-chat__trace {
  margin: 0 var(--nexus-space-3) var(--nexus-space-1);
  padding: 0;
  font-size: var(--nexus-fs-caption);
  color: var(--nx-text-faint);
  /* E' un flex item: senza min-width 0 una tabella nelle righe dello
     specialista lo allarga oltre lo schermo del telefono, e Safari su iOS
     INGRANDISCE il testo dei blocchi piu' larghi della finestra (visto su
     iPhone il 2026-09-09: ragionamento a corpo doppio e tagliato a destra).
     Il tetto e il text-size-adjust chiudono le due strade. */
  min-width: 0;
  max-width: 100%;
  overflow-wrap: anywhere;
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}

.nx-chat__trace .nx-md-table-wrap { max-width: 100%; }

.nx-chat__trace-head {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 0;
  border: 0;
  background: transparent;
  color: inherit;
  font: inherit;
  cursor: pointer;
}

.nx-chat__trace-head:hover { color: var(--nx-text-muted, var(--nx-text)); }
.nx-chat__trace-head:focus-visible { outline: none; box-shadow: var(--nexus-focus-ring); border-radius: var(--nx-radius-sm, 4px); }

/* La freccia gira invece di cambiare icona: e' lo stesso gesto delle
   fisarmoniche del portale. */
.nx-chat__trace-caret {
  display: grid;
  place-items: center;
  transform: rotate(-90deg);
  transition: transform var(--nexus-transition-fast);
}

.nx-chat__trace-caret--open { transform: rotate(0deg); }

.nx-chat__trace-list {
  margin: var(--nexus-space-1) 0 0;
  padding: 0 0 0 var(--nexus-space-3);
  list-style: decimal;
}

.nx-chat__trace-step {
  margin: 0;
  padding: 2px 0;
  overflow-wrap: anywhere;
}

/* Cio' che il modello ha SCRITTO prima del passaggio: e' il ragionamento, ed
   e' la parte che si legge — sta sopra, a piena riga, con l'impaginazione
   che aveva mentre scorreva (`pre-wrap`, come la bolla). */
.nx-chat__trace-said {
  display: block;
  color: var(--nx-text-muted, var(--nx-text));
  line-height: 1.5;
}

/* Cosa ha fatto: una riga di servizio sotto la frase, piu' tenue. */
.nx-chat__trace-did {
  display: block;
  color: var(--nx-text-faint);
  font-variant-numeric: tabular-nums;
}

.nx-chat__trace-said + .nx-chat__trace-did { margin-top: 2px; }

/* Quanti passaggi, accanto al titolo: un numero, non una parola in piu'. */
.nx-chat__trace-count {
  min-width: 16px;
  padding: 0 5px;
  border-radius: 999px;
  background: var(--nexus-hover-surface, rgba(127, 127, 127, 0.12));
  font-variant-numeric: tabular-nums;
  line-height: 1.6;
}

/* Cio' che e' arrivato MENTRE il passaggio girava: le righe di un agente
   delegato. Sotto la riga di servizio, rientrate di poco: sono parole di
   un altro, e si devono distinguere da quelle dell'assistente. */
.nx-chat__trace-reply {
  display: block;
  margin-top: 2px;
  padding-left: var(--nexus-space-2);
  border-left: 2px solid var(--nx-border, rgba(127, 127, 127, 0.3));
  color: var(--nx-text-muted, var(--nx-text));
  line-height: 1.5;
}

/* Il testo del giro in corso, in coda al blocco, mentre il turno gira: non
   e' ancora di nessun passaggio. Non e' numerato — non e' un passaggio — e
   porta il cursore che lampeggia, come la bolla in scrittura di prima. */
.nx-chat__trace-step--now { list-style: none; margin-left: calc(-1 * var(--nexus-space-3)); }

.nx-chat__trace-now::after {
  content: "";
  display: inline-block;
  width: 0.45em;
  height: 1em;
  margin-left: 2px;
  vertical-align: text-bottom;
  background: currentColor;
  opacity: 0.55;
  animation: nx-chat-caret 1s steps(2, start) infinite;
}

@media (prefers-reduced-motion: reduce) {
  .nx-chat__trace-now::after { animation: none; }
}

.nx-chat__pending-now {
  display: flex;
  align-items: center;
  gap: var(--nexus-space-2);
}

/* Le domande di rilancio (doc 45 par. 10 P7): pastiglie sotto la risposta,
   dentro la bolla. Sono suggerimenti, non azioni: peso normale, contorno
   leggero, nessun colore di comando — chi le clicca si ritrova la domanda
   nella casella, non una risposta in arrivo. */
.nx-chat__followups {
  display: flex;
  flex-wrap: wrap;
  gap: var(--nexus-space-1);
  margin-top: var(--nexus-space-2);
}

.nx-chat__followup {
  max-width: 100%;
  padding: 2px var(--nexus-space-2);
  border: 1px solid var(--nx-border);
  border-radius: 999px;
  background: transparent;
  color: var(--nx-text);
  font-size: var(--nexus-fs-caption);
  font-family: inherit;
  line-height: 1.6;
  text-align: left;
  cursor: pointer;
}

.nx-chat__followup:hover,
.nx-chat__followup:focus-visible {
  background: var(--nx-surface-hover, rgba(127, 127, 127, 0.12));
}

/* Quanto ci ha messo e quanto e' costata la risposta (D113 + il tempo,
   2026-09-17): stessa riga discreta delle fonti, sotto la bolla, perche'
   sono dati di servizio — si leggono se li si cerca, non intercettano
   l'occhio di chi sta leggendo la risposta. Una riga sola per entrambi: due
   annotazioni incolonnate sotto ogni risposta diventano rumore. */
.nx-chat__meta {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--nexus-space-2);
  margin: 0 var(--nexus-space-3);
  padding: var(--nexus-space-1) 0 0;
  font-size: var(--nexus-fs-caption);
  color: var(--nx-text-faint);
  /* Cifre a larghezza fissa: il tempo e i token cambiano a ogni risposta e
     senza questo la riga balla da un messaggio all'altro. */
  font-variant-numeric: tabular-nums;
}

.nx-chat__elapsed,
.nx-chat__tokens { white-space: nowrap; }

/* Il puntino fra tempo e token: due numeri accostati dal solo spazio si
   leggono come uno solo ("12 s 38,5k token"). Sta nel CSS e non nel markup
   perche' e' punteggiatura, non contenuto: chi legge con uno screen reader
   sente due annotazioni, non un separatore. */
.nx-chat__meta > span + span::before {
  content: "\00B7";
  margin-right: var(--nexus-space-2);
  opacity: .65;
}

/* Il totale della conversazione, in testata: numero tabellare perche'
   cambia a ogni turno e non deve far ballare i comandi accanto. */
.nx-chat__meter {
  flex: 0 0 auto;
  font-size: var(--nexus-fs-caption);
  color: var(--nx-text-faint);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* Risposta fermata (D113): il segno sta in cima alla bolla, dove si comincia
   a leggere. Colore d'avviso, non d'errore — non e' un guasto, e' una scelta
   di chi leggeva. Il bordo a sinistra tiene il segno agganciato al testo
   anche quando la risposta e' lunga. */
.nx-chat__bubble--interrupted {
  border-inline-start: 2px solid color-mix(in srgb, var(--nx-warning-ink, var(--nx-text)) 45%, transparent);
}

.nx-chat__stopped {
  display: flex;
  align-items: center;
  gap: var(--nexus-space-1);
  margin-bottom: var(--nexus-space-2);
  font-size: var(--nexus-fs-caption);
  color: var(--nx-warning-ink, var(--nx-text));
}

.nx-chat__stopped-empty {
  font-size: var(--nexus-fs-caption);
  color: var(--nx-text-faint);
  font-style: italic;
}

.nx-chat__source {
  display: inline-flex;
  align-items: center;
  padding: 1px var(--nexus-space-2);
  border-radius: var(--nexus-radius-md);
  background: color-mix(in srgb, var(--nx-teal) 10%, transparent);
  color: var(--nx-text);
  line-height: 1.4;
}

/* Il giudizio sulla risposta (doc 45 par. 10 P7): due pollici discreti sotto
   la bolla, nella stessa famiglia delle fonti e dei token — sono annotazioni
   di servizio, non comandi. Si accendono quando il giudizio c'e', cosi' chi
   torna sulla conversazione vede cosa aveva gia' detto. */
.nx-chat__rating {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--nexus-space-1);
  margin: 0 var(--nexus-space-3);
  padding: var(--nexus-space-1) 0 0;
}

.nx-chat__rate {
  display: inline-flex;
  align-items: center;
  padding: 2px 6px;
  border: 1px solid transparent;
  border-radius: var(--nx-radius-input, 6px);
  background: transparent;
  color: var(--nx-text-faint);
  cursor: pointer;
  opacity: 0.6;
}

.nx-chat__rate:hover,
.nx-chat__rate:focus-visible { opacity: 1; }

.nx-chat__rate--on {
  opacity: 1;
  border-color: var(--nx-border);
  color: var(--nx-text);
}

/* I motivi del pollice verso: compaiono in riga sotto i pollici, e stanno
   dentro la larghezza della bolla anche su schermo stretto. */
.nx-chat__rating-why {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--nexus-space-2);
  flex: 1 1 100%;
  padding-top: var(--nexus-space-1);
  font-size: var(--nexus-fs-caption);
}

.nx-chat__rating-check {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  cursor: pointer;
}

.nx-chat__rating-text {
  flex: 1 1 180px;
  min-width: 0;
  padding: 2px 6px;
  border: 1px solid var(--nx-border);
  border-radius: var(--nx-radius-input, 6px);
  background: transparent;
  color: var(--nx-text);
  font-family: inherit;
  font-size: var(--nexus-fs-caption);
}

.nx-chat__rating-send {
  padding: 2px var(--nexus-space-2);
  border: 1px solid var(--nx-border);
  border-radius: var(--nx-radius-input, 6px);
  background: transparent;
  color: var(--nx-text);
  font-family: inherit;
  font-size: var(--nexus-fs-caption);
  cursor: pointer;
}

/* L'azione che aspetta un permesso (doc 45 par. 10 P2). Non e' un messaggio
   della conversazione: e' un blocco che interrompe la lettura, perche' finche'
   non si risponde il turno resta fermo. Contorno d'avviso, non d'errore —
   non e' successo niente di male, si sta chiedendo. */
.nx-chat__approval {
  margin: var(--nexus-space-2) var(--nexus-space-3);
  padding: var(--nexus-space-3);
  border: 1px solid var(--nx-warning, #c88a00);
  border-radius: var(--nx-radius-card);
  background: var(--nx-surface);
}

.nx-chat__approval-head {
  display: flex;
  align-items: center;
  gap: var(--nexus-space-2);
  font-weight: 600;
}

/* Il nome dello strumento nella lingua di chi legge: e' la riga che dice di
   che cosa si tratta, e viene prima del codice. */
.nx-chat__approval-name {
  margin-top: var(--nexus-space-2);
  font-weight: 600;
}

/* Il codice resta, ma come identificativo tecnico: piccolo e smorzato. E'
   quello che si cerca nell'audit, non quello che si legge per decidere. */
.nx-chat__approval-tool {
  margin-top: 2px;
  font-family: var(--nx-font-mono, ui-monospace, monospace);
  font-size: var(--nexus-fs-caption);
  color: var(--nx-text-faint, var(--nx-text-muted, var(--nx-text)));
}

.nx-chat__approval-what {
  margin-top: var(--nexus-space-1);
  font-size: var(--nexus-fs-caption);
}

.nx-chat__approval-label {
  display: block;
  margin-top: var(--nexus-space-2);
  font-size: var(--nexus-fs-caption);
  opacity: 0.8;
}

/* Il riepilogo in parole (2026-09-15): testo normale, evidenziato appena
   quanto basta a dire "questo e' cio' che stai autorizzando". */
.nx-chat__approval-summary {
  margin: 4px 0 0;
  padding: var(--nexus-space-2) var(--nexus-space-3);
  border-left: 3px solid var(--nx-accent, currentColor);
  background: var(--nx-surface-sunken, transparent);
  border-radius: var(--nx-radius-input, 6px);
  font-size: var(--nexus-fs-body, 0.95rem);
  line-height: 1.4;
}

/* Il ripiego a campi: nome smorzato, valore pieno, una coppia per riga. */
.nx-chat__approval-fields {
  display: grid;
  grid-template-columns: max-content 1fr;
  gap: 2px var(--nexus-space-3);
  margin: 4px 0 0;
  padding: var(--nexus-space-2) var(--nexus-space-3);
  background: var(--nx-surface-sunken, transparent);
  border-radius: var(--nx-radius-input, 6px);
  font-size: var(--nexus-fs-caption);
}

.nx-chat__approval-fields dt {
  opacity: 0.7;
  font-family: var(--nx-font-mono, ui-monospace, monospace);
}

.nx-chat__approval-fields dd {
  margin: 0;
  overflow-wrap: anywhere;
}

/* Gli argomenti si leggono e si correggono: monospazio, perche' e' JSON, e
   nessun a capo automatico che nasconda una riga lunga. */
.nx-chat__approval-args {
  width: 100%;
  margin-top: 4px;
  padding: var(--nexus-space-2);
  border: 1px solid var(--nx-border);
  border-radius: var(--nx-radius-input, 6px);
  background: var(--nx-surface-sunken, transparent);
  color: var(--nx-text);
  font-family: var(--nx-font-mono, ui-monospace, monospace);
  font-size: var(--nexus-fs-caption);
  resize: vertical;
}

/* I due gruppi si separano: le approvazioni a sinistra, il rifiuto spinto
   dall'altra parte. Su schermo stretto la riga si spezza e il rifiuto scende
   sotto — che e' comunque una distanza, non un vicino di casa. */
.nx-chat__approval-buttons {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--nexus-space-2);
  margin-top: var(--nexus-space-3);
}

.nx-chat__approval-yes {
  display: flex;
  flex-wrap: wrap;
  gap: var(--nexus-space-2);
}

.nx-chat__approval-no {
  margin-inline-start: auto;
}

.nx-chat__approval-ok,
.nx-chat__approval-edit,
.nx-chat__approval-no {
  padding: 6px var(--nexus-space-3);
  border: 1px solid var(--nx-border);
  border-radius: var(--nx-radius-input, 6px);
  background: transparent;
  color: var(--nx-text);
  font-family: inherit;
  font-size: var(--nexus-fs-body, inherit);
  line-height: 1.35;
  cursor: pointer;
}

/* Un solo pulsante pieno, ed e' quello che si preme quasi sempre. Due pieni
   accanto non danno una gerarchia: danno due colori.

   La vernice e' quella PRIMARIA della suite — teal con inchiostro navy, come
   .nx-chat__send e .nx-btn-primary — non un verde suo. Il verde scuro che
   c'era prima era fuori dal sistema: in una pagina in cui ogni altro pulsante
   d'azione e' teal, un pulsante verde non dice "conferma", dice "vengo da
   un'altra applicazione". */
.nx-chat__approval-ok {
  border-color: transparent;
  background: var(--nx-teal);
  color: var(--nx-navy-deep);
  box-shadow: var(--nx-shadow-cta);
  font-weight: var(--nexus-fw-semibold, 600);
}

.nx-chat__approval-ok:hover { background: var(--nx-teal-hover); }

/* Approvare correggendo e' pur sempre approvare: stessa famiglia, meno peso —
   contorno teal, nessun riempimento. */
.nx-chat__approval-edit {
  border-color: color-mix(in srgb, var(--nx-teal) 60%, transparent);
  font-weight: var(--nexus-fw-semibold, 600);
}

.nx-chat__approval-edit:hover {
  background: color-mix(in srgb, var(--nx-teal) 14%, transparent);
  border-color: var(--nx-teal);
}

/* Il rifiuto NON e' rosso: non e' un errore ne' un pericolo, e' l'altra
   risposta legittima. Resta smorzato, e si accende solo quando ci si passa
   sopra — cosi' si trova senza attirare il dito. */
.nx-chat__approval-no {
  color: var(--nx-text-muted, var(--nx-text));
}

.nx-chat__approval-no:hover {
  border-color: color-mix(in srgb, var(--nx-danger-ink, #b3261e) 50%, transparent);
  color: var(--nx-danger-ink, #b3261e);
}

/* Sotto i 520 px i tre pulsanti a capo si accavallano: si prende tutta la
   larghezza, uno per riga, nell'ordine in cui si decide. Misurato su un
   telefono vero il 2026-09-04. */
@media (max-width: 520px) {
  .nx-chat__approval-buttons,
  .nx-chat__approval-yes {
    display: grid;
    gap: var(--nexus-space-2);
    width: 100%;
  }

  .nx-chat__approval-no {
    margin-inline-start: 0;
  }

  .nx-chat__approval-ok,
  .nx-chat__approval-edit,
  .nx-chat__approval-no {
    width: 100%;
    padding: 10px var(--nexus-space-3);
    text-align: center;
  }
}

.nx-chat__approval-note {
  margin: var(--nexus-space-2) 0 0;
  font-size: var(--nexus-fs-caption);
  color: var(--nx-text-faint);
}
