/* Governance compatta (stile Proposta 3), qui sopra i rami invece del
   cluster di chip sempre visibile della Proposta 2 */
.p4-gov-accordion {
  background: var(--lavender);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  margin: 0 auto 10px;
  padding: 12px 18px;
  max-width: 1020px;
}
.p4-gov-accordion summary { cursor: pointer; font-size: 0.86rem; color: var(--ink); font-weight: 600; text-align: left; }
.p4-gov-accordion .gov-accordion-body { margin-top: 12px; text-align: left; }
.p4-gov-accordion .gov-mini-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: 8px; margin-bottom: 10px; }
.p4-gov-accordion .gov-mini-card { background: var(--surface-card); border-radius: var(--radius-sm); padding: 8px 10px; font-size: 0.8rem; }
.p4-gov-accordion .gov-mini-role { display: block; font-size: 0.64rem; text-transform: uppercase; color: var(--coral); font-weight: 700; }
.p4-gov-accordion .gov-mini-name { display: block; font-weight: 600; }
.p4-gov-accordion .gov-mini-delega { display: block; font-size: 0.72rem; color: var(--steel); }
.p4-gov-accordion .gov-mini-organi { font-size: 0.8rem; margin: 8px 0 0; padding-left: 18px; }

/* Intestazione: titolo/sottotitolo a sinistra, ricerca ancorata in alto a
   destra, per recuperare spazio verticale sopra la riga delle Direzioni. */
.page-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 24px;
  text-align: left;
  margin-bottom: 10px;
}
.page-header-text { flex: 1 1 auto; min-width: 0; }
.page-header-text h1,
.page-header-text .subtitle { text-align: left; }
.page-header-text h1 {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  font-size: clamp(1.3rem, 2.4vw, 2.1rem);
  /* Serve una riga più alta della 1.08 di base: con overflow:hidden (che qui
     serve per i puntini di sospensione) una riga troppo stretta taglierebbe
     le code delle lettere, come la "g" di Organigramma e di degli. */
  line-height: 1.3;
  padding-bottom: 2px;
}
.page-header .p4-search { flex: 0 0 420px; margin: 4px 0 0; }

@media (max-width: 760px) {
  .page-header { flex-direction: column; align-items: stretch; }
  .page-header-text h1,
  .page-header-text .subtitle { text-align: center; }
  .page-header-text h1 { white-space: normal; font-size: clamp(1.5rem, 6vw, 2rem); }
  .page-header .p4-search { flex: 1 1 auto; margin: 8px auto 0; }
}

/* Ricerca globale: nome, ruolo, ufficio, Direzione o governance */
.p4-search {
  position: relative;
  max-width: 560px;
  margin: 0 auto 14px;
}
.p4-search input {
  width: 100%;
  padding: 11px 16px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--surface-card);
  color: var(--ink);
  font-size: 0.95rem;
  transition: box-shadow .3s var(--ease), border-color .3s var(--ease);
}
.p4-search input:focus {
  outline: none;
  border-color: var(--indigo-soft);
  box-shadow: 0 0 0 4px var(--lavender);
}
.p4-search-results {
  position: absolute;
  top: calc(100% + 8px);
  left: 0;
  right: 0;
  background: var(--surface-card);
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-lift);
  max-height: 360px;
  overflow-y: auto;
  z-index: 250;
  padding: 6px;
  text-align: left;
}
.p4-search-result {
  display: block;
  width: 100%;
  text-align: left;
  background: none;
  border: none;
  cursor: pointer;
  padding: 8px 10px;
  border-radius: var(--radius-sm);
  font: inherit;
  color: inherit;
}
.p4-search-result:hover, .p4-search-result.active { background: var(--lavender); }
.p4-search-result-label { display: block; font-weight: 600; font-size: 0.86rem; color: var(--ink); }
.p4-search-result-sub { display: block; font-size: 0.74rem; color: var(--steel); }

/* Chi regge piu' di una Direzione: il nome resta uno e le Direzioni diventano
   righe cliccabili sotto, una per riga (vedi renderResults() in popup.js).
   Il contenitore non e' piu' cliccabile di suo — quel che si sceglie e' la
   Direzione — quindi non si accende al passaggio del mouse; resta pero'
   evidenziato quando lo raggiungono le frecce, dove l'Invio apre la prima. */
.p4-search-result-multi { cursor: default; }
.p4-search-result-multi:hover { background: none; }
.p4-search-result-multi.active { background: var(--lavender); }
.p4-search-sedi { display: block; margin-top: 3px; }
.p4-search-sede {
  display: block;
  width: 100%;
  text-align: left;
  background: none;
  border: none;
  font: inherit;
  font-size: 0.74rem;
  color: var(--steel);
  cursor: pointer;
  padding: 3px 6px;
  border-radius: var(--radius-sm);
}
/* Il trattino davanti dice che sono voci di una stessa persona, non due
   risultati diversi rimasti attaccati. */
.p4-search-sede::before { content: '– '; }
.p4-search-sede:hover, .p4-search-sede:focus-visible {
  background: var(--lavender);
  color: var(--ink);
}
.p4-search-empty { padding: 10px; font-size: 0.85rem; color: var(--steel); text-align: left; }

