/**
 * Admin — layer applicativo sul Brand Kit installato.
 *
 * Il Brand Kit è tarato sulla comunicazione (controlli da 44px, respiro
 * ampio). Questo layer lo ri-densifica per un back-office usato tutto il
 * giorno su schede fino a 119 campi: controlli a 32px, scala tipografica
 * più stretta, gerarchia costruita con bordi invece che con ombre.
 *
 * Regole rispettate: nessun colore letterale (solo token --sv-*), il
 * polimorfismo del kit resta intatto, contrasti sui token AA del sistema.
 * Modello di profondità, valido in entrambe le polarità:
 *   canvas (--sv-bg-1) < card (--sv-surface-1) > controllo (--sv-bg-1)
 */

/* ═══════════════════════ 1. Scala applicativa ═══════════════════════ */

:root {
  /* densità dei controlli */
  --ds-h-control: 32px;      /* input, select, bottone md */
  --ds-h-control-sm: 26px;   /* bottoni compatti, chip */
  --ds-h-control-lg: 38px;   /* azione primaria di pagina */
  --ds-h-row: 34px;          /* riga di tabella */
  --ds-h-nav: 28px;          /* voce di menu */
  --ds-h-topbar: 48px;

  /* geometrie */
  --ds-sidebar-w: 236px;
  --ds-pad-x: 10px;          /* padding orizzontale dei controlli */
  --ds-gap-field: 10px;      /* gap fra campi nella griglia */
  --ds-gap-row: 10px;        /* gap fra righe di campi */
  --ds-pad-card: 14px;
  /* Il ritmo dell'Admin è suo — un pannello denso non respira come la pagina
     di un sito — ma si comprime col moltiplicatore di banda del kit invece
     che con una soglia nostra: --sv-gap-k vale 1 su desktop, .8 su tavoletta,
     .62 sul telefono. Così la misura resta scritta una volta sola e non c'è
     nessuna @media a ripeterla. */
  --ds-pad-content-x: calc(20px * var(--sv-gap-k, 1));
  --ds-pad-content: calc(16px * var(--sv-gap-k, 1)) var(--ds-pad-content-x);

  /* tipografia applicativa.
     Le etichette sono 12px/16px e non 11.5px/14px: su 30 righe la
     differenza d'ingombro è 60px in tutto, mentre una size frazionaria
     arrotonda diversamente fra motori e livelli di zoom e disallinea le
     baseline dei campi affiancati. */
  --ds-t-title: 600 17px/24px var(--sv-font-ui);
  --ds-t-section: 700 11px/16px var(--sv-font-mono);
  --ds-t-label: 500 12px/16px var(--sv-font-ui);
  --ds-t-body: 400 13px/20px var(--sv-font-ui);
  --ds-t-meta: 400 12px/16px var(--sv-font-ui);
  --ds-t-mono: 400 12px/16px var(--sv-font-mono);
  --ds-t-micro: 700 10px/16px var(--sv-font-mono);

  /* ---- Filetti: tre pesi, tre lavori distinti ----
     Contrasti misurati NEL DOM su tutte e 10 le palette del Brand Kit 8.1.2
     (5 kit × 2 polarità), leggendo il pixel reso invece del nome del token:
     le derivazioni di kits.css sono color-mix in oklab, e i numeri che
     getComputedStyle serializza sono coordinate oklab — leggerli come rgb
     dà cifre che sembrano contrasti e non lo sono.
     Il caso peggiore è smeraldo/chiaro su ogni riga. Lo strumento che le
     rimisura è `scripts/contrasti-admin.mjs`: va rieseguito a ogni
     aggiornamento del brand book, perché il peggiore può spostarsi. */
  --ds-line-hair: var(--sv-line);              /* 1.45 sul canvas — ritmo, righe di tabella */
  --ds-line-structure: var(--sv-line-strong);  /* 2.20 sul canvas — struttura, bordi di card */
  /* WCAG 1.4.11 chiede 3:1 sul confine di un componente. Sulla card, dove il
     confine di un controllo cade davvero, --sv-line si ferma a 1.31 e
     --sv-line-strong a 1.99: entrambi falliscono. Sotto il 54% non si arriva
     a 3:1 su nessuna palette; al 58% il minimo misurato sulla 8.1.2 è 4.26. */
  --ds-line-control: color-mix(in oklab, var(--sv-bg-1), var(--sv-text-1) 58%);

  /* ---- Inchiostri di feedback ----
     I token --sv-ok/warn/err/info sono tarati per il RIEMPIMENTO: come
     inchiostro su superficie non reggono AA. Qui si estende ai feedback la
     "regola dei due usi" del brand, con la stessa quota del 30% di
     --sv-accent-1-text: sulla 8.1.2 il minimo è 6.50 e il peggiore resta
     `ok` (purple/chiaro). Tutti e quattro passano AA su tutte e 10. */
  --ds-ok-text: color-mix(in oklab, var(--sv-ok), var(--sv-text-1) 30%);
  --ds-warn-text: color-mix(in oklab, var(--sv-warn), var(--sv-text-1) 30%);
  --ds-err-text: color-mix(in oklab, var(--sv-err), var(--sv-text-1) 30%);
  --ds-info-text: color-mix(in oklab, var(--sv-info), var(--sv-text-1) 30%);

  /* ---- Focus ----
     --sv-focus-ring del brand è l'accento all'80%, e a quella quota non
     regge 3:1 su tutte le palette. Qui l'anello è ad accento pieno e l'alone
     interno da 2px in --sv-bg-1 lo isola dal piano sottostante, così il
     contrasto si misura sempre contro la carta: sulla 8.1.2 il minimo è 3.53
     (pastelli/chiaro), sopra il 3:1 che WCAG 1.4.11 chiede. È il margine più
     sottile dell'intero layer — se un kit nuovo abbassa l'accento in luce
     chiara, è la prima riga che salta. */
  --ds-focus-ring: 0 0 0 2px var(--sv-bg-1), 0 0 0 4px var(--sv-accent-1);
}

/* ═══════════════════════ 2. Reset e base ═══════════════════════ */

html, body { margin: 0; padding: 0; }

/* il kit non dichiara box-sizing globale: senza questo i bottoni misurano
   2px più degli input e le righe non si allineano */
.ds-body, .ds-body *, .ds-body *::before, .ds-body *::after { box-sizing: border-box; }

.ds-body {
  min-height: 100vh;
  background: var(--sv-bg-1);
  color: var(--sv-text-1);
  font: var(--ds-t-body);
  -webkit-font-smoothing: antialiased;
}

/* Un link nel testo corrente.
   Né il kit né questo layer dichiaravano niente per una <a> senza classe, e
   il ripiego era il blu di default del browser: l'unico colore dell'intera
   interfaccia a non appartenere a nessun clima, e l'unico che resta identico
   quando tutto il resto si tinge. Non è una svista da due punti — è la
   ricaduta, quindi vale per ogni link che qualcuno scriverà d'ora in poi
   dentro una nota, un avviso o una riga di aiuto.
   L'inchiostro è quello d'accento nella versione da TESTO: il token pieno è
   tarato per il riempimento e come inchiostro non è garantito AA. */
.ds-content a:not([class]) {
  color: var(--sv-accent-1-text);
  text-decoration: underline;
  text-underline-offset: 2px;
}
.ds-content a:not([class]):hover { color: var(--sv-text-1); }

.ds-body *:focus-visible {
  outline: none;
  box-shadow: var(--ds-focus-ring);
  /* senza questo l'anello finisce sotto la cella o il campo adiacente */
  position: relative;
  z-index: 1;
}

/* ogni contenitore che scorre rasa l'anello degli elementi a filo bordo */
.ds-nav, .ds-table-wrap, .ds-sectionnav, .ds-settings-nav { scroll-padding: 2px; }

.ds-skip {
  position: absolute;
  left: 8px;
  top: -100px;
  z-index: var(--sv-z-modal);
  padding: 0 12px;
  height: var(--ds-h-control);
  display: inline-flex;
  align-items: center;
  background: var(--sv-accent-1);
  color: var(--sv-text-onaccent);
  border-radius: var(--sv-r1);
  text-decoration: none;
  font: 500 13px/1 var(--sv-font-ui);
}
.ds-skip:focus { top: 8px; }
.ds-content:focus { outline: none; }

.ds-shell { display: flex; min-height: 100vh; }

/* ═══════════════════════ 3. Controlli ═══════════════════════ */
/* .sv-* mantenute per le viste che già le usano, ri-densificate qui. */

.ds-input,
.ds-body .sv-input,
.ds-body .sv-select,
.ds-body select,
.ds-body input[type="text"],
.ds-body input[type="email"],
.ds-body input[type="url"],
.ds-body input[type="tel"],
.ds-body input[type="number"],
.ds-body input[type="password"],
.ds-body input[type="search"],
.ds-body input[type="date"],
.ds-body input[type="datetime-local"],
.ds-body input[type="file"] {
  height: var(--ds-h-control);
  padding: 0 var(--ds-pad-x);
  font: var(--ds-t-body);
  color: var(--sv-text-1);
  background: var(--sv-bg-1);
  border: 1px solid var(--ds-line-control);
  border-radius: var(--sv-r1);
  width: 100%;
  box-sizing: border-box;
  transition: border-color var(--sv-dur-2) var(--sv-ease);
}

.ds-body textarea,
.ds-body .sv-textarea,
.ds-textarea {
  height: auto;
  min-height: 64px;
  padding: 6px var(--ds-pad-x);
  font: var(--ds-t-body);
  color: var(--sv-text-1);
  background: var(--sv-bg-1);
  border: 1px solid var(--ds-line-control);
  border-radius: var(--sv-r1);
  width: 100%;
  box-sizing: border-box;
  resize: vertical;
}

