/* ==========================================================================
   Shared Components — Buttons, Cards, Badges, Forms, Modals, Progress, etc.
   ========================================================================== */

/* --- Buttons --- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-4);
  border: 1px solid var(--neutral-300);
  border-radius: var(--radius-md);
  background: #fff;
  color: var(--neutral-800);
  font-size: var(--text-sm);
  font-family: var(--font-family);
  font-weight: var(--font-medium);
  cursor: pointer;
  transition: background var(--transition-fast), border-color var(--transition-fast), box-shadow var(--transition-fast);
  text-decoration: none;
  line-height: var(--leading-normal);
}
/* Bug #1140. `text-decoration: none` on hover too: base.css says
   `a:hover { color: var(--primary-hover); text-decoration: underline }` at
   (0,1,1), which beats `.btn`'s own `text-decoration` (0,1,0), so every
   `<a class="btn ...">` grew an underline under the pointer. `.btn:hover` is
   (0,2,0) and wins whatever the load order (same fix as #1131 for `.sim-btn`). */
.btn:hover { background: var(--neutral-100); border-color: var(--neutral-400); text-decoration: none; }
.btn:disabled { opacity: 0.55; cursor: not-allowed; }
/* Substory #707, item 5 + item 3. Questa è TUTTA la quota di `.btn-*`: la
   forma non ha più niente da chiudere. `.btn` legge `--radius-md`, che
   design-system.css:301 fa alias di `--sim-radius`, lo stesso token che
   `.sim-btn` legge — 12px da entrambe le parti, misurati. `min-height` invece
   differisce davvero (`.sim-btn` porta `--sim-tap` 44px, `.btn` calcola 0), ma
   è criterio di #767 per decisione precedente e prenderlo qui vorrebbe dire
   rubare il varco di un'altra issue. Resta l'anello di fuoco, che finora su
   ogni bottone legacy del prodotto era quello predefinito del browser
   (`1px auto`): non una scelta di questo prodotto, e più sottile del minimo
   di 2px che #778 ha fissato. */
.btn:focus-visible { outline: 2px solid var(--sim-ink); outline-offset: 2px; }

/* Bug #839. Il fondo passa da `--primary` a `--action-fill`, e non è un
   rinominare: `--primary` è tornato a essere il ROSSO DEL MARCHIO
   (design-system.css, blocco alias), mentre il fondo di un bottone pieno resta
   l'inchiostro. Con `--primary` qui dentro ogni `.btn-primary` della pagina
   diventerebbe rosso — la lettera di ADR-0004, e l'errore che l'emendamento
   del 2026-09-19 rifiuta per il rischio di somigliare alle pagine di IRCC.
   `[data-primary-action]` ridefinisce `--action-fill` su di sé, quindi l'unico
   `.btn-primary` che la pagina dichiara primario (la prima "Vedi la lista di
   controllo" nella lista dei casi) prende l'accento e gli altri no. */
.btn-primary {
  background: var(--action-fill);
  color: #fff;
  border-color: var(--action-fill);
}
/* Bug #1140. Each filled variant restates its white ink on hover. Without it
   `a:hover` (0,1,1) beat `.btn-primary { color: #fff }` (0,1,0), and an
   `<a class="btn btn-primary">` — the cases list's "Visualizza la lista di
   controllo" — painted its label in the red hover colour on the red accent
   fill: a blank bar, 1:1. Same leak on `.btn-secondary` / `.btn-success`.
   `:active` is covered because a pressed pointer is still hovering; keyboard
   focus never matches `a:hover`, so it keeps the resting `#fff`. */