/* Sotto i 480px la ricerca esce dal padding orizzontale di .page (20px per
   lato, vedi tree-base.css) e va a filo dei bordi dello schermo: su un
   telefono quei 40px sottratti sono piu' di un decimo della larghezza utile,
   e li perdono sia il campo sia l'elenco dei risultati, che lo segue da solo
   perche' e' posizionato rispetto a .p4-search.
   I margini negativi sovrascrivono il "margin: 8px auto 0" della media query
   dei 760px: stessa specificita', ma questa regola viene dopo. */
@media (max-width: 480px) {
  .page-header .p4-search {
    margin-left: -20px;
    margin-right: -20px;
  }
}

/* Righe di chi sta solo nell'anagrafica telefonica: si aprono anche loro, ma
   sulla scheda della persona e non su una casella, quindi restano staccate
   dagli altri risultati. Le distingue la barra a sinistra e il nome più
   chiaro: dicono che quel nome non è nella struttura disegnata, non che la
   riga sia inerte. */
.p4-search-result-esterno {
  border-left: 3px solid var(--line);
  border-radius: 0;
  padding-left: 10px;
  margin-left: 4px;
}
.p4-search-result-esterno .p4-search-result-label { color: var(--steel); }
/* Il ruolo di chi è fuori organigramma: un po' più marcato del resto del
   sottotitolo, che resta grigio chiaro. Solo peso e colore, niente corsivo né
   maiuscoletto — deve farsi notare quanto basta a leggerlo per primo, non
   diventare l'elemento più forte della riga (che è il nome). */
.p4-search-result-ruolo {
  font-weight: 600;
  color: var(--ink);
}

/* Bottone di chiusura del flyout di una struttura: esiste nel markup a ogni
   larghezza ma si vede solo su cellulare, dove il flyout non si chiude da solo
   uscendone col mouse (vedi la media query in fondo). */
.cascade-flyout-close { display: none; }

/* Il ruolo del vertice su una riga sua, sotto al nome, come gia' accade per
   le persone negli elenchi delle caselle. Sulla stessa riga del nome e del
   numero finiva schiacciato in fondo, e con nomi lunghi andava a capo da
   solo in un punto qualsiasi. flex-basis 100% e non un <br>: la riga resta
   un contenitore flex, che serve ad allineare nome, numero e contrassegno. */
.panel-vertice-person { flex-wrap: wrap; }
/* row-gap azzerato: gli 8px di .panel-vertice-person servono a distanziare
   nome, numero e contrassegno fra loro, ma applicati anche fra le due righe
   staccavano il ruolo dal nome a cui appartiene — con due persone di vertice
   non si capiva piu' quale ruolo fosse di chi. */
.panel-vertice-person { row-gap: 0; }
.panel-vertice-ruolo { flex: 0 0 100%; line-height: 1.25; }

/* Il contrassegno dentro al vertice di un popup e' uno <span>, e li'
   ".panel-vertice-person span" (tree-base.css) e' piu' specifico di
   ".cascade-flag": senza questa riga il badge prenderebbe corpo e colore del
   ruolo accanto e risulterebbe piu' grande che nelle caselle a cascata. I
   valori sono quelli di .cascade-flag, ripetuti solo per riprendersi la
   precedenza: i contrassegni devono essere tutti uguali. */
.panel-vertice-person .cascade-flag {
  font-size: 0.6rem;
  padding: 1px 8px;
}
.panel-vertice-person .cascade-flag-resp {
  color: var(--coral);
}

/* Evidenzia la casella trovata da un risultato di ricerca con un bordo
   rosso, così si distingue subito dal resto anche in un popup affollato. */
.cascade-box-flash { animation: p4-flash 7s ease; }
@keyframes p4-flash {
  0%, 85% { box-shadow: 0 0 0 3px var(--danger); }
  100% { box-shadow: none; }
}

/* Nel vertice di un popup la riga della persona e' larga quanto il pannello,
   e il bordo rosso correva fino al margine destro, lontanissimo dal nome che
   doveva indicare. Mentre lampeggia la riga si stringe sul proprio contenuto,
   cosi' il bordo finisce poco dopo il contrassegno "Resp.".
   Solo mentre lampeggia: e' la stessa riga che si accende al passaggio del
   mouse, e li' deve restare larga come tutte le altre. */
.panel-vertice .person-row.cascade-box-flash {
  width: fit-content;
  max-width: 100%;
}

/* Direttore Generale con le sue Aree (nucleo, .vertice-core) e il gruppo
   indipendente del Rettorato affiancati. .vertice-cluster può andare a
   capo: sulle risoluzioni strette dove non entrano entrambi, è il gruppo
   Rettorato (che non è un diretto riporto del Direttore, quindi può stare
   anche sotto senza confondere la gerarchia) a scendere su una riga
   propria, invece del nucleo Direttore+Aree che deve restare sempre
   unito. */