/* l'altezza deve venire dall'attributo size (calcolato sul numero di
   opzioni): una min-height fissa reintrodurrebbe i box vuoti alti */
.ds-body select[multiple] { height: auto; min-height: 0; padding: 3px 4px; }
.ds-body select[multiple]:disabled { opacity: .55; }
.ds-body select[multiple] option { padding: 2px 6px; border-radius: var(--sv-r1); }

.ds-body .sv-input:hover,
.ds-body textarea:hover,
.ds-body select:hover { border-color: var(--sv-text-2); }

.ds-body .sv-input:focus,
.ds-body textarea:focus,
.ds-body select:focus,
.ds-body input:focus { border-color: var(--sv-accent-1); outline: none; }

.ds-body .sv-input:focus-visible,
.ds-body textarea:focus-visible,
.ds-body select:focus-visible,
.ds-body input:focus-visible {
  border-color: var(--sv-accent-1);
  box-shadow: var(--ds-focus-ring);
  outline: none;
}

.ds-body input[readonly],
.ds-body textarea[readonly],
.ds-body .sv-input[readonly] {
  /* il read-only non deve emergere: perde la scatola invece di
     guadagnare luminosità. In tema scuro un riempimento più chiaro legge
     come "a fuoco", e attirava l'occhio proprio sui due campi che
     l'operatore non può toccare. */
  background: transparent;
  border-color: transparent;
  border-bottom: 1px dashed var(--ds-line-control);
  border-radius: 0;
  padding-left: 0;
  color: var(--sv-text-2);
  cursor: default;
}

.ds-body input::placeholder,
.ds-body textarea::placeholder { color: var(--sv-text-3); }

/* Il bottone interno del file input lo disegna il browser e resta fuori
   scala: qui torna alle misure e ai token del sistema. */
.ds-body input[type="file"] { padding: 0 0 0 0; line-height: calc(var(--ds-h-control) - 2px); }
.ds-body input[type="file"]::file-selector-button {
  height: calc(var(--ds-h-control) - 2px);
  margin-right: 10px;
  padding: 0 12px;
  border: 0;
  border-right: 1px solid var(--ds-line-control);
  background: var(--sv-surface-2);
  color: var(--sv-text-1);
  font: 500 13px/1 var(--sv-font-ui);
  cursor: pointer;
}
.ds-body input[type="file"]::file-selector-button:hover { background: var(--sv-surface-3); }

/* ---- bottoni ---- */

.ds-btn,
.ds-body .sv-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  height: var(--ds-h-control);
  padding: 0 12px;
  font: 500 13px/1 var(--sv-font-ui);
  border-radius: var(--sv-r1);
  border: 1px solid transparent;
  cursor: pointer;
  white-space: nowrap;
  text-decoration: none;
  box-sizing: border-box;
  transition: background-color var(--sv-dur-2) var(--sv-ease),
              border-color var(--sv-dur-2) var(--sv-ease),
              color var(--sv-dur-2) var(--sv-ease);
  /* default: azione primaria */
  background: var(--sv-accent-1);
  color: var(--sv-text-onaccent);
}

.ds-btn:hover,
.ds-body .sv-btn:hover { background: var(--sv-accent-1-hover); }
.ds-btn:active,
.ds-body .sv-btn:active { background: var(--sv-accent-1-active); }

.ds-btn--secondary,
.ds-body .sv-btn--secondary {
  background: var(--sv-surface-2);
  color: var(--sv-text-1);
  border-color: var(--ds-line-control);
}
.ds-btn--secondary:hover,
.ds-body .sv-btn--secondary:hover { background: var(--sv-surface-3); }

.ds-btn--quiet,
.ds-body .sv-btn--ghost {
  background: transparent;
  color: var(--sv-text-2);
  border-color: transparent;
}
.ds-btn--quiet:hover,
.ds-body .sv-btn--ghost:hover { background: var(--sv-surface-2); color: var(--sv-text-1); }

/* I token di feedback sono tarati per il RIEMPIMENTO: usati come inchiostro
   su superficie non hanno un token dedicato e non sono garantiti AA.
   Qui l'errore sta su tinta con inchiostro di testo, e diventa pieno al hover. */
.ds-btn--danger,
.ds-body .sv-btn--danger {
  background: var(--sv-err-tint);
  color: var(--sv-text-1);
  border-color: var(--sv-err);
}
.ds-btn--danger:hover,
.ds-body .sv-btn--danger:hover { background: var(--sv-err); color: var(--sv-text-on-err); }

.ds-btn--sm,
.ds-body .sv-btn--sm { height: var(--ds-h-control-sm); padding: 0 9px; font-size: 12px; }
.ds-btn--lg { height: var(--ds-h-control-lg); padding: 0 18px; font-size: 14px; }
.ds-btn--icon { width: var(--ds-h-control); padding: 0; font-size: 15px; }

.ds-btn[disabled], .ds-btn.is-disabled,
.ds-body .sv-btn[disabled] { opacity: .38; pointer-events: none; }

/* ---- etichette e campi ---- */

.ds-field, .ds-body .sv-field {
  display: flex;
  flex-direction: column;
  gap: 3px;
  min-width: 0;
}