.btn-primary:hover:not(:disabled) { background: var(--action-fill-hover); border-color: var(--action-fill-hover); color: #fff; }

.btn-secondary {
  background: var(--neutral-700);
  color: #fff;
  border-color: var(--neutral-700);
}
.btn-secondary:hover:not(:disabled) { background: var(--neutral-800); color: #fff; }

.btn-outline {
  background: transparent;
  color: var(--primary);
  border-color: var(--primary);
}
.btn-outline:hover:not(:disabled) { background: var(--primary-bg); }

.btn-danger {
  color: var(--error);
  border-color: transparent;
  background: none;
  padding: 0 var(--space-1);
  font-size: var(--text-md);
}
.btn-danger:hover:not(:disabled) { color: var(--primary-hover); background: var(--error-light); }

.btn-success {
  background: var(--success);
  color: #fff;
  border-color: var(--success);
}
.btn-success:hover:not(:disabled) { background: #1B5E20; color: #fff; }

.btn-lg {
  padding: var(--space-3) var(--space-6);
  font-size: var(--text-md);
  border-radius: var(--radius-md);
}

/* --- Cards --- */
/* Substory #707, item 1. `--radius-md` -> `--radius-lg`, e non è un ritocco:
   `--radius-md` è un alias di `--sim-radius` (12px) e `--radius-lg` di
   `--sim-radius-lg` (18px), che è il raggio che `.sim-card` legge. Prima di
   questa riga il prodotto disegnava DUE schede con due angoli diversi a
   seconda di quale dei due sistemi di componenti avesse dipinto la pagina.
   L'ombra non si tocca: `--shadow-md` è già un alias di `--sim-shadow`
   (riga 304 di design-system.css), quindi le due schede la condividono già. */
.card {
  background: #fff;
  border-radius: var(--radius-lg);
  padding: var(--space-5);
  box-shadow: var(--shadow-md);
  transition: box-shadow var(--transition-base);
}
.card:hover { box-shadow: var(--shadow-lg); }

.card-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: var(--space-3);
}

.card-body {
  color: var(--neutral-700);
}

/* --- Badges --- */
.badge {
  display: inline-block;
  padding: 2px var(--space-2);
  border-radius: var(--radius-full);
  font-size: var(--text-xs);
  font-weight: var(--font-medium);
  line-height: 1.5;
}

.badge-success  { background: var(--success-light); color: var(--success); }
.badge-warning  { background: var(--warning-light); color: #795548; }
/* Substory #707, item 2. L'INCHIOSTRO si sposta, il FONDO no.
   `--error` è un alias di `--sim-red` (#D22B3E), il rosso d'identità, e su
   `--error-light` = `--sim-red-soft` (#FDECEE) misura 4.43:1 — sotto il 4.5
   che WCAG 2.1 SC 1.4.3 chiede a un testo. `--sim-red-ink` (#B02334) esiste
   per questo fondo e lo dice nella sua stessa dichiarazione
   (design-system.css:101, "rosso leggibile su fondo rosa: 5.87 su
   --sim-red-soft"). Il fondo resta rosa perché è l'identità dell'errore:
   spostare il fondo su un neutro supererebbe la soglia lasciando il difetto
   intatto e togliendo alla chip il colore che la fa leggere come errore.
   Stessa correzione su tutte e sei le regole di questo file che portavano la
   coppia: .badge-error (due volte), .validation-error, .modal .modal-error,
   .doc-panel .doc-load-error, .form-status-failed. NON toccato: `--error` su
   fondo neutro (.form-error-message, .modal-field-error, .summary-number.red),
   che misura 5.05:1 su bianco ed è già corretto. */
.badge-error    { background: var(--error-light);   color: var(--sim-red-ink); }
.badge-info     { background: var(--info-light);    color: var(--info); }
.badge-neutral  { background: var(--neutral-200);   color: var(--neutral-700); }

/* Status badge (pill style for cases) */
.status-badge {
  padding: var(--space-1) var(--space-3);
  border-radius: var(--radius-full);
  font-size: var(--text-sm);
  font-weight: var(--font-medium);
}
.status-documents_pending  { background: var(--warning-light); color: #795548; }
.status-documents_complete { background: var(--success-light); color: var(--success); }
.status-under_review       { background: var(--info-light);    color: var(--info); }
.status-created            { background: var(--neutral-200);   color: var(--neutral-700); }

/* --- Forms --- */
.form-group {
  margin-bottom: var(--space-4);
}

.form-label {
  display: block;
  font-size: var(--text-sm);
  font-weight: var(--font-medium);
  color: var(--neutral-700);
  margin-bottom: var(--space-1);
}

/* Substory #707, item 4. `.form-input` e `.form-control` SONO `.sim-input`.
   =======================================================================
   Nessuna delle due ha un consumatore: `.form-control` non compare da nessuna
   parte nel repository — né CSS, né template, né JS — e `.form-input` ha
   una regola e nessuno che la indossi. Il prodotto porta però i due nomi, e
   il primo che li scriverà si aspetta il campo che questo prodotto ha. Quindi
   invece di ammodernare una regola del 2019 la si ripunta sulle dichiarazioni
   di `.sim-input` (design-system.css:625), che è l'unico campo del sistema.

   PERCHÉ LA REGOLA STA QUI E NON NELL'ELENCO DI SELETTORI DI `.sim-input`.
   Due ragioni, e nessuna delle due è di gusto:

     1. ORDINE DI CARICAMENTO. base.html carica `design-system.css` e POI
        `components.css`. Aggiungere `.form-input` all'elenco di `.sim-input`
        lasciando in piedi la vecchia regola qui sotto le darebbe la stessa
        specificità (0,1,0) e la vecchia, essendo più avanti, continuerebbe a
        vincere: un diff che sembra una correzione e non cambia un pixel.
     2. `apps/core/tests/test_beta_substory707_component_retheme_e2e.py`
        ::test_the_probed_classes_are_declared_only_in_components_css pretende
        che queste classi siano dichiarate in UN foglio solo, ed è la
        precondizione che rende valida su ogni pagina una misura presa sulla
        landing. Una seconda dichiarazione in `design-system.css` vincerebbe o
        perderebbe per ordine di caricamento pagina per pagina.

   LE COSTANTI SONO DUPLICATE, E IL CONFRONTO È SORVEGLIATO. 10/13/16/1.3 sono
   scritte anche qui perché `.sim-input` le scrive come numeri e non come
   token, e inventare quattro token nuovi vorrebbe dire riscrivere una regola
   del design system che questa substory non ha in perimetro. La deriva non è
   affidata a questo commento: il test del punto 2 confronta 14 proprietà
   calcolate di `.form-input` e `.form-control` con quelle di `.sim-input` a
   ogni esecuzione della pipeline, e diventa rosso al primo valore che diverge.

   `width: 100%` resta e non è in quel confronto: `.sim-input` dice sopra di
   sé "la larghezza è disposizione, non aspetto", e quella di `.form-input`
   era già lì. */
.form-input,
.form-control {
  width: 100%;
  display: block;
  min-height: var(--sim-tap);
  padding-block: 10px;
  padding-inline: 13px;
  border: 1px solid var(--sim-line-strong);
  border-radius: var(--sim-radius);
  background-color: var(--sim-surface);
  color: var(--sim-ink);
  font-family: var(--sim-font);
  font-size: 16px;
  line-height: 1.3;
}
.form-input::placeholder,
.form-control::placeholder { color: var(--sim-muted); }

/* Substory #707, item 3. L'anello di fuoco del sistema, lo stesso che
   `.sim-btn`, `.sim-input`, `.sim-select`, `.sim-textarea`, `.sim-radio` e
   `.sim-langswitch` dichiarano già — e lo stesso che `.drop-zone` usa già in
   questo stesso file. Quello che c'era prima non era un anello più
   discreto: era `box-shadow: 0 0 0 2px var(--primary-bg)` senza nessun
   `outline`, e `--primary-bg` risolve a `--sim-soft` #F4F5F8, che su un campo
   bianco misura 1.09:1. WCAG 2.2 SC 1.4.11 chiede 3:1 a un indicatore di
   fuoco; `--sim-ink` ne misura 18.55. */
.form-input:focus-visible,
.form-control:focus-visible { outline: 2px solid var(--sim-ink); outline-offset: 2px; }

/* --- Modals --- */
.modal-backdrop {
  display: none;
  position: fixed;
  inset: 0;                         /* Bug #840: was top/left/right/bottom: 0. */
  background: rgba(0, 0, 0, 0.5);
  z-index: 100;
  align-items: center;
  justify-content: center;
}
.modal-backdrop.visible { display: flex; }

.modal {
  background: #fff;
  border-radius: var(--radius-lg);
  padding: var(--space-8);
  width: 90%;
  max-width: 400px;
  position: relative;
}

.modal h2 {
  font-size: var(--text-xl);
  margin-bottom: var(--space-4);
  color: var(--neutral-900);
  font-size: 1.3rem;
}

.modal .close-btn {
  position: absolute;
  top: var(--space-3);
  /* Bug #840: was `right`. The dismiss control belongs in the corner the
     reader's eye ends on, which is the left one in Urdu. */
  inset-inline-end: var(--space-3);
  background: none;
  border: none;
  font-size: 1.5rem;
  cursor: pointer;
  color: var(--neutral-500);
  line-height: 1;
}
.modal .close-btn:hover { color: var(--neutral-900); }

.modal label {
  display: block;
  font-size: var(--text-sm);
  font-weight: var(--font-medium);
  margin-bottom: var(--space-1);
  color: var(--neutral-700);
}

.modal input[type="email"],
.modal input[type="password"],
.modal input[type="text"].password-visible {
  width: 100%;
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--neutral-300);
  border-radius: var(--radius-md);
  font-size: var(--text-md);
  margin-bottom: var(--space-3);
  outline: none;
  font-family: var(--font-family);
}
/* Substory #707, item 3 — lo stesso anello, sulla metà che un cliente incontra
   davvero. Questa regola è la seconda metà della stessa prescrizione scaduta
   di `.form-input:focus`, e il campo che dipinge è quello dell'email nella
   modale di accesso: il primo modulo che la maggior parte dei visitatori vede.
   Il bordo non cambia più colore al fuoco: `--primary` è tornato a essere il
   ROSSO DEL MARCHIO (bug #839) e `.sim-input:focus-visible` non tocca il
   bordo — è l'anello a dire dove sei. */
.modal input:focus-visible { outline: 2px solid var(--sim-ink); outline-offset: 2px; }

/* --- Password Toggle --- */
.password-wrapper {
  position: relative;
}
.password-wrapper input {
  /* Bug #840: the well the toggle sits in, and the toggle below it, are one
     pair — both physical, so in RTL the eye moved to the left of the field
     while the hole stayed on the right and the glyph sat on top of the text. */
  padding-inline-end: 2.5rem;
}
.password-toggle {
  position: absolute;
  inset-inline-end: var(--space-2);
  top: 50%;
  transform: translateY(calc(-50% - var(--space-3) / 2));
  background: none;
  border: none;
  cursor: pointer;
  color: var(--neutral-500);
  font-size: var(--text-md);
  padding: var(--space-1);
  line-height: 1;
  display: flex;
  align-items: center;
}
.password-toggle:hover { color: var(--neutral-800); }

/* Bug #839, e QUI c'è una decisione, non solo un token rinominato.
   Il bottone d'invio di una modale NON prende l'accento: resta l'inchiostro.

   La modale galleggia sopra la pagina, e la pagina sotto continua a essere
   dipinta — l'azione primaria della landing (`#send-btn`) è ancora lì, ancora
   accentata, dietro il velo. Due rossi sullo stesso schermo sono esattamente
   la rarità che questo bug viene a ripristinare, e "uno per schermata" è la
   frase del criterio 1, non "uno per superficie".

   E non serve: una modale ha già un velo, una trappola di fuoco e un solo
   bottone pieno dentro di sé. Ciò che la rende l'unica cosa premibile non è
   il colore, è che ha coperto tutto il resto.

   `test_browser_design.py::test_the_modal_submit_is_the_ink_base_not_the_accent`
   fissa questa decisione contro i valori scritti in ADR-0004, così promuovere
   il submit all'accento diventa un cambio di record e non di foglio di stile. */
.modal .modal-submit {
  width: 100%;
  background: var(--action-fill);
  color: #fff;
  border: none;
  border-radius: var(--radius-md);
  padding: var(--space-3);
  font-size: var(--text-md);
  font-weight: var(--font-medium);
  cursor: pointer;
  transition: background var(--transition-base);
  font-family: var(--font-family);
}
.modal .modal-submit:hover { background: var(--action-fill-hover); }
.modal .modal-submit:disabled { opacity: 0.55; cursor: not-allowed; }

/* Substory #707, item 2 — vedi il commento su `.badge-error`. È l'unica delle
   cinque superfici d'errore con un consumatore renderizzato: è il messaggio
   che un accesso fallito mette sullo schermo. */
.modal .modal-error {
  background: var(--error-light);
  color: var(--sim-red-ink);
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-md);
  font-size: var(--text-sm);
  margin-bottom: var(--space-3);
  display: none;
}

.modal .modal-success {
  background: var(--success-light);
  color: var(--success);
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-md);
  font-size: var(--text-sm);
  margin-bottom: var(--space-3);
  display: none;
}

/* --- Inline field validation (bug #825) ---
 *
 * The page's replacement for the browser's constraint-validation bubble. The
 * bubble was browser chrome: outside the DOM, unstyleable, and written in the
 * browser's UI locale rather than the page's. These sit under the field they
 * are about, in the page's own language.
 *
 * `display: none` while empty so nothing shifts on first paint, and so the
 * probe in apps/accounts/tests/test_beta_bug825_auth_language_e2e.py counts
 * only messages a person can actually read; the handler sets `display: block`
 * together with the text.
 *
 * LOGICAL PROPERTIES ONLY, here and in .field-help. Urdu is RTL, and a
 * `margin-left` would survive every LTR review and then detach the message
 * from its field on /ur/ — which is what
 * test_the_urdu_helper_line_fits_and_mirrors measures, by comparing the
 * helper's inline-start edge with the input's.
 *
 * The negative block-start margin pulls each line up against the input, whose
 * own `margin-bottom: var(--space-3)` would otherwise leave the message
 * floating between two fields with nothing saying which it belongs to.
 */
.modal-field-error {
  display: none;
  color: var(--error);
  font-size: var(--text-sm);
  line-height: 1.4;
  margin-block: calc(var(--space-2) * -1) var(--space-3);
  margin-inline: 0;
  padding-inline: 0;
  text-align: start;
}

.modal input[aria-invalid="true"],
.auth-form input[aria-invalid="true"] {
  border-color: var(--error);
}

/* The password rule, stated before the first keystroke and kept on screen
 * while the person types. `.field-help--met` is the live check the issue asks
 * for; it changes the colour only — the sentence itself is swapped through
 * gettext() by the handler, so the state is readable and not merely green. */
.field-help {
  color: var(--neutral-700);
  font-size: var(--text-sm);
  line-height: 1.4;
  margin-block: calc(var(--space-2) * -1) var(--space-3);
  margin-inline: 0;
  padding-inline: 0;
  text-align: start;
}
.field-help--met { color: var(--success); }

.modal .modal-link {
  text-align: center;
  font-size: var(--text-sm);
  margin-top: var(--space-3);
}
.modal .modal-link a { color: var(--primary); cursor: pointer; }
.modal .modal-link a:hover { text-decoration: underline; }

/* --- Progress Bars --- */
.progress-bar {
  height: 8px;
  background: var(--neutral-300);
  border-radius: var(--radius-sm);
  overflow: hidden;
  margin: var(--space-2) 0;
}


.progress-fill {
  height: 100%;
  background: var(--success);
  border-radius: inherit;
  transition: width 0.3s ease;
}

.progress-text {
  font-size: var(--text-sm);
  color: var(--neutral-600);
}

/* --- Summary Bar ---
   DELETED by bug #1131, with `.summary-item`, `.summary-number`,
   `.summary-label` and `.summary-item-link`. The four stat cards above the
   Documenti section (Totale / Collegati / Mancanti / Avvisi) were the reason
   the section started at y=708 on a 390x844 phone; #1131 takes them off the
   screen and the counter card below answers the one question they did not.
   The number the "Mancanti" card carried (`data-missing-count`) is now on the
   card's primary action. */

/* --- The Documenti section (substory #711; bug #1131) ---
   The screen `MobileDocs.dc.html` draws, on the design-system layer: one
   counter card, then each group as a `.sim-group-head` label over ONE
   `.sim-card--list` of compact rows, directly on the page background — no
   wrapper card around the groups and no grey box per person (#1131, item 6).

   #775's SIZE BUDGET IS INHERITED, not discarded: at 390x844 the card, the
   MANCANTI heading and the first missing row must all clear the fold. That is
   why the card is dense and why a row is one line.

   What is left here is where a thing sits in the page and the parts of the row
   no component knows about. Surfaces, buttons, headings and their states are
   component classes on the elements. */
.documenti {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  margin-bottom: var(--space-5);
}

/* THE CARD. Per person: the count still needed, drawn large, with its
   sentence beside it; then one progress bar and the one primary action. */
.documenti-card {
  display: flex;
  flex-direction: column;
  gap: 14px;
  padding: 18px 20px;
}

.documenti-counters {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.documenti-counter {
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

/* The person is the quiet half and the number is the loud one. */
.documenti-counter-person {
  font-size: var(--text-xs);
  color: var(--sim-muted);
  overflow-wrap: anywhere;
}

.documenti-counter-value {
  font-size: var(--text-sm);
  font-weight: var(--font-semibold);
  color: var(--sim-ink);
  line-height: 1.3;
}

/* The artboard's 34px/700. Baseline-aligned inside the sentence, so the
   number and the words beside it read as one line in every word order. */
.documenti-counter-number {
  font-size: 34px;
  font-weight: 700;
  line-height: 1;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
  margin-inline-end: 6px;
}
.documenti-counter-number:empty { display: none; }

.documenti-progress {
  height: 6px;
  border-radius: 3px;
  background: var(--sim-line);
  overflow: hidden;
}
.documenti-progress-fill {
  height: 100%;
  border-radius: inherit;
  background: var(--sim-ok);
}

/* "Carica i N che mancano": full width, 46px, the `+` the artboard draws. The
   plus is a mask over `currentColor` rather than an inline <svg>: bug #764
   reads the first integer INSIDE this link as the missing count, and an
   <svg viewBox="0 0 16 16"> in front of the words would be read first. */
.documenti-go {
  min-height: 46px;
  text-decoration: none;
}
.documenti-go::before {
  content: '';
  flex: none;
  width: 16px;
  height: 16px;
  background: currentColor;
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M8 2v12M2 8h12' stroke='black' stroke-width='2' stroke-linecap='round'/%3E%3C/svg%3E") center / contain no-repeat;
          mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M8 2v12M2 8h12' stroke='black' stroke-width='2' stroke-linecap='round'/%3E%3C/svg%3E") center / contain no-repeat;
}

.documenti-complete {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: var(--space-3);
}
.documenti-complete-text { margin: 0; }
.documenti-next { flex: 0 0 auto; text-decoration: none; }

.documenti-empty {
  margin: 0;
  font-size: var(--text-sm);
  color: var(--sim-muted);
}

/* --- A group ---
   The heading is `.sim-group-head` (design-system.css); the rows share one
   `.sim-card--list`. The MANCANTI group is the link target of the card's
   action, so it clears the sticky nav when the browser scrolls to it. */
.documenti-group { margin: 0; scroll-margin-top: calc(var(--sim-tap) + 24px); }
.documenti-group > .documenti-group-heading { margin: 0; }

/* --- The row (bug #1131: one compact line) ---
   leading icon · name and meta · trailing control. The row stays
   `.checklist-item` (bug #764 slices the page on it); these rules replace
   that class's padding and its phone `flex-direction: column`, which is what
   put the status chip on a line of its own. (0,2,0) so they win on the
   cascade's own terms, whatever the load order (#767). */
.checklist-item.doc-row,
.doc-row {
  display: flex;
  flex-direction: row;
  align-items: flex-start;
  gap: 12px;
  /* Logical (bug #1424): the 16px indent is the leading side's, in RTL too. */
  padding-block: 12px;
  padding-inline: 16px 12px;
  border-bottom: 0;
  position: relative;
}
/* The hairline between rows, indented past the leading icon as drawn. */
.doc-row + .doc-row { border-top: 0; }
.doc-row + .doc-row::before {
  content: '';
  position: absolute;
  inset-block-start: 0;
  inset-inline-start: 52px;
  inset-inline-end: 0;
  height: 1px;
  background: var(--sim-line);
}
/* ...and under a row with no leading icon, the hairline starts where its name
   does. */
.doc-row + .doc-row.doc-row--missing::before { inset-inline-start: 16px; }
/* A document still owed is tinted, as drawn, and says who needs it in red. */
.doc-row--missing[data-doc-row-required="true"],
.doc-row--failed { background: var(--sim-red-soft); }
.doc-row--missing[data-doc-row-required="true"] .doc-row-meta,
.doc-row--failed .doc-row-meta { color: var(--sim-red-ink); }
/* Bug #1375: a flagged document is owed too, tinted in the warning's own
   colour; its `.validation-msg` says why. */
.doc-row--needs_review { background: var(--sim-warn-soft); }
/* The card's rounded corners, carried by the first and last row's tint:
   `.sim-card--list` does not clip (a ⋮ menu has to be able to leave it). */
.sim-card--list > .doc-row:first-child { border-start-start-radius: inherit; border-start-end-radius: inherit; }
.sim-card--list > .doc-row:last-child { border-end-start-radius: inherit; border-end-end-radius: inherit; }

/* The leading slot. Always 24px wide, drawn or not, so every name in a card
   starts on one column. Its top is the name's top: the icon is on the name's
   line (#1131: "no row carries a chip on its own line"). */
.doc-row-icon {
  flex: none;
  width: 24px;
  height: 20px;
  margin-block-start: 2px;
  display: flex;
  align-items: center;
  justify-content: flex-start;
}
/* A missing row draws no leading icon (#1131: "missing — (no leading icon) ·
   name · which programme requires it · Carica"). The slot collapses and the
   gap after it is taken back, so the name gets the width; the element stays,
   carrying its state word for a screen reader and `status-required` for
   bug #764. */
.doc-row--missing > .doc-row-icon { width: 0; margin-inline-end: -12px; overflow: hidden; }
.doc-row-glyph { width: 20px; height: 20px; }
.doc-row-glyph circle { fill: currentColor; }
.doc-row-glyph__mark {
  fill: none;
  stroke: var(--sim-surface);
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.status-linked .doc-row-glyph { color: var(--sim-ok); }
.status-warning .doc-row-glyph { color: var(--sim-warn); }
.status-failed .doc-row-glyph { color: var(--sim-red); }
.doc-row-glyph--spin { animation: doc-row-spin 1s linear infinite; }
.doc-row-glyph--spin .doc-row-glyph__track {
  fill: none; stroke: var(--sim-line-strong); stroke-width: 2.5;
}
.doc-row-glyph--spin .doc-row-glyph__arc {
  fill: none; stroke: var(--sim-ink-2); stroke-width: 2.5; stroke-linecap: round;
}
@keyframes doc-row-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  .doc-row-glyph--spin { animation: none; }
}

.doc-row-body {
  flex: 1 1 auto;
  min-width: 0;
  min-height: var(--sim-tap);
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 4px;
}
/* The name and the meta line: the row's link when a document is attached
   (`.sim-btn--row`), a plain block otherwise. */
.doc-row-open {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}
.doc-row-name {
  font-size: var(--text-sm);
  font-weight: var(--font-semibold);
  line-height: 20px;
  color: var(--sim-ink);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.doc-row-person { font-weight: 400; color: var(--sim-muted); }
/* ONE line with an ellipsis, never wrapped mid-word (#1131, item 4). Never
   `text-transform`ed: it carries the customer's own file name. */
.doc-row-meta {
  font-size: var(--text-xs);
  line-height: 18px;
  color: var(--sim-muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* ...except the failed row's, which is WHY in words plus the support
   reference: an ellipsis there would cut off the one thing the customer has
   to quote (CLAUDE.md). #711's body wins over the artboard here. */
.doc-row--failed .doc-row-meta {
  white-space: normal;
  overflow: visible;
  overflow-wrap: anywhere;
}
.doc-row-note {
  font-size: var(--text-xs);
  margin-top: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.doc-row-flags .item-badge { margin-inline-start: 0; }

/* `.doc-row > .doc-row-actions` and not the bare class: the element is also
   `.item-actions` (#777's named-control selector), whose `margin-top` sits
   later in this file at the same (0,1,0) and would push the control 8px below
   the row's middle -- and the row 8px taller -- on load order alone (#767). */
.doc-row > .doc-row-actions {
  flex: none;
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin: 0;
  align-self: center;
}
.doc-row-upload { flex: 0 0 auto; }
.doc-row-retry { flex: 0 0 auto; }

.doc-row-assign {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  flex-wrap: wrap;
  margin-top: var(--space-1);
}

/* --- RIMUOVI STOPS BEING THE LOUDEST THING ON SCREEN (audit id SI-083) ---
   A `<details>`, not a scripted popover: a closed `<details>` does not render
   its contents, so "the destructive control is not on screen" is a fact about
   the DOM. The toggle is `.sim-btn--icon` on its own (bug #1131): no fill, no
   border, an SVG in the secondary ink.

   The items float BELOW the toggle, anchored to its end edge, rather than in
   flow: in flow they would widen the trailing column and squeeze the name to
   nothing. The group card is `.sim-card--list`, which does not clip, so the
   menu of the last row can leave the card. An open menu is lifted above the
   rows after it. Logical properties throughout, for Urdu (#840). */
.doc-row-menu { flex: none; position: relative; }
.doc-row-menu[open] { z-index: 5; }
.doc-row-menu-toggle { list-style: none; }
.doc-row-menu-toggle::-webkit-details-marker { display: none; }
.doc-row-menu-toggle::marker { content: ''; }
.doc-row-menu-glyph { width: 20px; height: 20px; fill: currentColor; }
.doc-row-menu-items {
  position: absolute;
  inset-block-start: calc(100% + 4px);
  inset-inline-end: 0;
  min-inline-size: 220px;
  max-inline-size: min(320px, calc(100vw - 2 * var(--space-4)));
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  padding: var(--space-2);
  border: 1px solid var(--sim-line);
  border-radius: var(--sim-radius-sm);
  background: var(--sim-surface);
  box-shadow: var(--sim-shadow);
}
.doc-row-menu-doc {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}
.doc-row-menu-doc + .doc-row-menu-doc {
  padding-top: var(--space-1);
  border-top: 1px solid var(--sim-line);
}
.doc-row-menu-open { justify-content: flex-start; overflow-wrap: anywhere; }

/* Bug #1123, Step 3. Text a person or the model wrote, shown inside chrome
   that may be RTL, takes its paragraph direction from its own content -- the
   same rule as the chat bubble (`.msg` in pages/chat.css, which has the full
   reasoning). Measured at /ur/ before this: a field value "Toronto, ON."
   rendered ".Toronto, ON", a file named "(1) passport.pdf" rendered
   "passport.pdf (1)". `plaintext` rather than `dir="auto"` for the bubble's
   reason: it reorders the text and leaves `direction` -- and so every logical
   margin, padding and alignment around it -- the page's.

   Only elements that hold NOTHING BUT that text are listed: a checklist field
   value (`.app-field-text`, server- and script-rendered in
   templates/documents/checklist.html), the file name on a requirement's menu
   (`.doc-row-menu-open`, templates/documents/_documenti_row.html) and on the
   chat's document card (`.doc-name`, static/chat/doc-panel-view.js). A line
   that composes a file name into a translated sentence (`.doc-row-meta`) is
   not, because `plaintext` would let the file name decide the direction of
   the page's own sentence -- except the complete and needs_review meta lines,
   which are only `[label ·] file name` (#1424, rule below).
   apps/chat/tests/test_bug1123_bidi_plaintext_rules.py pins this list. */
.app-field-text,
.doc-row-menu-open,
.doc-name {
  unicode-bidi: plaintext;
}

/* Bug #1424. A one-line ellipsis is drawn at the END of the line's direction,
   and in an RTL page that is the left: a Latin title or file name that did
   not fit lost its START ("...of Funds", "…from-phone-camera.jpg", measured
   at /ur/ 390 px). `plaintext` gives each of these lines the direction of its
   own first strong character, so Latin text is cut at its right end and Urdu
   at its left. `match-parent` keeps the alignment the page's: a short Latin
   title still starts on the column the Urdu ones start on (#1131). Chromium
   parses only the prefixed spelling, so both are given.

   The row's name (the requirement's or the field's label, plus the person),
   the upload progress line's file name, and the meta line of a complete or a
   flagged row -- which is the file name, preceded only by what we read it as
   when that differs (`documenti_panel._meta_line`), so the page's own words
   still come first when there are any. Every other state's meta line is a
   translated sentence and stays out (#1123). */
.doc-row-name,
.doc-row--complete .doc-row-meta,
.doc-row--needs_review .doc-row-meta,
.upload-file-name {
  unicode-bidi: plaintext;
  text-align: match-parent;
  text-align: -webkit-match-parent;
}

/* Substory #777, second round, carried over: below 760px the design system
   says `.sim-btn { width: 100% }`, and a trailing control that claims the
   whole line collapses the row's text (measured once at 630px per row). Each
   selector names the parent the control actually has, at (0,2,0). */
@media (max-width: 760px) {
  .doc-row-actions > .doc-row-upload { width: auto; }
  .doc-row-actions > .doc-row-retry { width: auto; }
  .doc-row-actions > .doc-row-confirm { width: auto; }
}

/* Bug #1418: on a phone, a row whose text WRAPS puts its actions under it.
   #1131's one line works while the body is one line with an ellipsis; a
   flagged row (`needs_review`: its `.validation-msg` paragraphs, plus
   Sostituisci and Il documento è corretto) and a failed row (the reason and
   the support reference, plus Riprova) have text that wraps, and beside
   `flex: none` actions it wrapped into what was left -- 16px, one word per
   line, measured at 390x844 with the name cut to nothing and the buttons
   pushing the page sideways. Here the row wraps: icon and body share the
   first line (`flex-basis: 0`, or the body's max-content would send it to a
   line of its own), the actions take a line of their own under the text,
   indented to the text's column (the 24px icon slot + the row's 12px gap)
   and wrapping if they do not fit. The ⋮ keeps the row's inline end, where
   it is on every other row: its menu floats from the toggle's inline end at
   220px or more, and a toggle left in the text column (x~212 on a failed
   row at 390) opened it off the screen's inline start. The name and the
   file name wrap instead of being cut. Every other row keeps the compact
   line #1131 pinned. */
@media (max-width: 760px) {
  .doc-row.doc-row--needs_review,
  .doc-row.doc-row--failed { flex-wrap: wrap; }
  .doc-row--needs_review > .doc-row-body,
  .doc-row--failed > .doc-row-body { flex: 1 1 0; }
  .doc-row.doc-row--needs_review > .doc-row-actions,
  .doc-row.doc-row--failed > .doc-row-actions {
    flex: 1 0 100%;
    flex-wrap: wrap;
    padding-inline-start: 36px;
  }
  .doc-row--needs_review > .doc-row-actions > .doc-row-menu,
  .doc-row--failed > .doc-row-actions > .doc-row-menu { margin-inline-start: auto; }
  .doc-row--needs_review .doc-row-name,
  .doc-row--failed .doc-row-name,
  .doc-row--needs_review .doc-row-meta {
    white-space: normal;
    overflow: visible;
    overflow-wrap: anywhere;
  }
}

/* --- Status marks (checklist) ---
   Bug #1131: the mark is the row's leading icon (`.doc-row-icon` above), with
   its word as the accessible name, rather than #777's chip on a line of its
   own. The classes `status-icon`, `status-linked`, `status-warning`,
   `status-required`, `status-failed`, `status-processing` and
   `status-optional` stay on the element as hooks: bug #764 counts
   `.status-icon.status-required`, and the beta gates read a row's state
   through them. A class without a rule is a contract.

   `.status-icon` itself keeps its rule: substory #707's census
   (`test_every_legacy_component_class_is_still_declared`) holds every
   component class declared before the retheme, and a removal is a separate
   decision with its own migration. On the row it agrees with `.doc-row-icon`'s
   `flex: none`, so the leading slot never shrinks under a long name. */
.status-icon { flex-shrink: 0; }

/* --- Validation Messages --- */
.validation-msg {
  font-size: var(--text-xs);
  margin-top: var(--space-1);
  padding: var(--space-1) var(--space-2);
  border-radius: var(--radius-sm);
}
.validation-warning { background: var(--warning-light); color: #795548; }
/* Substory #707, item 2 — vedi il commento su `.badge-error`. */
.validation-error   { background: var(--error-light);   color: var(--sim-red-ink); }
.validation-valid   { background: var(--success-light); color: var(--success); }

/* --- Document Panel (chat sidebar) --- */
.doc-panel {
  width: 240px;
  background: #fff;
  border-radius: var(--radius-lg);
  padding: var(--space-4);
  max-height: 60vh;
  overflow-y: auto;
  flex-shrink: 0;
  box-shadow: var(--shadow-md);
}
.doc-panel h3 {
  font-size: var(--text-sm);
  color: var(--primary);
  margin-bottom: var(--space-3);
  text-transform: uppercase;
  letter-spacing: 0.05em;
}
.doc-panel .doc-item {
  padding: var(--space-2);
  border-radius: var(--radius-md);
  margin-bottom: var(--space-2);
  background: var(--neutral-50);
  border: 1px solid var(--neutral-200);
}
.doc-item .doc-name {
  font-size: var(--text-sm);
  font-weight: var(--font-medium);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.doc-item .doc-badge {
  display: inline-block;
  font-size: var(--text-xs);
  padding: 0.15rem 0.4rem;
  border-radius: var(--radius-sm);
  margin-top: var(--space-1);
  font-weight: var(--font-semibold);
}
/* Substory #804 asks for these to be "restyled with .sim-chip--pending /
   --done / --missing", and its Definition of Done keeps renderDocPanel() —
   which writes `processing` / `classified` / `failed` onto the badges —
   unchanged. So the restyle is a CSS one: the three rules point at the same
   design-system tokens the three chips use (design-system.css:129-131), rather
   than the chips being moved to meet the badges.

   What actually changed is the two foreground colours that predate the design
   system. `--warning-light` and `--error-light` are already aliases of
   `--sim-warn-soft` and `--sim-red-soft`, so the backgrounds were the chips'
   backgrounds all along and `classified` matched `.sim-chip--done` exactly.
   The text did not: `#795548` was a hand-written brown, and `--error`
   (`#D22B3E`, the identity red) is not the ink the chip uses — `--sim-red-ink`
   (`#B02334`) was chosen for 5.87:1 on the pink ground it sits on, which
   `--error` does not reach.

   Tokens, not hex: the gate reads both colours off the live page and compares
   the badge to the chip, so copying a literal here would pass today and drift
   at the next palette change.

   Bug #765: the amber pair needed the same treatment the red pair already had.
   `--sim-warn` on `--sim-warn-soft` measures 4.21, below the 4.5 minimum, so
   `processing` moves to `--sim-warn-ink` (5.13 on that ground). Changed here
   and on `.sim-chip--pending` (design-system.css:166) in the same commit: the
   assertion at test_beta_substory804_mobile_documents_e2e.py:1793 requires the
   badge and the chip to render identically, so the pair only moves together. */
.doc-badge.processing { background: var(--sim-warn-soft); color: var(--sim-warn-ink); }
.doc-badge.classified { background: var(--sim-ok-soft);   color: var(--sim-ok); }
.doc-badge.failed     { background: var(--sim-red-soft);  color: var(--sim-red-ink); }

/* Bug #826 — a card that is no longer a dead end.

   Four additions, all INSIDE .doc-item so they inherit the one presentation
   #804 settled: the same #doc-list is the desktop sidebar's body and the mobile
   sheet's body, and nothing here asks which it is. There is no media query in
   this block on purpose — a second breakpoint would be a second source of truth
   about the same card.

   Logical properties throughout (`margin-inline-start`, not `margin-left`). The
   issue asks for it by name — "Urdu RTL via logical properties" — and the panel
   is one of the places a physical margin shows: in `ur` the elapsed counter
   sits to the LEFT of the badge, and `margin-left` would push it away from the
   badge instead of towards it. */

/* The seconds counter beside the processing badge. Tabular figures so the
   number does not jitter sideways once a second as the digits change width,
   which on a 240px sidebar is the whole card twitching. */
.doc-item .doc-elapsed {
  display: inline-block;
  margin-inline-start: var(--space-2);
  font-size: var(--text-xs);
  font-variant-numeric: tabular-nums;
  color: var(--neutral-500);
}

/* "Usually under a minute" — the expectation the issue asks for. It is what
   turns a 40-second wait into a process rather than a hang. */
.doc-item .doc-hint {
  margin-top: var(--space-1);
  font-size: var(--text-xs);
  color: var(--neutral-500);
}

/* The reason a failed card finally carries. Deliberately not red: the badge
   above it is already the alarm, and a second red block for one failure reads
   as two problems. This line is the INSTRUCTION, so it is ordinary readable
   text. */
.doc-item .doc-reason {
  margin-top: var(--space-1);
  font-size: var(--text-sm);
  color: var(--neutral-700);
}

/* Retry and Remove.

   `flex-wrap: wrap` is the issue's "buttons wrap under the name at 390px". Both
   controls are `.sim-btn`s, so each is at least `--sim-tap` (44px) tall and
   carries its own padding; at 390px inside the bottom sheet two of them do not
   fit on one line, and without wrapping the second would be pushed out of the
   card rather than under it. */
.doc-item .doc-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin-top: var(--space-2);
}

/* A narrower, smaller-text variant of `.sim-btn` for a control that lives
   inside a 240px card. The HEIGHT is untouched, because that is the tap target
   the design system declares and the one the issue names (44px); only the
   horizontal padding and the label size come down. */
.doc-item .doc-action {
  padding-inline: var(--space-3);
  font-size: var(--text-sm);
}

/* Substory #711, audit id SI-083 — the card's `⋮` and the box it opens.

   `Rimuovi` was a full-width `sim-btn--danger` on every card: measured on beta
   at 340px wide in a 390px viewport, which is the loudest thing on a card
   whose useful action is opening the document. It is an item in here now.

   A `<details>`, so a closed menu renders NO contents at all — "the
   destructive control is not on screen" is then a fact about the DOM rather
   than a rule a later stylesheet can outrank. The marker is removed in both
   spellings, or the summary paints a disclosure triangle beside the three dots
   and reads as two controls.

   The box is IN FLOW, not absolutely positioned: `#doc-list` is a scroll
   container in the desktop sidebar and the body of a bottom sheet on a phone,
   and an absolutely positioned menu in either has its bottom half clipped.
   Logical properties throughout, as everywhere else in this block — the
   product ships Urdu. */
.doc-item .doc-menu { position: relative; }
.doc-item .doc-menu__toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-inline-size: var(--sim-tap, 44px);
  cursor: pointer;
  list-style: none;
}
.doc-item .doc-menu__toggle::-webkit-details-marker { display: none; }
.doc-item .doc-menu__toggle::marker { content: ''; }
.doc-item .doc-menu__items {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  margin-block-start: var(--space-1);
  padding: var(--space-2);
  border: 1px solid var(--sim-line, #E3E7EC);
  border-radius: var(--sim-radius-sm, 9px);
  background: var(--sim-surface, #fff);
  box-shadow: var(--shadow-md);
}

.doc-panel .no-docs {
  font-size: var(--text-sm);
  color: var(--neutral-500);
  font-style: italic;
}
/* Substory #707, item 2 — vedi il commento su `.badge-error`. */
.doc-panel .doc-load-error {
  font-size: var(--text-sm);
  color: var(--sim-red-ink);
  background: var(--error-light);
  padding: var(--space-2);
  border-radius: var(--radius-sm);
  margin-bottom: var(--space-2);
}

/* --- Upload Elements --- */
.upload-input { display: none; }

.upload-progress {
  padding: var(--space-2) var(--space-4);
  font-size: var(--text-sm);
  color: var(--primary);
}
.upload-progress .file-item {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-1) 0;
}
.upload-progress .spinner {
  width: 14px; height: 14px;
  border: 2px solid var(--neutral-300);
  border-top-color: var(--primary);
  border-radius: 50%;
  animation: spin 0.8s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* --- Drop Overlay --- */
.drop-overlay {
  display: none;
  position: absolute;
  inset: 0;                         /* Bug #840: was top/left/right/bottom: 0. */
  /* Bug #839: era `rgba(183, 28, 28, 0.08)`, cioè il vecchio #B71C1C all'8%,
     dentro un bordo che ora risolve a #D22B3E — due rossi diversi nello stesso
     riquadro. Il proprietario del valore è `--sim-red` (design-system.css:99);
     qui va ripetuto in cifre perché `rgba()` non accetta un token esadecimale
     come primi tre argomenti, e un token dedicato per un solo chiamante
     costerebbe più di quanto renda. Se `--sim-red` cambia, cambia anche questa
     riga. Non è `--sim-red-soft`: quello è opaco e coprirebbe la zona di
     rilascio, mentre questo è un velo trasparente sopra il contenuto. */
  background: rgba(210, 43, 62, 0.08);
  border: 3px dashed var(--primary);
  border-radius: var(--radius-lg);
  z-index: 10;
  align-items: center;
  justify-content: center;
  font-size: 1.2rem;
  /* Stessa specie del difetto di `.drop-zone-icon` qui sotto, e nessun test lo
     vede: per farlo comparire serve un trascinamento con file veri sulla
     landing. `--primary` è passato all'accento, e questo testo cade sul velo
     dichiarato sopra — l'8% di `#D22B3E` su `.messages` (bianco, chat.css:118)
     compone `#FBEEF0`. Misurato: `#D22B3E` su `#FBEEF0` dà 4.47:1, sotto il
     4.5:1. Approfondire il velo peggiora le cose (al 12% si scende a 4.22:1),
     quindi si sposta il primo piano: `--sim-red-ink` `#B02334` su `#FBEEF0` dà
     5.93:1. Il bordo tratteggiato resta `--primary`: non è testo, e a 4.47:1 è
     sopra il 3:1 che WCAG 1.4.11 chiede a un elemento non testuale. */
  color: var(--sim-red-ink);
  font-weight: var(--font-semibold);
  pointer-events: none;
}
.drop-overlay.visible { display: flex; }

/* --- Linked Documents (checklist) ---
   DELETED by bug #1131: `.linked-docs` / `.linked-doc` held each attached
   file as a bordered `.sim-docbar` link beside its own ⋮. The row itself now
   opens its document and names it on the meta line, and the other documents
   of a requirement are in the row's ⋮ (`.doc-row-menu-doc`). */

/* --- Item Content (checklist) --- */
.item-content { flex: 1; }
.item-name { font-weight: var(--font-semibold); font-size: var(--text-base); }
.item-notes { font-size: var(--text-sm); color: var(--neutral-600); margin-top: var(--space-1); }
.item-badge {
  display: inline-block;
  padding: 2px var(--space-2);
  border-radius: var(--radius-full);
  font-size: var(--text-xs);
  font-weight: var(--font-medium);
  /* Bug #840. `margin-inline-start` rather than `margin-left`, which is what
     let `[dir="rtl"] .item-badge { margin-left: 0; margin-right: 8px }` in
     base.css be deleted outright: `--space-2` IS 8px, so that override was this
     declaration mirrored by hand, maintained in a second file forever. */
  margin-inline-start: var(--space-2);
}
.badge-mandatory   { background: var(--neutral-200);   color: var(--neutral-700); }
.badge-optional    { background: var(--warning-light); color: #795548; }
.badge-translation { background: var(--info-light);    color: var(--info); }

.badge-auto-matched { background: var(--success-light); color: var(--success); }

.item-actions {
  display: flex;
  gap: var(--space-2);
  margin-top: var(--space-2);
}

/* --- Drop Zone (checklist) --- */
.drop-zone {
  border: 2px dashed var(--primary);
  border-radius: var(--radius-lg);
  padding: var(--space-8) var(--space-5);
  text-align: center;
  margin-bottom: var(--space-5);
  background: var(--primary-bg);
  transition: background var(--transition-fast), border-color var(--transition-fast);
  cursor: pointer;
}
/* Substory #778. La drop zone dichiarava una transizione su `background` e
   `border-color` dal primo giorno e non aveva NIENTE che li cambiasse: un
   `cursor: pointer` sopra un'area che non rispondeva né al mouse né alla
   tastiera. Non è una `.sim-*` e i suoi stati stanno qui accanto a lei: il
   passo 7 chiede che non stiano sulla PAGINA, e `components.css` è condiviso —
   una seconda pagina con una drop zone li eredita.

   L'ORDINE È ASSERTIVO. Queste regole stanno PRIMA di `.drop-zone.drag-over`
   perché `:hover` e `.drag-over` hanno la stessa specificità (0,2,0) e durante
   un trascinamento il puntatore è per forza sopra la zona: invertite, l'hover
   vincerebbe per ordine di sorgente e cancellerebbe proprio il segnale che dice
   "lascia qui" — l'unico stato che questo elemento già aveva.

   Il fondo va a `--sim-line` e non a `--sim-soft`: `--sim-soft` è il fondo a
   riposo (`--primary-bg` ne è l'alias), quindi sarebbe un hover che non cambia
   niente, cioè la specie di regola che il gate di #778 chiama "dichiarata e non
   dipinta". Il bordo non si tocca: a riposo è già `--sim-ink`, il più scuro che
   il sistema ha, e qualunque cosa gli si faccia lo indebolisce.

   L'anello di fuoco è quello del sistema (2px `--sim-ink`). Questa è una delle
   due sole fermate di tabulazione della pagina che non ne dichiarava nessuno: un
   `role="region" tabindex="0"` che un utente da tastiera raggiungeva senza che
   niente glielo dicesse, se non l'anello di default di Chromium, che non è
   nostro e non è nel nostro inchiostro. */
.drop-zone:hover { background: var(--sim-line); }
.drop-zone:active { box-shadow: var(--sim-press); }
.drop-zone:focus-visible { outline: 2px solid var(--sim-ink); outline-offset: 2px; }
/* Substory #777. Era `#FFCDD2` — Material Red 100, rimasto dalla palette che
   PR #768 ha sostituito — e sotto ci stanno `.drop-zone-text` e
   `.drop-zone-hint`, entrambi `--sim-muted`: misurato, 4.03:1, sotto il 4.5:1
   che la storia richiede. Il gate di #765 non lo vede perché per entrare in
   questo stato serve un trascinamento. `--sim-red-soft` è il rosa del design
   system e dà 4.97 con lo stesso inchiostro. */
.drop-zone.drag-over {
  background: var(--sim-red-soft);
  border-color: var(--primary-hover);
}
/* Bug #839, secondo giro. Questa riga non è cambiata: è cambiato `--primary`
   sotto di lei, da `--sim-ink` a `--sim-accent`. L'icona è testo (36px), e il
   fondo su cui cade durante il trascinamento è `--sim-red-soft` della regola
   qui sopra — rosso su rosa. Misurato (WCAG 2.1, calcolato di nuovo qui e non
   copiato): `#D22B3E` su `#FDECEE` dà 4.43:1, sotto il 4.5:1 che #767 richiede,
   ed è il gate che ha fermato la pipeline su db6b68d5. Non è l'unico stato in
   difficoltà: sull'hover (`--sim-line` `#E3E7EC`, riga 876) l'accento dà 4.07:1.
   A riposo (`--primary-bg` `#F4F5F8`) dava 4.64:1, appena sopra.

   Il rimedio è il PRIMO PIANO, non il fondo: `.drop-zone.drag-over` è di #777,
   il suo `--sim-red-soft` è misurato e documentato lì, e questo bug non c'entra
   con lui. `--sim-red-ink` `#B02334` è la risposta che il sistema aveva già
   (design-system.css:101, "rosso leggibile su fondo rosa"). Misurato: 5.87:1 su
   `--sim-red-soft`, 5.39:1 su `--sim-line`, 6.14:1 su `--primary-bg`. Tutti e
   tre gli stati passano, non solo quello che il test guarda.

   Nota (#848): l'emoji `&#128196;` che `.drop-zone-icon` conteneva è stata
   rimossa e l'elemento non è più nel markup. La regola resta perché
   test_beta_bug839_accent_e2e.py legge il `color` calcolato di questa regola
   CSS (la sonda di contrasto), e varrebbe davvero se qui tornasse un'icona
   vettoriale con `currentColor`. Il difetto gemello di `.drop-overlay` è invece
   testo vero. */
.drop-zone-icon { font-size: 2.25rem; margin-bottom: var(--space-2); color: var(--sim-red-ink); }
.drop-zone-text { font-size: var(--text-base); color: var(--neutral-600); margin-bottom: var(--space-3); }
.drop-zone-hint { font-size: var(--text-xs); color: var(--neutral-500); }
/* Substory #1257 Step 6: the collection notice inside the upload area. */
.drop-zone-notice { margin-block: var(--space-2) 0; }
.drop-zone-actions { display: flex; gap: var(--space-3); justify-content: center; margin-top: var(--space-3); }

/* --- Upload Progress List (checklist) --- */
.upload-progress-list { margin-bottom: var(--space-5); }
.upload-progress-item {
  background: #fff;
  border-radius: var(--radius-md);
  padding: var(--space-2) var(--space-4);
  margin-bottom: var(--space-2);
  box-shadow: var(--shadow-sm);
  display: flex;
  align-items: center;
  gap: var(--space-3);
}
.upload-file-name { flex: 1; font-size: var(--text-sm); font-weight: var(--font-medium); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.upload-file-size { font-size: var(--text-xs); color: var(--neutral-500); flex-shrink: 0; }
.upload-status-badge {
  display: inline-block;
  padding: 2px var(--space-2);
  border-radius: var(--radius-full);
  font-size: var(--text-xs);
  font-weight: var(--font-medium);
  flex-shrink: 0;
}
.badge-uploading  { background: var(--info-light);    color: var(--info); }
.badge-done       { background: var(--success-light); color: var(--success); }
/* Substory #707, item 2 — vedi il commento sulla prima `.badge-error`. Questa
   è la SECONDA dichiarazione della stessa classe, ed è quella che vince per
   ordine di caricamento: correggerne una sola non avrebbe cambiato un pixel. */
.badge-error      { background: var(--error-light);   color: var(--sim-red-ink); }

/* --- Unassociated Documents (checklist) ---
   DELETED by substory #711, not left behind. `#unassociatedSection` was a
   second document list on the checklist page -- a hidden box that JavaScript
   filled on the first poll -- and its rows are ordinary rows in the
   `unclassified` group of the one Documenti list now, styled by the same
   `.checklist-item` and `.doc-row-*` rules as every other document. The five
   rules that were here (`.unassociated-section`, `.unassociated-count`,
   `.unassociated-doc` and its two children) have no markup left to match.

   Deleted rather than kept, on #777's own step 6 -- "delete the rules the
   component classes replace, rather than leaving them to compete". A rule with
   no element is not harmless: it is the next agent's evidence that the element
   still exists.

   The one measurement worth keeping out of them, because bug #765 paid for it:
   `.unassociated-count` was near-black on mid-tone amber at 3.92, and was
   inverted to white on `--sim-warn-ink` for 5.75. The count it carried is now
   part of the per-person `.documenti-counter`, which is ordinary text on
   `--sim-soft` and is measured by test_beta_bug765_contrast_e2e.py under
   `[data-doc-counter]`. */

/* Substory #777. Il select porta `.sim-select`, "Assegna" è una
   `.sim-btn--primary` e il cestino una `.sim-btn--danger --icon`. Le tre
   regole che stavano qui sono state CANCELLATE, non battute: avevano la stessa
   specificità del componente e vincevano per ordine di caricamento, ed erano
   il motivo per cui questi tre controlli hanno attraversato il cambio di
   palette intatti — "Assegna" era ancora un verde Material con un #1B5E20
   scritto a mano al passaggio del mouse. Resta la sola larghezza minima del
   select, che è layout della riga e non aspetto del controllo. */
.reassign-select { min-width: 200px; }

/* --- Toast Notification --- */
.toast {
  position: fixed;
  /* Substory #708. The only unconditional bottom-fixed surface in the codebase:
     no media query, so it is 24px off the bottom on every screen. Until #708
     added `viewport-fit=cover` to the viewport meta that was fine, because
     `env(safe-area-inset-bottom)` was 0px everywhere; the moment the meta lands,
     a notched iPhone's 34px home indicator eats the 24px gap and 10px of the
     toast with it — measured in the browser half at 390x844.

     The inset goes on `bottom` rather than on `padding-bottom` because that is
     the declaration that moves this box's bottom EDGE. Padding would grow the
     green rectangle downwards into the indicator and merely keep the text out
     of it; the offset lifts the whole toast clear. `0px` as the fallback so
     nothing moves on a browser with no safe area, which is every desktop and
     every test viewport without a CDP override. */
  bottom: calc(var(--space-6) + env(safe-area-inset-bottom, 0px));
  inset-inline-end: var(--space-6);   /* Bug #840: was `right`. */
  background: var(--success);
  color: #fff;
  padding: var(--space-3) var(--space-5);
  border-radius: var(--radius-md);
  font-size: var(--text-sm);
  box-shadow: var(--shadow-lg);
  opacity: 0;
  transform: translateY(20px);
  transition: opacity 0.3s, transform 0.3s;
  z-index: 1000;
}
.toast.show { opacity: 1; transform: translateY(0); }

/* --- Action Panel --- */
/* Substory #777: superficie `.sim-card` sull'elemento; qui resta lo spazio
   sotto il pannello. */
.action-panel {
  margin-bottom: var(--space-6);
}
.action-panel-header {
  margin-bottom: var(--space-4);
}
.action-panel-title {
  font-size: var(--text-lg);
  font-weight: var(--font-semibold);
  color: var(--success);
}
.action-panel-buttons {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-4);
  margin-bottom: var(--space-4);
}
/* Substory #777: padding, font, raggio, cursore e transizione arrivano da
   `.sim-btn`. Qui resta solo come il bottone si comporta DENTRO la riga flex
   del pannello, che il componente non sa e non deve sapere. */
.action-btn {
  flex: 1;
  min-width: 200px;
}
.action-btn:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}
.action-btn-help {
  font-size: var(--text-sm);
  color: var(--neutral-600);
  margin: 0 0 var(--space-3) 0;
  flex-basis: 100%;
}
.btn-secondary {
  background: var(--neutral-200);
  color: var(--neutral-900);
  border: 1px solid var(--neutral-400);
}
.btn-secondary:hover { background: var(--neutral-300); }
.btn-outline {
  background: transparent;
  color: var(--neutral-700);
  border: 1px solid var(--neutral-400);
}
.btn-outline:hover:not(:disabled) { background: var(--neutral-100); }
.action-panel-consultation {
  border-top: 1px solid var(--neutral-300);
  padding-top: var(--space-4);
}
@media (max-width: 600px) {
  .action-panel-buttons { flex-direction: column; }
  .action-btn { min-width: 100%; }
}

/* Substory #1249: the priced Generate controls, shared by the checklist's
   action panel and La tua pratica. Tokens only (ADR-0004), logical
   properties only (#840: the product ships Urdu). */
.payment-price { white-space: nowrap; }
.payment-test-notice {
  margin: 0;
  padding-block: var(--space-2);
  padding-inline: var(--space-3);
  border-radius: var(--radius-sm);
  background: var(--sim-warn-soft);
  color: var(--sim-warn-ink);
  font-size: var(--text-sm);
  overflow-wrap: anywhere;
}
.action-panel-buttons .payment-test-notice,
.action-panel-buttons .payment-unavailable-note { flex-basis: 100%; }
.payment-unavailable-note {
  margin: 0;
  font-size: var(--text-sm);
  color: var(--neutral-600);
}

/* --- Form Generation Progress --- */
.form-progress-section {
  background: var(--neutral-50);
  border: 2px solid var(--neutral-300);
  border-radius: var(--radius-lg);
  padding: var(--space-6);
  margin-bottom: var(--space-6);
}
.form-progress-header { margin-bottom: var(--space-4); }
.form-progress-title {
  font-size: var(--text-lg);
  font-weight: var(--font-semibold);
  color: var(--neutral-900);
  margin-bottom: var(--space-3);
}
.form-progress-list { display: flex; flex-direction: column; gap: var(--space-2); }
.form-progress-item {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: var(--space-2) var(--space-3);
  background: #fff;
  border-radius: var(--radius-sm);
  border: 1px solid var(--neutral-200);
}
.form-type-label { font-weight: var(--font-medium); }
.form-status-badge {
  font-size: var(--text-sm);
  padding: 2px 8px;
  border-radius: var(--radius-full);
}
.form-status-pending   { background: var(--neutral-200); color: var(--neutral-600); }
.form-status-processing { background: var(--info-light); color: var(--info); }
.form-status-completed  { background: var(--success-light); color: var(--success); }
/* Substory #707, item 2 — vedi il commento su `.badge-error`. */
.form-status-failed     { background: var(--error-light); color: var(--sim-red-ink); }
.form-download-area { margin-top: var(--space-4); text-align: center; }
.form-error-area { margin-top: var(--space-4); }
.form-error-message {
  color: var(--error);
  font-weight: var(--font-medium);
  margin-bottom: var(--space-3);
}

/* --- Social Login Buttons --- */
.social-login-buttons {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  margin-bottom: var(--space-3);
}
.social-btn-container {
  display: flex;
  justify-content: center;
  min-height: 44px;
}
.social-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  width: 100%;
  padding: 12px 16px;
  border: none;
  border-radius: var(--radius-md);
  font-size: var(--font-sm);
  font-weight: var(--font-medium);
  cursor: pointer;
  transition: opacity 0.15s ease;
}
.social-btn:hover { opacity: 0.9; }
.social-btn-google {
  background-color: #fff;
  color: #3c4043;
  border: 1px solid #dadce0;
}
.social-btn-google:hover { background-color: #f7f8f8; opacity: 1; }
.social-btn-google svg { flex-shrink: 0; }
.social-btn-facebook {
  background-color: #1877F2;
  color: white;
}
.social-divider {
  display: flex;
  align-items: center;
  margin: var(--space-3) 0;
  color: var(--neutral-500);
  font-size: var(--font-xs);
}
.social-divider::before,
.social-divider::after {
  content: '';
  flex: 1;
  height: 1px;
  background: var(--neutral-300);
}
.social-divider span {
  padding: 0 var(--space-3);
}