.vertice-cluster {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  margin: 2px auto 10px;
  /* Il column-gap ampio (90px) è la distanza fra il nucleo Direttore+Aree e
     il gruppo Rettorato: sono gli unici due figli, quindi vale solo fra
     loro. Sta qui e non come margine sul Rettorato perché il column-gap non
     si applica quando il gruppo va a capo — così sulle risoluzioni strette
     resta centrato invece di restare spostato a destra di 90px. */
  gap: 14px 90px;
}
.vertice-cluster .node-vertice { margin: 0; }
/* Nucleo Direttore Generale + Aree: non va MAI a capo di suo (le due Aree
   sono diretti riporti, spezzarle su righe diverse spezzerebbe la lettura
   della gerarchia). width:fit-content + margin:auto lo centra quando il
   contenuto ci sta; se eccede lo schermo, max-width:100% lo blocca al
   bordo e overflow-x:auto apre lo scorrimento orizzontale (barra nascosta,
   come .direzioni-riga più sotto) come ultima risorsa — mai irraggiungibile
   via scroll, a differenza di un flex centrato con contenuto in eccesso
   (il browser non permette uno scrollLeft negativo). */
.vertice-core {
  display: flex;
  align-items: center;
  justify-content: flex-start;
  flex-wrap: nowrap;
  width: fit-content;
  max-width: 100%;
  overflow-x: auto;
  padding-bottom: 2px;
  gap: 10px;
  scrollbar-width: none;
  -ms-overflow-style: none;
}
.vertice-core::-webkit-scrollbar { width: 0; height: 0; }
/* text-align:left: .page ha text-align:center, ereditato da qui in giù.
   I contenuti a display:flex (block-level, come .area-box-static) non ne
   risentono — riempiono comunque tutta la larghezza — ma un nodo
   inline-flex come .node-vertice (badge del Rettore) sì: senza questa
   riga finirebbe centrato nella colonna invece che allineato al bordo
   come le Aree, con un distacco dal resto del gruppo diverso dal previsto. */
.vertice-side { width: 240px; flex: 0 0 240px; text-align: left; }
/* Il badge del Rettore (.node-vertice) è largo quanto il suo contenuto
   (~175px), non 240px come le Aree: dentro un .vertice-side a larghezza
   fissa restava spazio vuoto prima della freccia, allontanando
   visivamente Rettore e Segreteria anche se il gap dichiarato era piccolo.
   width:auto lo fa aderire al contenuto, così la freccia (e la Segreteria)
   gli stanno subito accanto. */
.vertice-side-auto { width: auto; flex: 0 0 auto; }
/* Ramo di sinistra: Area programmazione e Consulta impilate, ciascuna con
   la propria riga [casella + freccia] — non un'unica freccia condivisa,
   perché sono due diretti riporti distinti del Direttore Generale.
   flex-direction:column qui sopra è sicuro: i figli diretti sono
   .vertice-branch-row (row, non .cascade-column), quindi non si ripete il
   problema del flex-basis di .cascade-column che si applicherebbe
   all'altezza invece che alla larghezza in un contenitore verticale. */