.ds-label,
.ds-body .sv-field__label,
.ds-body .sv-label {
  font: var(--ds-t-label);
  letter-spacing: .01em;
  text-transform: none;      /* 119 etichette in MAIUSCOLO sono illeggibili */
  color: var(--sv-text-2);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.ds-hint,
.ds-body .sv-field__hint,
.ds-body .sv-hint {
  font: var(--ds-t-meta);
  color: var(--sv-text-3);
}

/* Il nome macchina sotto un campo (chiave di setting, nome di colonna) è
   informazione di secondo livello: se lo si compone con lo stesso peso
   dell'etichetta, su venti righe la pagina diventa due colonne di testo
   equivalente e non si capisce più quale delle due nomina il campo. */
.ds-body code {
  font: 400 11px/16px var(--sv-font-mono);
  letter-spacing: 0;
  color: var(--sv-text-3);
}
.ds-hint code { color: inherit; }
.ds-body .ds-code { font-size: 12px; color: var(--sv-text-2); }

.ds-body input[type="checkbox"] {
  width: 16px; height: 16px; margin: 0;
  accent-color: var(--sv-accent-1);
  cursor: pointer;
}

/* ---- avvisi ---- */

.ds-alert, .ds-body .sv-alert {
  padding: 8px 12px;
  border-radius: var(--sv-r1);
  font: var(--ds-t-body);
  border: 1px solid var(--ds-line-structure);
  border-left-width: 3px;
  background: var(--sv-surface-1);
  color: var(--sv-text-1);
}
.ds-alert--ok, .ds-body .sv-alert--ok { background: var(--sv-ok-tint); border-color: var(--sv-ok); }
.ds-alert--err, .ds-body .sv-alert--err { background: var(--sv-err-tint); border-color: var(--sv-err); }
.ds-alert--warn, .ds-body .sv-alert--warn { background: var(--sv-warn-tint); border-color: var(--sv-warn); }
.ds-alert__list { margin: 0; padding-left: 18px; }

/* Il colore non è mai l'unico veicolo (WCAG 1.4.1): l'avviso ha tinta,
   filetto laterale e marcatore testuale. */
.ds-alert::before {
  font: var(--ds-t-micro);
  letter-spacing: .12em;
  margin-right: 8px;
}
.ds-alert--ok::before { content: 'OK'; color: var(--ds-ok-text); }
.ds-alert--err::before { content: 'ERRORE'; color: var(--ds-err-text); }
.ds-alert--warn::before { content: 'ATTENZIONE'; color: var(--ds-warn-text); }

/* ---- stato di errore di un campo ---- */

.ds-body [aria-invalid="true"],
.ds-body .ds-input.is-invalid { border-color: var(--sv-err); border-width: 2px; }

.ds-field__error {
  font: var(--ds-t-meta);
  color: var(--ds-err-text);
  display: flex;
  gap: 4px;
  align-items: baseline;
}
.ds-field__error::before { content: '!'; font: var(--ds-t-micro); }

/* ---- badge di stato ---- */

/* Il badge porta il RIEMPIMENTO di tinta e l'INCHIOSTRO dedicato: i token
   --sv-ok/warn/err/info come testo su tinta stanno fra 3.66 e 4.18, sotto
   AA. Con --ds-*-text il minimo misurato è 5.45. */
.ds-badge {
  display: inline-flex;
  align-items: center;
  height: 20px;
  padding: 0 7px;
  border-radius: var(--sv-r-full);
  font: var(--ds-t-micro);
  letter-spacing: .1em;
  text-transform: uppercase;
  white-space: nowrap;
  background: var(--sv-surface-2);
  color: var(--sv-text-3);
}
.ds-badge--ok { background: var(--sv-ok-tint); color: var(--ds-ok-text); }
.ds-badge--warn { background: var(--sv-warn-tint); color: var(--ds-warn-text); }
.ds-badge--err { background: var(--sv-err-tint); color: var(--ds-err-text); }
.ds-badge--info { background: var(--sv-info-tint); color: var(--ds-info-text); }
/* il badge d'accento va su surface-2 (4.84) e non su accent-1-tint sopra
   surface-1, dove l'inchiostro d'accento scende a 4.26 */
.ds-badge--accent { background: var(--sv-surface-2); color: var(--sv-accent-1-text); }

/* Changelog: l'etichetta di tipo tiene la sua colonna, così l'occhio
   scorre i colori in verticale invece di rileggere ogni riga. */
.ds-changelog { list-style: none; margin: 0; padding: 0; display: grid; gap: 10px; }
.ds-changelog__item {
  display: grid;
  /* L'interruttore del kit al posto di una soglia nostra: su desktop e
     tavoletta vale la ricaduta scritta qui — etichetta e testo affiancati —
     e sul telefono --sv-g2 la riduce a una colonna sola. */
  grid-template-columns: var(--sv-g2, auto 1fr);
  gap: 10px;
  align-items: start;
}
.ds-changelog__type { min-width: 84px; justify-content: center; margin-top: 2px; }
.ds-changelog__text { display: flex; flex-direction: column; gap: 2px; }

.ds-btn-group { display: flex; gap: 6px; flex-wrap: wrap; align-items: center; }
.ds-table .ds-btn-group { flex-wrap: nowrap; }

/* Un numero breve dentro una cella di tabella (il tetto per client). Senza
   una larghezza propria eredita i 60ch del campo normale e allarga la
   colonna a dismisura per contenere due cifre. */
/* La fascia dei due mondi (v.7.5.0): la prima cosa che si vede, in ogni
   pagina. A righe diagonali di proposito — il colore da solo lo si smette
   di notare dopo mezz'ora, una trama no, ed è esattamente il caso in cui
   assuefarsi costa caro: chi dimentica di essere in test crede che il
   sistema abbia perso i dati. */
.ds-realm-banner {
  position: sticky; top: 0; z-index: 30;
  padding: 8px 16px;
  font: var(--ds-t-meta);
  color: var(--ds-warn-text);
  background: var(--sv-warn-tint);
  background-image: repeating-linear-gradient(
    135deg,
    transparent 0 10px,
    rgba(0, 0, 0, .05) 10px 20px
  );
  border-bottom: 2px solid var(--sv-warn, currentColor);
  display: flex; gap: 10px; flex-wrap: wrap; align-items: baseline;
}
.ds-realm-banner a { text-decoration: underline; margin-left: auto; }

.ds-field--num { width: 8ch; flex: 0 0 auto; }
.ds-body .ds-field--num > .ds-input { width: 100%; max-width: none; padding-inline: 6px; }

.ds-code {
  font: var(--ds-t-mono);
  color: var(--sv-text-2);
  background: var(--sv-surface-2);
  padding: 1px 5px;
  border-radius: var(--sv-r1);
}

/* ═══════════════════════ 4. Sidebar ═══════════════════════ */

.ds-sidebar {
  width: var(--ds-sidebar-w);
  flex: none;
  display: flex;
  flex-direction: column;
  background: var(--sv-surface-1);
  border-right: 1px solid var(--ds-line-structure);
  position: sticky;
  top: 0;
  height: 100vh;
  box-sizing: border-box;
  /* La sidebar è un contesto di impilamento: il pannello dell'aspetto,
     per quanto alto sia il suo z-index, non può uscire da qui. Con lo
     stesso z-index della topbar e dell'indice di sezione perdeva il
     pareggio per ordine nel DOM e si faceva coprire le prime due righe.
     Le due fasce non si sovrappongono mai orizzontalmente alla sidebar,
     quindi alzarla non nasconde nulla. */
  z-index: calc(var(--sv-z-sticky) + 2);
}

.ds-sidebar__head {
  height: var(--ds-h-topbar);
  flex: none;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 0 10px 0 14px;
  border-bottom: 1px solid var(--ds-line-structure);
}

/* Il lockup porta la sua geometria: qui si dichiara solo l'altezza, e
   tutto il resto (marchio, scritta, riga di prodotto) la segue. */
/* `color: inherit` non è cosmesi: un <a> senza colore dichiarato tiene il blu
   di default del browser, che è l'unico valore in tutta l'interfaccia a non
   appartenere a nessun clima. Oggi non si vede perché ogni discendente del
   lockup dichiara il proprio inchiostro — ma è una trappola che scatta al
   primo testo aggiunto qui dentro, e il test del kit («cambia data-kit: se
   qualcosa non cambia, non appartiene al sistema») la trova subito. */
.ds-brand { --sv-lockup-h: 30px; color: inherit; text-decoration: none; min-width: 0; }
.ds-brand .sv-lockup__prodotto { letter-spacing: .16em; }

.ds-nav {
  flex: 1;
  overflow-y: auto;
  padding: 8px;
  display: flex;
  flex-direction: column;
  gap: 1px;
}
.ds-nav::-webkit-scrollbar { width: 8px; }
.ds-nav::-webkit-scrollbar-thumb { background: var(--sv-line-strong); border-radius: var(--sv-r-full); }

.ds-nav__link {
  display: flex;
  align-items: center;
  height: var(--ds-h-nav);
  padding: 0 8px 0 10px;
  border-radius: var(--sv-r1);
  color: var(--sv-text-2);
  text-decoration: none;
  font: 400 13px/1 var(--sv-font-ui);
  border-left: 2px solid transparent;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.ds-nav__link:hover { background: var(--sv-surface-2); color: var(--sv-text-1); }
/* L'inchiostro dell'accento sulla tinta scende sotto AA su Pop (4.23):
   lo stato attivo è comunicato da tinta + barra + peso, il testo resta
   l'inchiostro primario. Misurato su 6 kit × 3 luci. */
.ds-nav__link.is-active {
  background: var(--sv-accent-1-tint);
  color: var(--sv-text-1);
  border-left-color: var(--sv-accent-1);
  font-weight: 500;
}

.ds-nav__group { margin-top: 12px; }
.ds-nav__group:first-child { margin-top: 0; }
.ds-nav__heading {
  display: flex;
  align-items: center;
  height: 24px;
  padding: 0 8px;
  font: var(--ds-t-section);
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--sv-text-2);
  cursor: pointer;
  list-style: none;
  user-select: none;
  border-radius: var(--sv-r1);
}
.ds-nav__heading::-webkit-details-marker { display: none; }
.ds-nav__heading::after {
  content: '';
  margin-left: auto;
  width: 0; height: 0;
  border-left: 4px solid currentColor;
  border-top: 3px solid transparent;
  border-bottom: 3px solid transparent;
  opacity: .6;
  transition: transform var(--sv-dur-2) var(--sv-ease);
}
.ds-nav__group[open] > .ds-nav__heading::after { transform: rotate(90deg); }
.ds-nav__heading:hover { color: var(--sv-text-1); background: var(--sv-surface-2); }
/* il filetto verticale rende leggibile a colpo d'occhio dove inizia e
   dove finisce un gruppo aperto: senza, dieci righe mono tutte uguali */
.ds-nav__items {
  display: flex;
  flex-direction: column;
  gap: 1px;
  padding-top: 2px;
  margin-left: 11px;
  padding-left: 7px;
  border-left: 1px solid var(--ds-line-hair);
}

/* Footerino: tre fasce in quest'ordine — dove si può andare, chi si è,
   cos'è questo. I filetti separano le fasce, non le singole voci: sono
   le fasce a dare l'ordine, e sottolineare ogni riga lo toglierebbe. */
/* Voce di PRIMO LIVELLO che non apre un gruppo: porta la stessa tipografia
   della label di sezione. Il primo livello si legge tutto allo stesso modo,
   e ciò che si apre lo dice il triangolo — non il corpo del carattere. */
.ds-nav__link--section {
  font: var(--ds-t-section);
  letter-spacing: .14em;
  text-transform: uppercase;
}

.ds-sidebar__foot {
  flex: none;
  border-top: 1px solid var(--ds-line-structure);
  padding: 8px 10px;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 4px;
}
/* Le tre voci del piede sono centrate: è una colonna stretta, e allineare a
   sinistra un elenco di tre righe disomogenee lo faceva sembrare un menu
   interrotto a metà. */
.ds-nav__link--foot { justify-content: center; }
.ds-sidebar__foot .ds-user {
  text-align: center;
  padding: 2px 8px;
}
/* Data e ora del sistema (v.6.2.0): stato di chi guarda, come l'email —
   stessa fascia, stesso tono. Le cifre tabulari tengono ferma la larghezza
   mentre i secondi scorrono; con il tempo alterato prende la tinta di
   avviso della spia in topbar: è una condizione, non un'azione. */
.ds-sidebar__foot .ds-clock {
  display: block;
  text-align: center;
  padding: 2px 8px;
  font: var(--ds-t-mono);
  font-variant-numeric: tabular-nums;
  color: var(--sv-text-3);
  white-space: nowrap;
}
.ds-sidebar__foot .ds-clock.is-altered { color: var(--ds-warn-text); }
/* La riga di chiusura: versione e uscita sulla stessa linea. */
.ds-sidebar__foot-row {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  margin-top: 4px;
  padding-top: 8px;
  border-top: 1px solid var(--ds-line-structure);
}
.ds-sidebar__foot-row .ds-version { padding: 0; }
.ds-user {
  font: var(--ds-t-meta);
  color: var(--sv-text-3);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ═══════════════════════ 5. Selettore kit + luce ═══════════════════════ */

.ds-appearance { position: relative; flex: none; }

.ds-appearance__trigger {
  width: 26px; height: 26px;
  display: grid;
  place-items: center;
  background: transparent;
  border: 1px solid var(--ds-line-control);
  border-radius: var(--sv-r-full);
  cursor: pointer;
  padding: 0;
}
.ds-appearance__trigger:hover { border-color: var(--sv-text-2); background: var(--sv-surface-2); }

/* pastiglia bicroma: legge gli accenti del kit in cui si trova */
.ds-kit-dot {
  width: 12px; height: 12px;
  border-radius: var(--sv-r-full);
  background: linear-gradient(135deg, var(--sv-accent-1) 0 50%, var(--sv-accent-2) 50% 100%);
  display: block;
}

.ds-appearance__panel {
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  z-index: var(--sv-z-overlay);
  width: 210px;
  padding: 10px;
  background: var(--sv-surface-1);
  border: 1px solid var(--ds-line-structure);
  border-radius: var(--sv-r2);
  box-shadow: var(--sv-e3);
}
.ds-appearance__panel[hidden] { display: none; }
.ds-appearance__label {
  font: var(--ds-t-section);
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--sv-text-3);
  margin: 0 0 6px;
}
.ds-appearance__kits { display: flex; flex-direction: column; gap: 1px; margin-bottom: 12px; }

.ds-kit-swatch {
  display: flex;
  align-items: center;
  gap: 8px;
  height: 26px;
  padding: 0 6px;
  background: transparent;
  border: none;
  border-radius: var(--sv-r1);
  cursor: pointer;
  font: 400 12px/1 var(--sv-font-ui);
  color: var(--sv-text-2);
  text-align: left;
}
.ds-kit-swatch:hover { background: var(--sv-surface-2); color: var(--sv-text-1); }
.ds-kit-swatch.is-active { background: var(--sv-surface-2); color: var(--sv-text-1); font-weight: 500; }
.ds-kit-swatch.is-active::after { content: '✓'; margin-left: auto; color: var(--sv-accent-1-text); font-size: 11px; }
.ds-kit-swatch .ds-kit-dot { width: 14px; height: 14px; box-shadow: 0 0 0 1px var(--ds-line-control); }

.ds-segmented {
  display: flex;
  padding: 2px;
  gap: 2px;
  background: var(--sv-bg-1);
  border: 1px solid var(--ds-line-control);
  border-radius: var(--sv-r1);
}
.ds-segmented__item {
  flex: 1;
  height: 22px;
  border: none;
  background: transparent;
  border-radius: var(--sv-r1);
  cursor: pointer;
  font: 500 11px/1 var(--sv-font-ui);
  color: var(--sv-text-3);
}
.ds-segmented__item:hover { color: var(--sv-text-1); }
.ds-segmented__item.is-active { background: var(--sv-accent-1); color: var(--sv-text-onaccent); }

.ds-appearance__version {
  margin: 10px 0 0;
  font: var(--ds-t-micro);
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--sv-text-3);
}