.vertice-branch {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.vertice-branch-row {
  display: flex;
  align-items: center;
  gap: 10px;
}
/* Rettore e Segreteria affiancati (non impilati) apposta: restano alti
   quanto il Direttore Generale invece di allungare la riga in verticale.
   Indipendenti da lui — nessuna freccia li collega — quindi un margine più
   ampio del gap interno (che è ~38px, la stessa distanza fra il Direttore
   Generale e le sue Aree) li stacca chiaramente dal blocco Direttore+Aree,
   invece di leggersi come una prosecuzione della stessa catena; la
   freccetta fra Rettore e Segreteria mostra solo la loro relazione.
   Quel distacco è il column-gap di .vertice-cluster, non un margine qui. */
.vertice-rettorato-row {
  display: flex;
  align-items: center;
  gap: 10px;
}
/* Il ramo dell'Area (Area + Uffici) impilato accanto al Direttore Generale.
   .cascade-column ha di suo "width:260px; flex:0 0 260px" (pensato per il
   popup di una Direzione, dove sta in una riga più larga): senza
   sovrascriverli qui, dentro un .vertice-side da 240px il contenuto
   sborda di 20px oltre il bordo, arrivando a toccare — o sovrapporre — la
   freccia accanto. width:100% lo riporta alla larghezza reale del
   contenitore invece che al valore fisso pensato per un altro contesto. */
.vertice-side .cascade-column {
  display: flex;
  flex-direction: column;
  gap: 6px;
  width: 100%;
  flex: 1 1 auto;
}

/* Accanto al Direttore Generale si vede solo la casella dell'Area, come per
   una qualsiasi Area di una Direzione: i suoi Uffici restano nel markup —
   il popup li legge da lì per elencarli tutti — ma non occupano spazio nella
   testata, che deve restare compatta per lasciare aria ai popup sotto. */
.vertice-side .cascade-column > .cascade-box + .cascade-box { display: none; }
.vertice-arrow {
  font-size: 1.3rem;
  line-height: 1;
  color: var(--indigo-soft);
  flex: 0 0 auto;
}

/* Consulta: stesso stile di una casella Area (colore, forma) ma statica —
   niente hover/click, quindi niente cursore a mano né sollevamento. */
.area-box-static {
  display: flex;
  align-items: center;
  border-radius: var(--radius-sm);
  padding: 7px 11px;
  background: var(--surface-card);
  border: 1px solid var(--indigo-soft);
  cursor: default;
}

@media (max-width: 760px) {
  /* Il gap qui separa solo il nucleo Direttore+Aree dal gruppo Rettorato
     (sono gli unici due figli): più largo del gap interno alle colonne
     (6px) per staccarli, come fa il column-gap di 90px in orizzontale —
     altrimenti impilati sembrano un'unica catena, con il Rettore che pare
     un riporto dell'Area di coordinamento sopra di lui. */
  .vertice-cluster { flex-direction: column; gap: 26px; }
  .vertice-core { flex-direction: column; width: auto; max-width: none; overflow-x: visible; gap: 6px; }
  .vertice-arrow { transform: rotate(90deg); }
  /* Impilate una sopra l'altra, Consulta e Area programmazione formavano
     una catena — quella in cima sembrava riportare a quella sotto invece
     che al Direttore, e solo una delle due gli restava adiacente. Qui
     restano affiancate anche in verticale: due colonne parallele sopra il
     Direttore, ciascuna con la propria freccia che scende su di lui, che è
     esattamente la relazione reale (due diretti riporti distinti). */
  .vertice-branch { flex-direction: row; align-items: stretch; gap: 8px; }
  /* Le frecce del ramo restano quelle generali, ruotate di +90deg: partono
     dal Direttore e puntano in alto verso le due caselle, lo stesso verso
     che hanno affiancate (dove il "<-" parte da lui e indica l'Area alla
     sua sinistra). */
  .vertice-side { width: min(320px, 90vw); flex: 0 0 auto; }
  .vertice-branch-row, .vertice-rettorato-row { flex-direction: column; }
  /* Le due colonne si dividono in parti uguali la stessa larghezza delle
     altre caselle: così il ramo resta stretto e raccolto in alto sopra il
     Direttore invece di allargare o allungare la testata. */
  .vertice-branch { width: min(320px, 90vw); }
  .vertice-branch-row { flex: 1 1 0; justify-content: space-between; gap: 2px; }
  /* Le due caselle vanno alte uguali: affiancate, una più bassa dell'altra
     leggerebbe come "meno importante", mentre sono due riporti pari grado.
     L'altezza la detta la più alta (align-items:stretch sul ramo) e la
     catena di flex:1 la propaga fino alla casella vera, che altrimenti
     resterebbe alta quanto il proprio testo. */
  .vertice-branch .vertice-side {
    width: 100%;
    flex: 1 1 auto;
    display: flex;
    flex-direction: column;
  }
  .vertice-branch .vertice-side > *,
  .vertice-branch .cascade-column > .cascade-box:first-child { flex: 1 1 auto; }
  /* Impilato, il badge del Rettore (inline-flex, largo quanto il testo)
     resterebbe a sinistra della sua colonna per via del text-align:left di
     .vertice-side — pensato per l'affiancamento orizzontale, dove serve ad
     allinearlo al bordo come le Aree. Qui sopra tutto è centrato in
     colonna, quindi va centrato anche lui. Solo .vertice-side-auto (il
     badge): sulle .vertice-side normali il text-align si erediterebbe
     dentro le caselle, centrandone nomi e responsabili. */
  .vertice-side-auto { text-align: center; }
}

/* Risoluzioni desktop più piccole (laptop 1280/1366px e simili): la
   ricerca fissa a 420px lasciava troppo poco spazio al titolo.
   Limitato a min-width:761px per non sovrapporsi mai al layout mobile
   impilato qui sopra (sotto i 761px comanda solo quello). */
@media (max-width: 1300px) and (min-width: 761px) {
  .page-header .p4-search { flex: 0 0 320px; }
  .page-header-text h1 { font-size: clamp(1.1rem, 2.1vw, 1.7rem); }
}
@media (max-width: 1080px) and (min-width: 761px) {
  .page-header .p4-search { flex: 0 0 260px; }
  .page-header-text h1 { font-size: clamp(0.98rem, 2vw, 1.4rem); }
}

/* Una sola riga, che scorre in orizzontale se le Direzioni non entrano
   tutte: nessuna resta mai nascosta, e su desktop/risoluzioni intermedie
   la riga non va mai a capo su più righe.
   NB: niente "justify-content: center" qui — con contenuto che eccede la
   larghezza disponibile, un flex centrato rende irraggiungibile via scroll
   la parte che sborda a sinistra (il browser non permette uno scrollLeft
   negativo). Con flex-start la riga parte sempre da sinistra e, se avanza
   spazio a destra, resta comunque bilanciata dal padding/margin della
   pagina attorno a #direzioni-row. */
.direzioni-riga {
  display: flex;
  flex-wrap: nowrap;
  justify-content: flex-start;
  gap: 8px;
  overflow-x: auto;
  padding-bottom: 6px;
  width: 100%;
  min-width: 0;
  /* La barra di scorrimento resta nascosta: lo scorrimento orizzontale
     continua a funzionare (trackpad, rotella, tastiera), ma la riga non
     mostra la barra sotto le Direzioni. */
  scrollbar-width: none;
  -ms-overflow-style: none;
}
.direzioni-riga::-webkit-scrollbar { width: 0; height: 0; }

/* Il bottone Direzione non spinge più nulla: apre un popup flottante */
#direzioni-row { margin-bottom: 6px; margin-top: 4px; }

/* Tutte le Direzioni della stessa dimensione: una sola riga finché ci
   stanno, altrimenti scorrimento orizzontale (mai vanno a capo su più
   righe su desktop/risoluzioni intermedie). */
.level-direzioni .node-direzione {
  flex: 1 1 0;
  width: auto;
  min-width: 124px;
  max-width: none;
  height: 108px;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 4px;
  padding: 10px 12px;
  overflow: hidden;
}
.level-direzioni .node-direzione .node-title {
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
  line-height: 1.18;
  font-size: 0.78rem;
}
.level-direzioni .node-direzione .node-sub {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 0.66rem;
}
/* "(ad interim)" sotto al nome del direttore, stesso carattere e stesso
   colore: nella casella e' l'unica cosa che distingue un incarico
   temporaneo, e in corsivo piu' chiaro sembrava una nota a margine invece
   che parte del nome. La riga puo' andare a capo solo qui: altrove il nome
   resta su una riga sola con i puntini di sospensione. */
.level-direzioni .node-direzione .node-sub:has(.node-sub-interim) {
  white-space: normal;
  line-height: 1.2;
}
.node-sub-interim { display: block; }

.level-direzioni .node-direzione .node-count {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 0.58rem;
}

/* Solo sotto i 900px (mobile) la riga smette di scorrere in orizzontale
   (poco scopribile col dito) e va a capo in una griglia compatta, invece
   di scorrere. Sopra i 900px (desktop e risoluzioni intermedie) resta
   sempre una riga sola scorrevole, vedi le regole base qui sopra. */
@media (max-width: 900px) {
  .direzioni-riga {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(130px, 1fr));
    overflow-x: visible;
  }
  .level-direzioni .node-direzione {
    min-width: 0;
    height: auto;
    min-height: 92px;
    padding: 10px 12px;
  }
  .level-direzioni .node-direzione .node-title { font-size: 0.8rem; -webkit-line-clamp: 3; }
  .level-direzioni .node-direzione .node-sub { font-size: 0.68rem; }
  .level-direzioni .node-direzione .node-count { font-size: 0.6rem; }
}
@media (max-width: 420px) {
  .direzioni-riga { grid-template-columns: 1fr; }
}

/* Fra 900px e 1400px le Direzioni non entrano tutte nella riga ma lo schermo
   non è ancora abbastanza stretto da passare alla griglia mobile: è la
   fascia in cui lo scorrimento orizzontale c'è ma non si vedrebbe. Qui la
   barra viene quindi mostrata, così si capisce che la riga continua oltre il
   bordo. Sopra i 1400px resta nascosta: le Direzioni ci stanno e la barra
   sarebbe solo rumore. */
@media (min-width: 901px) and (max-width: 1400px) {
  .direzioni-riga {
    scrollbar-width: thin;
    scrollbar-color: var(--indigo-soft) var(--lavender);
    -ms-overflow-style: auto;
    padding-bottom: 10px;
  }
  .direzioni-riga::-webkit-scrollbar { width: auto; height: 8px; }
  .direzioni-riga::-webkit-scrollbar-track {
    background: var(--lavender);
    border-radius: 20px;
  }
  .direzioni-riga::-webkit-scrollbar-thumb {
    background: var(--indigo-soft);
    border-radius: 20px;
  }
  .direzioni-riga::-webkit-scrollbar-thumb:hover { background: var(--indigo); }
}

.popup-panel {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 200;
  width: min(840px, 92vw);
  max-height: min(560px, 75vh);
  overflow-y: auto;
  text-align: left;
  background: var(--lavender);
  border: 1px solid var(--indigo-soft);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lift);
  padding: 18px 20px;
  opacity: 0;
  visibility: hidden;
  transform: translateY(6px);
  transition: opacity .22s var(--ease), transform .22s var(--ease), visibility 0s linear .22s;
}
.popup-panel.popup-open {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
  transition: opacity .22s var(--ease), transform .22s var(--ease), visibility 0s linear 0s;
}

/* Le colonne (Area + Uffici a cascata) hanno altezze diverse tra loro.
   Un layout a colonne CSS (masonry) le impacchetta in sequenza dall'alto,
   ma può spostare l'intestazione di un'Area a metà di una "colonna"
   invece di tenerla allineata in cima insieme alle altre. Con una riga
   flessibile che va a capo, invece, ogni colonna è un blocco verticale
   indipendente e tutte le intestazioni restano allineate in alto. */
.popup-columns {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  /* Row-gap più largo del column-gap: le colonne che vanno a capo restano
     ben distinte dalla riga sopra invece di sembrarne la prosecuzione. */
  gap: 26px 12px;
  margin-top: 14px;
}
.popup-columns .cascade-column {
  width: 260px;
  flex: 0 0 260px;
  display: flex;
  flex-direction: column;
  gap: 4px;
}