/* ═══════════════════════ 6. Main, topbar, contenuto ═══════════════════════ */

.ds-main { flex: 1; min-width: 0; display: flex; flex-direction: column; }

.ds-topbar {
  height: var(--ds-h-topbar);
  flex: none;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 0 20px;
  border-bottom: 1px solid var(--ds-line-structure);
  background: var(--sv-surface-1);
  position: sticky;
  top: 0;
  z-index: calc(var(--sv-z-sticky) + 1);
}
.ds-topbar__title {
  font: var(--ds-t-title);
  margin: 0;
  flex: 1;
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.ds-topbar__crumb { color: var(--sv-text-3); font-weight: 400; }
.ds-topbar__actions { display: flex; gap: 6px; align-items: center; flex: none; }
.ds-topbar__menu { display: none; }

/* Spia del contesto di debug: usa la tinta di avviso, non l'accento —
   l'accento significa "azione", questa è una condizione. */
.ds-debug-flag {
  display: inline-flex;
  align-items: center;
  height: 22px;
  padding: 0 8px;
  flex: none;
  border-radius: var(--sv-r-full);
  background: var(--sv-warn-tint);
  color: var(--ds-warn-text);
  box-shadow: inset 0 0 0 1px var(--sv-warn);
  font: var(--ds-t-micro);
  letter-spacing: .1em;
  text-transform: uppercase;
  text-decoration: none;
  white-space: nowrap;
}

.ds-content {
  padding: var(--ds-pad-content);
  display: flex;
  flex-direction: column;
  gap: 12px;
  flex: 1;
  min-width: 0;
}
.ds-flash { display: flex; flex-direction: column; gap: 8px; }

/* Un <form> che avvolge più riquadri non deve mangiare il ritmo del
   contenitore: il gap vale fra i figli diretti, e i riquadri dentro il
   form sono figli del form. Senza questo, due card nello stesso form si
   toccano mentre quelle fuori restano distanziate — ed è esattamente il
   caso delle pagine Settings. */
   :not([hidden]) non è un dettaglio: display:flex batte il display:none
   che l'attributo hidden porta dal browser, e la conferma di eliminazione
   — che nasce hidden — restava aperta in fondo a ogni scheda. */
.ds-content > form:not([hidden]) { display: flex; flex-direction: column; gap: inherit; }

/* Ritmo comodo, per le pagine di configurazione.
   La scala densa esiste per le schede da 119 campi, dove ogni pixel
   risparmiato è mezza schermata di scroll in meno. Una pagina di Settings
   ha tre riquadri da quattro campi: lì lo stesso ritmo non compra niente e
   i riquadri si leggono come un blocco unico. Le misure restano sulla
   scala del kit (--sv-s5 = 24, --sv-s4 = 16). */
.ds-content--comfort { gap: var(--sv-s5); padding: var(--sv-s5) var(--sv-s5) var(--sv-s6); }
.ds-content--comfort > .ds-settings-nav { margin-bottom: calc(var(--sv-s2) * -1); }
.ds-content--comfort .ds-section__body { padding: var(--sv-s4) var(--sv-s5) var(--sv-s5); }
.ds-content--comfort .ds-section__title { height: 44px; padding: 0 var(--sv-s5); }
.ds-content--comfort .ds-row { margin-bottom: var(--sv-s4); }
.ds-content--comfort .ds-row:last-child { margin-bottom: 0; }
.ds-content--comfort .ds-form-actions { padding-top: var(--sv-s4); }
.ds-content--comfort .ds-table th:first-child,
.ds-content--comfort .ds-table td:first-child { padding-left: var(--sv-s5); }
.ds-content--comfort .ds-table th:last-child,
.ds-content--comfort .ds-table td:last-child { padding-right: var(--sv-s5); }
/* lo shim per le card senza guscio di corpo segue lo stesso passo */
.ds-content--comfort .ds-card > .ds-section__title ~ *:not(:where(.ds-section__body, .ds-table-wrap, .ds-table-toolbar, .ds-table-footer, .ds-actionbar, table)) {
  margin-left: var(--sv-s5);
  margin-right: var(--sv-s5);
}

/* Nessun blocco di prosa supera la misura di riga leggibile: a piena
   larghezza una riga arriva a 178 caratteri, contro le 45-75 entro cui
   l'occhio ritrova da solo l'inizio della riga successiva. */
.ds-content > p,
.ds-section__body > p,
.ds-alert { max-width: 72ch; }

/* ═══════════════════════ 7. Card e sezioni ═══════════════════════ */

.ds-card, .ds-body .sv-card {
  background: var(--sv-surface-1);
  border: 1px solid var(--ds-line-structure);
  border-radius: var(--sv-r2);
  box-shadow: none;
  backdrop-filter: none;   /* il vetro su una pagina densa abbassa il contrasto */
  padding: 0;
  /* .sv-card del kit usa overflow:hidden, che taglia l'anello di focus
     (box-shadow) dei controlli sul bordo della card */
  overflow: visible;
}
.ds-card--pad, .ds-pad { padding: var(--ds-pad-card) 16px; }

/* La spaziatura del form la governa il guscio, non un margine inline
   sulle singole card. */
.ds-resource-form { display: flex; flex-direction: column; gap: 12px; flex: 1; min-height: 0; }

/* Le sezioni di una scheda sono un unico blocco continuo, non sei card
   impilate: da card indipendenti i bordi si raddoppiano a ogni giunzione
   (2px) e i raggi si scontrano a coppie strozzando gli angoli. Qui il
   guscio è uno solo e le figlie portano solo il proprio separatore.
   overflow:hidden taglierebbe l'anello di focus, quindi il raggio va
   alle estremità. */
.ds-sections {
  background: var(--sv-surface-1);
  border: 1px solid var(--ds-line-structure);
  border-radius: var(--sv-r2);
}
.ds-sections > .ds-section {
  border: 0;
  border-radius: 0;
  border-bottom: 1px solid var(--ds-line-structure);
}
.ds-sections > .ds-section:last-child { border-bottom: 0; }
.ds-sections > .ds-section:first-child > summary { border-radius: var(--sv-r2) var(--sv-r2) 0 0; }
.ds-sections > .ds-section:last-child:not([open]) > summary { border-radius: 0 0 var(--sv-r2) var(--sv-r2); }

.ds-section {
  display: block;
  /* la pila sticky è topbar 48 + indice di sezione 40: senza questo il
     salto dall'indice atterra su campi senza intestazione */
  scroll-margin-top: calc(var(--ds-h-topbar) + 48px);
}
.ds-section__title,
details.ds-section > summary {
  display: flex;
  align-items: center;
  gap: 8px;
  height: 38px;
  padding: 0 16px;
  margin: 0;
  font: var(--ds-t-section);
  letter-spacing: .12em;
  text-transform: uppercase;
  /* il titolo di sezione è il livello 1 della gerarchia e deve pesare
     più dei suoi sotto-titoli: fondo di chrome e inchiostro primario */
  background: var(--sv-surface-2);
  color: var(--sv-text-1);
  list-style: none;
  cursor: pointer;
  user-select: none;
  border-radius: var(--sv-r2) var(--sv-r2) 0 0;
}
details.ds-section > summary::-webkit-details-marker { display: none; }
details.ds-section > summary::after {
  content: '';
  margin-left: 10px;
  width: 0; height: 0;
  border-left: 5px solid currentColor;
  border-top: 4px solid transparent;
  border-bottom: 4px solid transparent;
  opacity: .5;
  transition: transform var(--sv-dur-2) var(--sv-ease);
}
details.ds-section[open] > summary::after { transform: rotate(90deg); }
details.ds-section[open] > summary { border-bottom: 1px solid var(--ds-line-structure); }
details.ds-section > summary:hover { background: var(--sv-surface-3); }
.ds-section__count {
  font: var(--ds-t-mono);
  color: var(--sv-text-3);
  letter-spacing: 0;
  margin-left: auto;
  padding-left: 8px;
  font-variant-numeric: tabular-nums;
}
.ds-section__body { padding: 14px 16px; }

/* Paragrafo o avviso che apre una sezione. Prima erano una dozzina di
   margini inline in rem (.5 / .75 / .35), fuori dal modulo da 4px e tutti
   diversi fra loro: il ritmo verticale cambiava da pagina a pagina. */
.ds-section__intro { margin: 0 0 12px; }
.ds-section__intro:last-child { margin-bottom: 0; }

/* ---- selettore booleano ---- */

/* Due voci affiancate invece di una casella: una checkbox dice se stessa
   ("debug mode" spuntato = acceso?), un segmentato dice lo stato per
   esteso su entrambi i lati, e a colpo d'occhio si legge quale dei due
   valori e' quello attivo. Su un pannello diagnostico conta: l'operatore
   deve capire in che stato si trova, non dedurlo. */
.ds-toggle {
  display: inline-flex;
  padding: 2px;
  gap: 2px;
  background: var(--sv-bg-1);
  border: 1px solid var(--ds-line-control);
  border-radius: var(--sv-r1);
  width: 100%;
  max-width: 200px;
}
.ds-toggle__option { flex: 1; display: flex; }
.ds-toggle__option input {
  position: absolute;
  width: 1px; height: 1px;
  opacity: 0;
  margin: 0;
}
.ds-toggle__option span {
  flex: 1;
  height: 26px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--sv-r1);
  font: 500 12px/1 var(--sv-font-ui);
  color: var(--sv-text-3);
  cursor: pointer;
  user-select: none;
}
.ds-toggle__option span:hover { color: var(--sv-text-1); }
.ds-toggle__option input:checked + span { background: var(--sv-surface-3); color: var(--sv-text-1); }
/* Acceso non e' un valore neutro: un contesto diagnostico attivo si vede. */
.ds-toggle__option input:checked + span.is-on {
  background: var(--sv-warn-tint);
  color: var(--ds-warn-text);
  box-shadow: inset 0 0 0 1px var(--sv-warn);
}
.ds-toggle__option input:focus-visible + span { box-shadow: var(--ds-focus-ring); }