/* Spacer invisibile: forza le colonne successive a iniziare una riga nuova
   nel flex-wrap, così un gruppo (es. le Strutture-sigla di ogni
   Dipartimento) resta compatto invece di spezzarsi fra due righe. */
.cascade-row-break {
  flex-basis: 100%;
  width: 0;
  height: 0;
  margin: 0;
  padding: 0;
}

/* Quando la Direzione ha più di 3 colonne allo stesso livello (es. più
   Aree), il popup standard (720px) non basta a tenerle tutte sulla stessa
   riga: si allarga per farcele stare, entro il limite dello schermo. */
.popup-panel-wide {
  width: min(1180px, 94vw);
}

@media (max-width: 760px) {
  .popup-panel { width: 94vw; max-height: 88vh; }
  .popup-panel-wide { width: 94vw; }
}
@media (max-width: 480px) {
  .popup-panel { padding: 14px 14px; }
  .popup-columns .cascade-column {
    width: 100%;
    flex: 1 1 100%;
  }
}

/* --- Scheda della singola persona ------------------------------------- */

/* La riga persona è cliccabile ovunque compaia: elenco della casella,
   flyout laterale, vertice e staff diretto del popup di una Direzione. */
.person-row {
  cursor: pointer;
  border-radius: var(--radius-sm);
  transition: background .15s var(--ease);
}
.person-row:hover,
.person-row:focus-visible {
  background: var(--lavender);
}

.person-modal[hidden] { display: none; }
.person-modal {
  position: fixed;
  inset: 0;
  /* Sopra popup Direzione e flyout: la scheda si apre da lì e deve
     restarci sopra senza chiuderli. */
  z-index: 1200;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 5vh 4vw;
}
.person-modal-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(27, 58, 99, 0.38);
  backdrop-filter: blur(2px);
}
.person-modal-card {
  position: relative;
  /* 460 e non 420: con l'icona di copia accanto all'email, a 420px un
     indirizzo nome.cognome@uniroma3.it andava a capo spezzandosi sull'ultima
     lettera. Qui ci sta in una riga sola, e su schermi stretti il min()
     lascia comunque la card larga quanto la finestra. */
  width: min(460px, 100%);
  max-height: 90vh;
  overflow-y: auto;
  background: var(--surface-card);
  color: var(--ink);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lift);
  padding: 20px 22px 22px;
}
.person-modal-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 14px;
}
.person-modal-header h3 {
  margin: 0;
  font-family: var(--font-display);
  font-size: 1.15rem;
  line-height: 1.25;
}
.person-modal-role {
  margin: 4px 0 0;
  color: var(--steel);
  font-size: .85rem;
}
.person-modal-role[hidden] { display: none; }
.person-modal-close {
  flex: 0 0 auto;
  width: 30px;
  height: 30px;
  border: 1px solid var(--line);
  border-radius: 50%;
  background: transparent;
  color: var(--steel);
  font-size: 1.1rem;
  line-height: 1;
  cursor: pointer;
  transition: background .15s var(--ease), color .15s var(--ease);
}
.person-modal-close:hover {
  background: var(--lavender);
  color: var(--ink);
}

/* Etichetta e valore su due colonne: le etichette sono corte e regolari,
   i valori (email, indirizzi) possono andare a capo. */
.person-modal-fields {
  display: grid;
  grid-template-columns: auto 1fr;
  /* gap azzerato di proposito: la spaziatura fra etichetta e valore diventa
     padding delle celle, altrimenti la banda colorata delle righe alternate
     resterebbe interrotta nel mezzo. */
  gap: 0;
  margin: 0;
  border-top: 1px solid var(--line);
  padding-top: 10px;
  font-size: .9rem;
}
.person-modal-fields dt {
  color: var(--steel);
  font-size: .78rem;
  text-transform: uppercase;
  letter-spacing: .04em;
  padding: 8px 14px 8px 8px;
}
.person-modal-fields dd {
  margin: 0;
  overflow-wrap: anywhere;
  padding: 7px 8px 7px 0;
}
/* Righe alternate: la riga è la coppia dt+dd, quindi si colorano insieme
   l'etichetta dispari e il valore che la segue. Gli angoli arrotondati alle
   due estremità fanno leggere la banda come una riga sola invece che come
   due celle accostate. */
.person-modal-fields dt:nth-of-type(odd),
.person-modal-fields dt:nth-of-type(odd) + dd {
  background: var(--zebra-row);
}
.person-modal-fields dt:nth-of-type(odd) {
  border-radius: 6px 0 0 6px;
}
.person-modal-fields dt:nth-of-type(odd) + dd {
  border-radius: 0 6px 6px 0;
}
.person-modal-fields a {
  color: var(--indigo);
  text-decoration: none;
  border-bottom: 1px solid transparent;
}
.person-modal-fields a:hover { border-bottom-color: currentColor; }
/* Icona "copia" accanto al recapito: discreta finché non la si cerca, si
   accende al passaggio del mouse. inline-flex e non inline-block, così il
   glifo resta centrato qualunque sia l'altezza della riga. */