/* ---- nota informativa di sezione ---- */

.ds-info { margin: 0 0 12px; }
.ds-info:last-child { margin-bottom: 0; }

/* L'intera riga apre la nota: un bersaglio da 16px accanto al testo è
   sotto il minimo di 24px di WCAG 2.5.8, e costringe a mirare. */
.ds-info__summary {
  display: flex;
  align-items: center;
  gap: 8px;
  list-style: none;
  cursor: pointer;
  font: var(--ds-t-meta);
  color: var(--sv-text-2);
  border-radius: var(--sv-r1);
  min-height: 24px;
}
.ds-info__summary::-webkit-details-marker { display: none; }
.ds-info__summary:hover { color: var(--sv-text-1); }
.ds-info__short { max-width: 72ch; }

.ds-info__icon {
  display: inline-flex;
  width: 16px;
  height: 16px;
  flex: none;
  color: var(--sv-text-3);
}
.ds-info__icon svg { width: 100%; height: 100%; }
.ds-info__summary:hover .ds-info__icon,
.ds-info[open] .ds-info__icon { color: var(--sv-accent-1-text); }

.ds-info__panel {
  margin-top: 8px;
  padding: 12px 14px;
  max-width: 72ch;
  background: var(--sv-surface-2);
  border: 1px solid var(--ds-line-structure);
  border-left: 3px solid var(--sv-accent-1);
  border-radius: var(--sv-r1);
}
.ds-info__panel p { margin: 0 0 8px; font: var(--ds-t-body); color: var(--sv-text-1); }
.ds-info__panel p:last-child { margin-bottom: 0; }