.person-modal-fields dd.person-modal-value-copiabile {
  display: flex;
  align-items: flex-start;
  gap: 6px;
}
/* Il valore prende lo spazio che serve e va a capo da solo; l'icona non si
   restringe mai e resta a fianco invece di essere spinta sotto. */
.person-modal-value-copiabile > a { min-width: 0; }
/* margin-top negativo: il bottone è più alto della riga di testo, e
   allineato in cima restava otticamente basso rispetto all'email. Così il
   glifo si legge sulla stessa linea del testo invece che sotto. */
.person-modal-value-copiabile > .person-modal-copy { flex: none; margin-top: -4px; }
.person-modal-copy {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  vertical-align: middle;
  padding: 3px;
  width: 25px;
  height: 25px;
  border: 1px solid transparent;
  border-radius: 6px;
  background: none;
  color: var(--steel);
  cursor: pointer;
  transition: color .15s, background-color .15s, border-color .15s;
}
.person-modal-copy:hover {
  color: var(--indigo);
  background: rgba(0, 0, 0, .04);
  border-color: var(--line);
}
.person-modal-copy:focus-visible {
  outline: 2px solid var(--indigo);
  outline-offset: 1px;
}
.person-modal-copy-done,
.person-modal-copy-done:hover {
  color: #1a7f45;
  background: none;
  border-color: transparent;
}
.person-modal-empty {
  margin: 0;
  color: var(--steel);
  font-size: .88rem;
}

@media (max-width: 480px) {
  .person-modal { padding: 0; align-items: flex-end; }
  .person-modal-card {
    width: 100%;
    max-height: 82vh;
    border-radius: var(--radius-lg) var(--radius-lg) 0 0;
  }
}

/* Telefono accanto al nome nei risultati di ricerca. Il .person-phone
   generale (tree-base.css) porta gia colore e peso attenuati; qui le ultime 4
   cifre restano in neretto ma dello stesso colore del resto del numero, come
   nella scheda della persona: il solo peso basta a farle risaltare. */
.p4-search-result-label .person-phone { font-size: 0.78rem; }
.p4-search-result-label .person-phone strong { font-weight: 700; }

/* --- Vista su cellulare -------------------------------------------------
   Tutto ciò che segue vale solo sotto i 760px: la vista da scrivania e le
   larghezze intermedie restano esattamente come sono. */
@media (max-width: 760px) {
  /* 16px esatti nel campo di ricerca, non 15,2. Sotto i 16 iOS ingrandisce
     da solo la pagina appena il campo prende il fuoco, e da lì in poi
     l'organigramma resta zoomato: chi cerca deve rimetterlo a posto a mano
     ogni volta. Non è una scelta tipografica, è una soglia del browser. */
  .p4-search input { font-size: 16px; }

  /* Velatura dietro il popup di una Direzione. Il pannello copre quasi tutto
     lo schermo ma lascia intravedere la pagina ai bordi, e si legge come una
     casella che galleggia sopra le altre invece che come il pannello che è;
     la velatura lo stacca e dice anche dove toccare per chiuderlo (il click
     fuori chiude già, vedi popup.js). Sta sotto il pannello (z-index 200) e
     sopra la pagina. Dove :has() non è supportato semplicemente non compare:
     si torna a com'era prima, senza rompere nulla. */
  #popups-container:has(.popup-open)::before {
    content: '';
    position: fixed;
    inset: 0;
    z-index: 199;
    background: rgba(20, 18, 38, 0.42);
  }

  /* Vertice del popup: numero di telefono e contrassegno "Resp." restano
     sulla riga del nome invece di scendere ciascuno sulla propria. Il ruolo
     continua ad andare a capo da solo, per il flex-basis 100% della regola
     base.

     Erano impilati perché su una riga sola si spezzavano a metà parola in tre
     colonnine strette. Non succede più perché a cedere è ora il solo nome:
     numero e contrassegno non vanno mai a capo internamente (white-space)
     né si lasciano comprimere (flex: 0 0 auto), mentre il nome con
     min-width: 0 può andare a capo fra una parola e l'altra invece di
     spingerli sotto di sé. */
  .panel-vertice-person {
    display: block;
    margin-bottom: 10px;
  }
  /* Fuori dal flex il flex-basis del ruolo non vale piu': la riga propria
     gliela da' display:block. */
  .panel-vertice-ruolo { display: block; }
  /* Nome, numero e contrassegno restano cosi' testo in flusso, separati
     dagli spazi che il markup gia' contiene: niente gap da reimpostare. Il
     nome, se lungo, va a capo fra una parola e l'altra e numero e
     contrassegno proseguono subito dopo l'ultima, invece di scendere su
     righe loro. Il white-space impedisce l'unico modo che avrebbero ancora
     di spezzarsi: al proprio interno, fra prefisso e ultime quattro cifre. */
  .panel-vertice-person .person-phone,
  .panel-vertice-person .cascade-flag {
    white-space: nowrap;
  }

  /* Le caselle delle Direzioni sono toccabili ma non lo sembrano: senza
     hover non c'è nulla che lo dica. Il chevron è l'unico segno che serve,
     e la reazione al tocco conferma che il dito ha preso. */
  .level-direzioni .node-direzione {
    position: relative;
    padding-right: 28px;
  }
  .level-direzioni .node-direzione::after {
    content: '';
    position: absolute;
    right: 13px;
    top: 50%;
    width: 7px;
    height: 7px;
    margin-top: -4px;
    border-right: 2px solid var(--indigo-soft);
    border-bottom: 2px solid var(--indigo-soft);
    transform: rotate(-45deg);
  }
  .level-direzioni .node-direzione:active { filter: brightness(0.96); }
  .level-direzioni .node-direzione[aria-expanded="true"]::after {
    border-color: var(--indigo);
    /* Aperta: il chevron gira in su, come una tendina che si è alzata. */
    transform: rotate(-135deg);
    margin-top: -1px;
  }

  /* Chiusura del flyout di una struttura, in alto a destra come il
     "Chiudi" del popup di una Direzione. Col mouse il flyout si chiude da
     solo uscendone; col dito no, e restava aperto finché non si toccava un
     punto vuoto della pagina — che dentro un popup pieno di caselle non è
     sempre facile da trovare. Il bottone è nel markup a ogni larghezza ma
     qui sopra è display:none, quindi le altre viste non cambiano. */
  .cascade-flyout-title {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
  }
  .cascade-flyout-close {
    display: inline-block;
    flex: none;
    background: none;
    border: 1px solid var(--line);
    border-radius: 999px;
    padding: 3px 11px;
    font: inherit;
    font-size: 0.74rem;
    font-weight: 400;
    color: var(--steel);
    cursor: pointer;
  }

  /* Righe persona dentro popup e flyout: con il dito servono qualche pixel
     in più di quelli che bastano al mouse. */
  .popup-panel .person-row:not(.panel-vertice-person),
  .flyout .person-row:not(.panel-vertice-person) {
    padding: 3px 6px;
    min-height: 34px;
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0 6px;
  }
}