/* visibile solo agli screen reader */
.ds-sr {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* etichetta di un gruppo di controlli, non di un singolo campo */
.ds-label--block { display: block; margin-bottom: 6px; }

/* Data History: la piuma accanto all'etichetta del campo */
.ds-history-btn {
  border: 0; background: none; cursor: pointer; padding: 0 2px;
  font-size: 13px; line-height: 1; vertical-align: baseline;
  opacity: .55; transition: opacity var(--sv-dur-2) var(--sv-ease);
}
.ds-history-btn:hover, .ds-history-btn:focus-visible { opacity: 1; }

.ds-mono { font-family: var(--sv-font-mono); font-size: 12px; }
.ds-code--wrap { word-break: break-all; }
.ds-table__center { text-align: center; }

/* Titolo dentro una card già padded: è un'intestazione, non una fascia,
   quindi niente fondo di chrome né padding proprio. */
.ds-card__title {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0 0 12px;
  font: var(--ds-t-title);
}

.ds-pre {
  background: var(--sv-surface-2);
  border: 1px solid var(--ds-line-structure);
  border-radius: var(--sv-r1);
  padding: 10px 12px;
  overflow: auto;
  font: var(--ds-t-mono);
  line-height: 18px;
  max-height: 400px;
  margin: 0;
}

/* Compatibilità: molte viste dichiarano il titolo come <h2> seguito dal
   contenuto nudo, senza il guscio .ds-section__body. Il titolo è una
   fascia a filo card con 16px di padding, il contenuto ne aveva 0: il
   bordo sinistro della pagina risultava frastagliato di 16px, card per
   card. Qui il contenuto rientra sul filo del titolo; le fasce che devono
   restare a tutta larghezza (tabelle, toolbar, footer) sono escluse. */
.ds-card > .ds-section__title ~ *:not(:where(.ds-section__body, .ds-table-wrap, .ds-table-toolbar, .ds-table-footer, .ds-actionbar, table)) {
  margin-left: 16px;
  margin-right: 16px;
}
.ds-card > .ds-section__title + *:not(:where(.ds-section__body, .ds-table-wrap, .ds-table-toolbar, .ds-table-footer, .ds-actionbar, table)) {
  margin-top: 14px;
}
.ds-card > .ds-section__title ~ *:last-child:not(:where(.ds-section__body, .ds-table-wrap, .ds-table-toolbar, .ds-table-footer, .ds-actionbar, table)) {
  margin-bottom: 14px;
}

/* ═══════════════════════ 8. Griglia dei form ═══════════════════════ */

/* Griglia vera a 12 colonne, non flex.
   Con flex il flex-basis sottrae il gap ma il max-width no: resta sempre
   uno spazio libero che flex-grow ridistribuisce in parti UGUALI a ogni
   colonna, a prescindere dallo span. Su righe a composizione mista il
   bordo interno delle colonne scarta di qualche pixel da riga a riga e il
   form risulta frastagliato. Con grid ogni bordo di colonna cade sullo
   stesso pixel su tutte le righe. */
.ds-row {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  gap: var(--ds-gap-field);
  margin-bottom: var(--ds-gap-row);
  align-items: start;
}
.ds-row:last-child { margin-bottom: 0; }

.ds-col {
  grid-column: span min(var(--ds-col, 12), 12);
  min-width: 0;
  min-height: 0;
}

/* La protezione contro le colonne-fessura passa dai breakpoint, non da un
   min-width che dentro una griglia provocherebbe overflow. Sotto i 1400px
   l'unità scende sotto i 180px leggibili: la quota collassa di un gradino
   (--ds-col-md, calcolato da FormLayout::collapse).

   Queste due soglie NON sono bande di dispositivo e non vanno allineate a
   quelle del kit: 1400 e 1100 sono i punti in cui una griglia a 12 quote
   porta il singolo campo sotto la misura leggibile, e dipendono da quante
   quote il modulo chiede — cioè dal contenuto, non dallo schermo. Il kit
   vieta di ripetere a valle i PROPRI valori; questi non lo sono. */
@media (max-width: 1400px) {
  .ds-col { grid-column: span min(var(--ds-col-md, var(--ds-col, 12)), 12); }
}
@media (max-width: 1100px) {
  .ds-col, .ds-col--wide { grid-column: 1 / -1; }
}

/* Il mono maiuscolo si paga solo su stringhe corte: su
   "Fascia 0 — noleggio standard (intervallo giorni + prezzo)" azzera la
   sagoma della parola e va letto lettera per lettera. */
.ds-field-heading {
  font: 600 12px/16px var(--sv-font-ui);
  letter-spacing: .01em;
  text-transform: none;
  color: var(--sv-text-2);
  margin: 6px 0 2px;
  padding-bottom: 4px;
  border-bottom: 1px solid var(--ds-line-hair);
  width: 100%;
}

.ds-checkbox-field {
  flex-direction: row;
  align-items: center;
  gap: 8px;
  height: var(--ds-h-control);
  padding: 0 2px;
}
.ds-checkbox-field .ds-label,
.ds-checkbox-field .sv-field__label { white-space: normal; }

/* Una relazione senza record collegabili non deve avere l'aspetto di un
   campo compilabile: sei rettangoli identici a un input, ognuno alto 58px
   per dire sei volte "non c'è niente". Il tratteggio toglie l'affordance
   e l'altezza scende a quella di un controllo. */
.ds-field__empty {
  height: var(--ds-h-control);
  display: flex;
  align-items: center;
  padding: 0 var(--ds-pad-x);
  font: var(--ds-t-meta);
  color: var(--sv-text-3);
  background: var(--sv-surface-2);
  border: 1px dashed var(--ds-line-hair);
  border-radius: var(--sv-r1);
}

/* Un campo a riga intera che contiene un codice di otto caratteri resta
   comunque allineato alla griglia, ma oltre ~60 caratteri la scatola non
   aiuta più a leggere il valore. */
.ds-field > .ds-input:not(textarea):not([multiple]) { max-width: 60ch; }

.ds-image-preview { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 4px; }
.ds-image-preview img {
  max-width: 96px;
  max-height: 72px;
  border-radius: var(--sv-r1);
  border: 1px solid var(--ds-line-hair);
  object-fit: cover;
  background: var(--sv-surface-2);
}

.ds-repeater { display: flex; flex-direction: column; gap: 6px; }
.ds-repeater__item {
  padding: 8px 10px;
  border: 1px solid var(--ds-line-hair);
  border-radius: var(--sv-r1);
  background: var(--sv-bg-1);
}
.ds-repeater__item .ds-row:last-child { margin-bottom: 0; }
.ds-repeater__foot { display: flex; justify-content: flex-start; margin-top: 2px; }

/* ═══════════════════════ 9. Tabs ═══════════════════════ */

.ds-tabs { margin: 4px 0 10px; }
.ds-tabs__nav {
  display: flex;
  gap: 2px;
  flex-wrap: wrap;
  border-bottom: 1px solid var(--ds-line-structure);
  margin-bottom: 12px;
}
.ds-tabs__tab {
  background: none;
  border: none;
  border-bottom: 2px solid transparent;
  padding: 6px 10px;
  margin-bottom: -1px;
  color: var(--sv-text-3);
  font: 500 12px/16px var(--sv-font-ui);
  cursor: pointer;
}
.ds-tabs__tab:hover { color: var(--sv-text-1); }
.ds-tabs__tab.is-active { color: var(--sv-text-1); border-bottom-color: var(--sv-accent-1); }
.ds-tabs__panel { display: none; }
.ds-tabs__panel.is-active { display: block; }

/* ═══════════════════════ 10. Indice di sezione + barra azioni ═══════════════════════ */

.ds-sectionnav {
  position: sticky;
  top: var(--ds-h-topbar);
  z-index: var(--sv-z-sticky);
  display: flex;
  align-items: center;
  gap: 4px;
  overflow-x: auto;
  padding: 8px 20px;
  margin: calc(var(--ds-pad-card) * -1) calc(var(--ds-pad-content-x) * -1) 0;
  background: var(--sv-bg-1);
  border-bottom: 1px solid var(--ds-line-structure);
  scrollbar-width: thin;
}
.ds-sectionnav__item {
  flex: none;
  height: 32px;
  padding: 0 10px;
  border: 0;
  border-radius: 0;
  background: transparent;
  color: var(--sv-text-3);
  font: 500 12px/1 var(--sv-font-ui);
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  box-shadow: inset 0 -2px 0 transparent;
}
.ds-sectionnav__item:hover { color: var(--sv-text-1); }
.ds-sectionnav__toggle { margin-left: auto; flex: none; }
.ds-sectionnav__item.is-active {
  color: var(--sv-text-1);
  box-shadow: inset 0 -2px 0 var(--sv-accent-1);
}

.ds-actionbar {
  position: sticky;
  bottom: 0;
  z-index: var(--sv-z-sticky);
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px 16px;
  /* auto in alto: su una scheda corta la barra scende comunque a fondo
     pagina invece di lasciare mezzo schermo di canvas sotto di sé */
  margin: auto calc(var(--ds-pad-content-x) * -1) calc(16px * var(--sv-gap-k, 1) * -1);
  background: var(--sv-surface-1);
  border-top: 1px solid var(--ds-line-structure);
}
.ds-actionbar__meta {
  font: var(--ds-t-mono);
  color: var(--sv-text-3);
  margin-right: auto;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ═══════════════════════ 11. Tabella dati ═══════════════════════ */

.ds-table-card { display: flex; flex-direction: column; overflow: hidden; }
/* Una tabella sola in pagina collassava sul contenuto lasciando fuori
   700px di canvas nudo. Il vuoto deve stare DENTRO il contenitore, dove
   significa "non ci sono altri record", non fuori come pagina morta.
   Solo quando è l'unica card: se ce ne sono due si spartirebbero
   l'altezza e nessuna delle due mostrerebbe le sue righe. */
.ds-content > .ds-table-card:only-child { flex: 1; min-height: 0; }
.ds-content > .ds-table-card:only-child .ds-table-wrap { flex: 1; max-height: none; }

.ds-table-toolbar {
  display: flex;
  gap: 8px;
  align-items: center;
  padding: 10px 12px;
  border-bottom: 1px solid var(--ds-line-structure);
  flex-wrap: wrap;
}
.ds-table-search { max-width: 300px; flex: 1 1 220px; }
.ds-table-perpage { max-width: 120px; }

.ds-table-wrap { overflow: auto; max-height: calc(100vh - 210px); }

.ds-table {
  width: 100%;
  /* Regola del kit: le colonne di una tabella NON collassano, la traccia
     scorre — «una riga di dati spezzata in verticale non è più una riga di
     dati». Sul telefono --sv-riga-min impone la misura sotto la quale le
     colonne diventano illeggibili, e il wrapper qui sopra la fa scorrere. */
  min-width: var(--sv-riga-min, auto);
  border-collapse: separate;
  border-spacing: 0;
  font: var(--ds-t-body);
}
.ds-table th {
  position: sticky;
  top: 0;
  z-index: 1;
  text-align: left;
  padding: 0 10px;
  height: 30px;
  /* l'intestazione di colonna è l'unica bussola di una tabella a 15+
     colonne: in mono 11px MAIUSCOLO spaziato, nell'inchiostro più debole
     della scala, era il testo più difficile della pagina — più difficile
     del dato che deve indicizzare. */
  font: 600 12px/16px var(--sv-font-ui);
  letter-spacing: .01em;
  text-transform: none;
  color: var(--sv-text-2);
  background: var(--sv-surface-2);
  border-bottom: 1px solid var(--ds-line-structure);
  white-space: nowrap;
}
.ds-table td {
  padding: 0 10px;
  height: var(--ds-h-row);
  border-bottom: 1px solid var(--ds-line-hair);
  color: var(--sv-text-1);
  max-width: 320px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.ds-table tbody tr:hover td { background: var(--sv-surface-2); }
.ds-table tbody tr:last-child td { border-bottom: none; }
.ds-table__sort { color: inherit; text-decoration: none; display: inline-flex; gap: 4px; align-items: center; }
.ds-table__sort:hover { color: var(--sv-text-1); }
.ds-table__sort.is-sorted-asc::after { content: '↑'; color: var(--sv-accent-1-text); }
.ds-table__sort.is-sorted-desc::after { content: '↓'; color: var(--sv-accent-1-text); }
.ds-table__empty {
  text-align: center;
  color: var(--sv-text-3);
  padding: 40px 16px !important;
  height: auto !important;
  white-space: normal !important;
}
/* Colonna identità congelata: senza, appena si scorre a destra per
   leggere le ultime colonne ogni riga diventa anonima. Il fondo esplicito
   è obbligatorio, una cella trasparente in sticky lascia passare le
   colonne che le scorrono sotto. */
.ds-table th:first-child,
.ds-table td:first-child {
  padding-left: 16px;
  position: sticky;
  left: 0;
  z-index: 2;
  background: var(--sv-surface-1);
  box-shadow: 1px 0 0 var(--ds-line-hair);
}
.ds-table th.ds-table__actions-col,
.ds-table td.ds-table__actions-col {
  position: sticky;
  right: 0;
  z-index: 2;
  background: var(--sv-surface-1);
  border-left: 1px solid var(--ds-line-structure);
}
.ds-table thead th:first-child,
.ds-table thead th.ds-table__actions-col { z-index: 3; background: var(--sv-surface-2); }
.ds-table tbody tr:hover td:first-child,
.ds-table tbody tr:hover td.ds-table__actions-col { background: var(--sv-surface-2); }
.ds-table th:last-child, .ds-table td:last-child { padding-right: 16px; }
.ds-table__actions-col { width: 1%; white-space: nowrap; }
.ds-table__code { font: var(--ds-t-mono); color: var(--sv-text-2); }

/* Il dettaglio di un'esecuzione è una frase, non un codice: va a capo
   invece di allargare la tabella oltre lo schermo. */
.ds-table__detail { max-width: 46ch; white-space: normal; word-break: break-word; }

/* Il codice che apre il record era testo colorato senza sottolineatura,
   indistinguibile da un valore qualsiasi della stessa riga. */
.ds-table__link {
  font: var(--ds-t-mono);
  color: var(--sv-accent-1-text);
  text-decoration: underline;
  text-underline-offset: 2px;
}
.ds-table__link:hover { color: var(--sv-text-1); }

.ds-table-footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 8px 12px;
  border-top: 1px solid var(--ds-line-structure);
  flex-wrap: wrap;
}
.ds-table-count { color: var(--sv-text-3); font: var(--ds-t-meta); }
.ds-pagination { display: flex; align-items: center; gap: 6px; }
.ds-pagination__state { color: var(--sv-text-3); font: var(--ds-t-meta); }
.is-disabled { opacity: .38; pointer-events: none; }

/* ═══════════════════════ 12. Bacheca ═══════════════════════ */

.ds-board-filters { display: flex; gap: 12px; padding: 10px 12px; flex-wrap: wrap; align-items: flex-end; width: fit-content; max-width: 100%; }
.ds-board-filters .sv-field, .ds-board-filters .ds-field { min-width: 150px; }

.ds-board {
  display: grid;
  /* Tre colonne che il kit fa scendere a due in banda tavoletta e a una sul
     telefono. Prima erano tre o una, con la tavoletta che saltava il gradino
     di mezzo perché la soglia era nostra e ne conosceva uno solo. */
  grid-template-columns: var(--sv-g3, repeat(3, 1fr));
  gap: calc(10px * var(--sv-gap-k, 1));
  min-height: calc(100vh - var(--ds-h-topbar) - 120px);
  grid-auto-rows: minmax(0, 1fr);
}

.ds-board__column {
  display: flex;
  flex-direction: column;
  background: var(--sv-surface-1);
  border: 1px solid var(--ds-line-structure);
  border-radius: var(--sv-r2);
  overflow: hidden;
}
.ds-board__header {
  font: var(--ds-t-section);
  letter-spacing: .14em;
  text-transform: uppercase;
  height: 34px;
  padding: 0 12px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  border-bottom: 1px solid var(--ds-line-structure);
  color: var(--sv-text-2);
  position: relative;
}
.ds-board__header::before {
  content: '';
  position: absolute;
  inset: 0 auto auto 0;
  width: 100%; height: 2px;
}
.ds-board__header--todo::before { background: var(--sv-text-3); }
.ds-board__header--working::before { background: var(--sv-info); }
.ds-board__header--blocked::before { background: var(--sv-err); }
.ds-board__header--close::before { background: var(--sv-ok); }
.ds-board__count { color: var(--sv-text-3); letter-spacing: 0; }
.ds-board__list { flex: 1; min-height: 0; padding: 8px; display: flex; flex-direction: column; gap: 6px; }
.ds-board__list.is-over { background: var(--sv-accent-1-tint); }
.ds-board__empty { color: var(--sv-text-3); font: var(--ds-t-meta); text-align: center; margin: auto 0; }

.ds-task {
  background: var(--sv-bg-1);
  border: 1px solid var(--ds-line-structure);
  border-radius: var(--sv-r1);
  padding: 8px 10px;
  cursor: grab;
}
.ds-task:hover { border-color: var(--ds-line-control); }
.ds-task.is-dragging { opacity: .5; }
.ds-task__top { display: flex; align-items: center; gap: 6px; }
.ds-task__title { font: 500 13px/18px var(--sv-font-ui); margin: 0; flex: 1; min-width: 0; }
.ds-task__priority {
  font: 700 10px/16px var(--sv-font-mono);
  min-width: 18px;
  height: 16px;
  text-align: center;
  border-radius: var(--sv-r-full);
  flex: none;
  padding: 0 4px;
}
.ds-task__priority.is-high { background: var(--sv-err); color: var(--sv-text-on-err); }
.ds-task__priority.is-medium { background: var(--sv-warn); color: var(--sv-text-on-warn); }
.ds-task__priority.is-low { background: var(--sv-ok); color: var(--sv-text-on-ok); }
.ds-task__priority.is-none { background: var(--sv-surface-3); color: var(--sv-text-3); }
.ds-task__preview { font: var(--ds-t-meta); color: var(--sv-text-2); margin: 4px 0; }
.ds-task__meta { display: flex; justify-content: space-between; font: var(--ds-t-mono); color: var(--sv-text-3); }

.ds-useful-links { padding: 12px; }
.ds-useful-links__grid { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }

/* ═══════════════════════ 13. Modale, toast ═══════════════════════ */

.ds-modal { position: fixed; inset: 0; z-index: var(--sv-z-modal); display: flex; align-items: center; justify-content: center; }
.ds-modal[hidden] { display: none; }
/* Il velo NON è nero. Il kit lo dice esplicitamente e ne dà il token:
   --sv-scrim è derivato dall'inchiostro del clima attivo, e un velo di nero
   puro sarebbe l'unico pezzo d'interfaccia che non appartiene al kit — si
   nota proprio nel momento in cui tutto il resto si è appena tinto.
   Anche la sfocatura è del kit: --sv-scrim-blur, che alcuni climi azzerano. */
.ds-modal__backdrop {
  position: absolute;
  inset: 0;
  background: var(--sv-scrim);
  backdrop-filter: blur(var(--sv-scrim-blur));
  -webkit-backdrop-filter: blur(var(--sv-scrim-blur));
}
.ds-modal__panel {
  position: relative;
  width: min(700px, calc(100vw - 32px));
  max-height: calc(100vh - 64px);
  overflow-y: auto;
  padding: 16px;
  box-shadow: var(--sv-e3);
}

.ds-toast {
  position: fixed;
  bottom: 16px;
  right: 16px;
  z-index: var(--sv-z-modal);
  box-shadow: var(--sv-e3);
}

/* ═══════════════════════ 14. Settings ═══════════════════════ */

.ds-settings-nav {
  display: flex;
  gap: 2px;
  overflow-x: auto;
  padding: 4px;
  background: var(--sv-surface-1);
  border: 1px solid var(--ds-line-control);
  border-radius: var(--sv-r2);
  scrollbar-width: thin;
}
.ds-settings-nav a {
  flex: none;
  height: 26px;
  padding: 0 10px;
  display: inline-flex;
  align-items: center;
  border-radius: var(--sv-r1);
  font: 500 12px/1 var(--sv-font-ui);
  color: var(--sv-text-2);
  text-decoration: none;
  white-space: nowrap;
  border: none;
  background: transparent;
}
.ds-settings-nav a:hover { background: var(--sv-surface-2); color: var(--sv-text-1); }
.ds-settings-nav a.is-active {
  background: var(--sv-accent-1-tint);
  color: var(--sv-text-1);
  box-shadow: inset 0 0 0 1px var(--sv-accent-1);
  font-weight: 500;
}

.ds-form-actions { display: flex; gap: 8px; align-items: center; padding-top: 12px; }
.ds-delete-confirm { padding: 14px 16px; border-color: var(--sv-err); }

/* ═══════════════════════ 14b. Log viewer ═══════════════════════ */

/* Il viewer resta scuro come una console, ma il nero lo dà il kit
   (--sv-bg-0 della polarità scura) e non un letterale: così segue il kit
   attivo e in tema chiaro non incolla una finestra nera nella pagina. */
.ds-log-viewer {
  background: var(--sv-surface-3);
  color: var(--sv-text-1);
  font: var(--ds-t-mono);
  line-height: 1.55;
  padding: 12px 14px;
  border: 1px solid var(--ds-line-structure);
  border-radius: var(--sv-r2);
  overflow: auto;
  height: 60vh;
  min-height: 320px;
}
.ds-log-line { white-space: pre-wrap; word-break: break-word; }
.ds-log-critical,
.ds-log-error { color: var(--ds-err-text); font-weight: 700; }
.ds-log-warning { color: var(--ds-warn-text); }
.ds-log-info { color: var(--ds-info-text); }
.ds-log-debug { color: var(--sv-text-3); }
.ds-log-viewer mark {
  background: var(--sv-accent-1-tint);
  color: var(--sv-text-1);
  box-shadow: inset 0 0 0 1px var(--sv-accent-1);
  border-radius: var(--sv-r1);
}
.ds-log-toolbar { display: flex; flex-wrap: wrap; gap: 10px; align-items: flex-end; margin-bottom: 10px; }
.ds-log-toolbar .sv-field, .ds-log-toolbar .ds-field { margin: 0; min-width: 150px; }
.ds-log-meta { margin-top: 8px; }

/* card che porta un avviso: il filetto laterale è l'unico segnale
   strutturale, il colore da solo non basta */
.ds-section--warn { border-color: var(--sv-warn); border-left-width: 3px; }

/* ═══════════════════════ 14c. Dizionario campi ═══════════════════════ */

.ds-dict-meta {
  font: var(--ds-t-mono);
  color: var(--sv-text-3);
  text-transform: none;
  letter-spacing: 0;
  margin-left: 8px;
}
/* --sv-warn come inchiostro sta a 4.10: sotto AA. L'inchiostro dedicato
   porta lo stesso significato a 5.45. */
.ds-dict-warn { color: var(--ds-warn-text); }
.ds-dict-fields { display: flex; flex-wrap: wrap; gap: 6px; }
.ds-dict-field {
  font: 500 12px/18px var(--sv-font-mono);
  padding: 3px 8px;
  border-radius: var(--sv-r1);
  background: var(--sv-surface-2);
  border: 1px solid var(--ds-line-hair);
  color: var(--sv-text-1);
  cursor: pointer;
}
.ds-dict-field:hover { border-color: var(--ds-line-control); }
/* l'inchiostro d'accento su accent-1-tint sopra surface-1 scende a 4.26;
   su surface-2 tiene 4.84 */
.ds-dict-field.is-pk { background: var(--sv-surface-2); color: var(--sv-accent-1-text); font-weight: 700; box-shadow: inset 0 0 0 1px var(--sv-accent-1); }
.ds-dict-field.is-warn { border-color: var(--sv-warn); }
.ds-dict-field.is-hidden { display: none; }
.ds-dict-field.is-copied { background: var(--sv-ok-tint); border-color: var(--sv-ok); }

/* ═══════════════════════ 14d. Articoli di listino ═══════════════════════ */

/* Il riquadro di un articolo porta in intestazione il tipo e il nome: su
   venti riquadri aperti è l'unica cosa che distingue "telo 3x3" da
   "telo 4x4" senza leggere i prezzi. */
.ds-priceitem > summary { gap: 8px; }
.ds-priceitem > summary .ds-badge { flex: none; }

/* Le quattro fasce sono lo stesso schema ripetuto: senza una riga di
   separazione i dodici campi si leggono come un unico blocco e non si
   capisce dove finisce una fascia. */
.ds-priceitem__tier + .ds-priceitem__tier { margin-top: var(--sv-s3); }
.ds-priceitem__tier .ds-field-heading { display: flex; align-items: baseline; gap: 8px; }

/* Togliere un articolo è distruttivo: non deve stare in mezzo ai prezzi
   dove si spunta per sbaglio scorrendo. */
.ds-priceitem__remove {
  margin-top: var(--sv-s3);
  padding-top: var(--sv-s2);
  border-top: 1px solid var(--ds-line-hair);
  height: auto;
  color: var(--sv-text-3);
}

.ds-priceitem__add + .ds-priceitem__add { margin-top: var(--sv-s3); }
/* Il bottone si allinea al fondo della select, non alla sua etichetta. */
.ds-priceitem__add-action { display: flex; align-items: flex-end; padding-bottom: 2px; }
.ds-priceitem__add-action .ds-btn { width: 100%; }

/* ═══════════════════ 14e. Collegamenti fra risorse ═══════════════════ */

/* Il chip porta il codice-link e la crocetta di scollegamento: la form
   inline non deve rompere il flusso del chip. */
.ds-dict-field .ds-link-remove { display: inline; margin-left: 4px; }
.ds-link-remove__btn {
  border: 0; background: none; cursor: pointer;
  font: inherit; color: var(--sv-text-3); padding: 0 2px;
}
.ds-link-remove__btn:hover { color: var(--ds-err-text); }
.ds-dict-field a { color: inherit; text-decoration: none; }
.ds-dict-field a:hover { text-decoration: underline; }

/* ═══════════════════════ 15. Login ═══════════════════════ */

.ds-login { display: flex; align-items: center; justify-content: center; min-height: 100vh; }
.ds-login__card { width: min(360px, calc(100vw - 32px)); padding: 32px 28px; }
.ds-login__lockup { --sv-lockup-h: 44px; display: flex; margin: 0 0 24px; justify-content: center; }
.ds-login__form { display: flex; flex-direction: column; gap: 12px; }
.ds-login__submit { width: 100%; height: var(--ds-h-control-lg); margin-top: 4px; }

/* ═══════════════════════ 16. Responsive ═══════════════════════ */

/* UNA soglia, e non è nostra: 1023px è il confine fra tavoletta e desktop
   che `tokens/dispositivo.css` dichiara. Prima l'applicativo ne aveva cinque
   diverse — 640, 900, 1000, 1100, 1400 — e chi ridimensionava la finestra
   vedeva la sidebar richiudersi a 900, la bacheca a 1000 e il modulo a 1100:
   tre riflussi per un solo gesto. Il kit dice dove finisce un dispositivo, e
   ripetere quei valori a valle sarebbero due verità.
   Restano fuori da questa regola le due soglie del modulo (1400/1100): non
   parlano del dispositivo ma della misura sotto la quale un campo smette di
   potersi leggere, che è una proprietà del contenuto. */
@media (max-width: 1023px) {
  .ds-sidebar { position: fixed; z-index: var(--sv-z-overlay); transform: translateX(-100%); transition: transform var(--sv-dur-3) var(--sv-ease); }
  .ds-sidebar.is-open { transform: none; }
  .ds-topbar__menu { display: inline-flex; }
}

/* Versione di prodotto in sidebar: piccola, cliccabile, apre il changelog */
.ds-version {
  font: var(--ds-t-micro);
  color: var(--sv-text-3);
  text-decoration: none;
  white-space: nowrap;
}
.ds-version:hover { color: var(--sv-text-1); text-decoration: underline; }

/* Field Mapping: griglia di campi cliccabili con scheda a comparsa */
.ds-fieldmap { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 12px; }
.ds-fieldmap__item { flex: 0 1 auto; min-width: 0; }
.ds-fieldmap__item > summary {
  cursor: pointer; list-style: none; padding: 3px 8px;
  border: 1px solid var(--ds-line-structure); border-radius: var(--sv-r-full);
  display: inline-flex; gap: 6px; align-items: center;
}
.ds-fieldmap__item > summary::-webkit-details-marker { display: none; }
.ds-fieldmap__item[open] { flex-basis: 100%; }
.ds-fieldmap__card {
  margin: 6px 0 4px; padding: 10px 12px;
  border: 1px solid var(--ds-line-structure); border-radius: var(--sv-r2);
}
.ds-fieldmap__card p { margin: 0 0 4px; }

/* Company Branches: i due percorsi di assegnazione, distinti e affiancati */
.ds-branch-assign {
  height: 100%; padding: 12px 14px;
  border: 1px solid var(--ds-line-structure); border-radius: var(--sv-r2);
}
.ds-branch-assign__title { margin: 0 0 2px; font: var(--ds-t-label); }

/* Pagina utenza: fila di KPI in testa */
.ds-kpi-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: 10px; margin-bottom: 12px; }
.ds-kpi { padding: 12px 14px; display: flex; flex-direction: column; gap: 2px; }
.ds-kpi__value { font-size: 28px; font-weight: 700; line-height: 1; }
.ds-kpi__label { font: var(--ds-t-label); color: var(--sv-text-2); }

/* Scelta colonne della tabella risorsa */
.ds-colchooser { padding: 10px 14px; border-bottom: 1px solid var(--ds-line-structure); }
.ds-colchooser__grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 2px 14px; }

/* ---- Organigramma (v.6.1.1) --------------------------------------------
   L'albero è un <ul> annidato e le linee sono bordi: due livelli di
   gerarchia non giustificano una libreria. Il ramo scorre in orizzontale
   dentro il proprio contenitore, così una sede numerosa non allarga la
   pagina. */
.ds-chart-wrap { overflow-x: auto; padding: 4px 0 8px; }

.ds-chart, .ds-chart__branch {
  display: flex; justify-content: center; align-items: flex-start;
  gap: 12px; list-style: none; margin: 0; padding: 0;
}
.ds-chart { padding-top: 0; }

.ds-chart__item {
  display: flex; flex-direction: column; align-items: center;
  position: relative; padding-top: 18px;
}
/* le radici non hanno nessuno sopra: niente gambo */
.ds-chart > .ds-chart__item { padding-top: 0; }

/* il gambo che scende dal superiore fino al nodo */
.ds-chart__item::before {
  content: ''; position: absolute; top: 0; left: 50%;
  width: 1px; height: 18px; background: var(--ds-line-structure);
}
.ds-chart > .ds-chart__item::before { display: none; }

/* la traversa che unisce i fratelli: mezza per il primo, mezza per
   l'ultimo, intera per quelli in mezzo — un figlio unico non ne ha */