@media (max-width: 480px) {
  /* Scheda persona su schermo stretto: etichetta sopra e valore sotto,
     invece che affiancati. Con due colonne l'etichetta più lunga
     ("CELLULARE BREVE") si prende metà larghezza e all'email non ne resta
     abbastanza: andava a capo in mezzo a una parola, "alberto.apruzzese@u /
     niroma3.it". A tutta riga ci sta.

     Le bande delle righe alternate restano una per coppia etichetta+valore,
     solo che ora si sviluppano in verticale: gli angoli arrotondati passano
     quindi da sinistra/destra a sopra/sotto. */
  .person-modal-fields { grid-template-columns: 1fr; }
  .person-modal-fields dt { padding: 7px 10px 0; }
  .person-modal-fields dd { padding: 1px 10px 8px; }
  .person-modal-fields dt:nth-of-type(odd) { border-radius: 6px 6px 0 0; }
  .person-modal-fields dt:nth-of-type(odd) + dd { border-radius: 0 0 6px 6px; }
}

@media (max-width: 760px) {
  /* Il conteggio delle persone va a capo sempre, in tutte le caselle.
     Prima seguiva lo spazio rimasto: dove nome e responsabile erano corti
     restava in fondo alla loro riga, dove erano lunghi scendeva sotto — e
     caselle affiancate finivano impaginate in due modi diversi, che e' la
     cosa che si nota per prima scorrendo un elenco.

     L'interruzione di riga la fa uno pseudo-elemento della testata, che nel
     flex e' un elemento come gli altri: largo tutta la riga e alto zero,
     occupa quel che resta e spinge il conteggio sotto. Serve perche' dare
     'flex-basis: 100%' al conteggio stesso lo allargherebbe da pastiglia a
     barra per tutta la larghezza. L'ordine e' esplicito su tutti e quattro,
     altrimenti lo pseudo-elemento — che nel documento viene per ultimo —
     finirebbe dopo il conteggio invece che prima. */
  .cascade-box-name { order: 0; }
  .cascade-box-resp { order: 1; }
  .cascade-box summary::after {
    content: '';
    order: 2;
    flex: 0 0 100%;
    height: 0;
  }
  .cascade-box-count { order: 3; }
}

@media (min-width: 761px) {
  /* Testata delle caselle: il nome della struttura si tiene una riga tutta
     sua, e sotto vanno insieme responsabile e conteggio.

     Prima si disponevano per lo spazio che avanzava, e dentro una colonna di
     250px avanzava sempre in modo diverso: nella stessa Direzione una casella
     aveva il responsabile a destra del nome, quella sotto ce l'aveva a capo, e
     una terza spezzava il nome su due righe tenendo il responsabile in alto.
     Tre impaginazioni diverse in una colonna sola, ed e' l'alternanza a
     saltare all'occhio scorrendo l'elenco, non la riga in piu'.

     Basta il nome a 'flex: 0 0 100%' per ottenerlo: prendendosi la riga
     intera manda gli altri due a capo da soli, senza pseudo-elementi. Su
     telefono resta il comportamento della vista stretta, dove il
     responsabile sta accanto al nome quando ci sta e il conteggio va sempre
     a capo. */
  .cascade-box-name { flex: 0 0 100%; }
}