.ds-chart__item::after {
  content: ''; position: absolute; top: 0; left: 0;
  width: 100%; height: 1px; background: var(--ds-line-structure);
}
.ds-chart__item:first-child::after { left: 50%; width: 50%; }
.ds-chart__item:last-child::after { width: 50%; }
.ds-chart__item:only-child::after { display: none; }
.ds-chart > .ds-chart__item::after { display: none; }

/* il gambo che scende dal nodo verso i propri sottoposti */
.ds-chart__branch { position: relative; margin-top: 18px; }
.ds-chart__branch::before {
  content: ''; position: absolute; top: -18px; left: 50%;
  width: 1px; height: 18px; background: var(--ds-line-structure);
}

.ds-chart__node {
  min-width: 170px; max-width: 240px; padding: 8px 10px;
  border: 1px solid var(--ds-line-structure); border-radius: var(--sv-r2);
  background: var(--sv-bg-1); text-align: center;
}
.ds-chart__node--vacant { border-style: dashed; }

.ds-chart__role { font: var(--ds-t-section); text-transform: uppercase; color: var(--sv-text-2); }
.ds-chart__person { margin-top: 4px; }
.ds-chart__person + .ds-chart__person { border-top: 1px solid var(--ds-line-hair); padding-top: 4px; }
.ds-chart__email { display: block; font: var(--ds-t-mono); color: var(--sv-text-2); overflow-wrap: anywhere; }
.ds-chart__empty { margin: 4px 0 0; font: var(--ds-t-meta); color: var(--sv-text-2); }

/* I recapiti della persona (v.6.2.0): due bersagli da 24px, nessun
   numero scritto — il nodo è già stretto, e il numero vive nell'href e
   nel title. Solo token semantici: un kit diverso li ritinge tutti. */
.ds-chart__contacts { display: flex; justify-content: center; gap: 6px; margin-top: 4px; }
.ds-contact {
  display: inline-flex; align-items: center; justify-content: center;
  width: 24px; height: 24px; border-radius: var(--sv-r-full);
  border: 1px solid var(--ds-line-hair);
  color: var(--sv-text-2); text-decoration: none;
}
.ds-contact svg { width: 14px; height: 14px; }
.ds-contact:hover { color: var(--sv-accent-1-text); border-color: var(--sv-accent-1); }
.ds-contact:focus-visible { outline: none; box-shadow: var(--ds-focus-ring); }

/* Un bottone che si legge come un link (v.6.3.0): sta dentro una riga di
   suggerimento, accanto a un link vero, e deve somigliargli. È un
   BOTTONE e non un <a> perché fa una scrittura, e una scrittura non si
   fa con una GET — la forma segue la funzione, l'aspetto segue il
   contesto. */
.ds-linkish {
    appearance: none;
    background: none;
    border: 0;
    padding: 0;
    font: inherit;
    color: var(--sv-accent-1-text);
    text-decoration: underline;
    text-underline-offset: 2px;
    cursor: pointer;
}

.ds-linkish:hover { color: var(--sv-text-1); }

/* Un recapito telefonico in due pezzi (v.6.4.0): la tendina del prefisso
   e la casella del numero stanno sulla stessa riga, e la tendina non si
   allarga — il prefisso è corto e il numero no. Sotto i 480px vanno una
   sopra l'altra, perché affiancate diventerebbero due caselle troppo
   strette per leggerle. */
.ds-phone {
    display: flex;
    gap: var(--sv-s2, .5rem);
    align-items: stretch;
}

.ds-phone__prefix { flex: 0 0 auto; max-width: 14rem; }
.ds-phone__number { flex: 1 1 auto; min-width: 0; }

@media (max-width: 480px) {
    .ds-phone { flex-direction: column; }
    .ds-phone__prefix { max-width: none; }
}
