/*
 * GROMA product UI — .g-* namespace (docs/design/design-system.md).
 * Layout shell: shell.css. Marketing site (groma.vibestrategy.it) is tone reference only.
 */

/* The tokens are linked from every <head>, before this file, and are deliberately
 * not `@import`ed here. On an MPA where every menu entry is a whole document and
 * `Cache-Control: no-store` is an invariant of privacy, an `@import` is a second
 * round trip *in series* on the render-blocking path — paid again on every
 * navigation, by a console whose users navigate constantly. Two <link>s are
 * fetched in parallel; an @import cannot start until its importer has arrived. */

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

/* Author display:flex on panels/nav must not beat the hidden attribute.
   That combination painted a white content column + an empty sidebar. */
html {
  font-size: 100%;
  color-scheme: light;
}

body {
  margin: 0;
  min-height: 100vh;
  min-height: 100dvh;
  font-family: var(--sans);
  font-size: var(--fs-15);
  line-height: 1.45;
  color: var(--ink);
  background: var(--carta);
  -webkit-font-smoothing: antialiased;
  /* Prevent horizontal rubber-band from 100vw + scrollbar / safe-area */
  overflow-x: clip;
}

/* Programmatic focus after bootSession (tabindex=-1) must not look like a selected box.
   Keyboard users still get :focus-visible on real titles they tab to. */
.g-title[tabindex="-1"]:focus {
  outline: none;
}

a {
  color: var(--verde);
  text-decoration-thickness: 1px;
  text-underline-offset: 0.15em;
}

@media (hover: hover) {
  a:hover {
    color: var(--ink);
  }
}

a:focus-visible {
  outline: 2px solid var(--arancio);
  outline-offset: 2px;
}

.g-mono {
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
}

.g-muted {
  color: var(--ink-muted);
}

.g-title {
  font-size: var(--fs-31);
  font-weight: 700;
  line-height: 1.15;
  margin: 0 0 var(--s3);
}

.g-lede {
  font-size: var(--fs-15);
  color: var(--ink-muted);
  margin: 0 0 var(--s4);
  max-width: 40rem;
}

.g-meta {
  font-size: var(--fs-13);
  color: var(--ink-muted);
  margin: 0 0 var(--s4);
}

:where(.g-lede) + .g-meta:is(:not(:empty), [data-attende]) {
  margin-top: calc(-1 * var(--s3));
}

.g-meta:empty:not([data-attende]) {
  display: none;
}

/* A line the page writes after its read keeps its line while it waits: filling it must
   not push down what is already painted. The attribute is the page's promise that it
   will be written; an empty line nobody writes still collapses. */
[data-attende]:empty {
  display: block;
  min-height: 1lh;
}

/* Short labels identify the context of a block; they are not a second heading. */
.g-kicker {
  margin: 0 0 var(--s1);
  color: var(--ink-muted);
  font-family: var(--mono);
  font-size: var(--fs-10);
  font-weight: 500;
  letter-spacing: 0.06em;
  line-height: 1.2;
  text-transform: uppercase;
}

.g-section {
  font-size: var(--fs-10);
  font-family: var(--mono);
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--ink-muted);
  margin: 0 0 var(--s3);
}

/* Buttons. `:hover` everywhere in the console lives inside `@media (hover: hover)`: a phone
   emulates hover on tap and leaves the tint on until the next tap lands elsewhere. */
.g-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--s2);
  font-family: var(--sans);
  font-size: var(--fs-15);
  font-weight: 600;
  line-height: 1.2;
  padding: 0.55rem 1rem;
  border-radius: 0.4rem;
  border: 1px solid transparent;
  cursor: pointer;
  text-decoration: none;
  background: var(--foglio-2);
  color: var(--ink);
  /* Prefer --touch-min on narrow; desktop can stay slightly denser */
  min-height: 2.5rem;
  /* Avoid 300ms tap delay / double-tap zoom on iOS for controls */
  touch-action: manipulation;
  transition:
    background var(--motion-fast) var(--ease-standard),
    border-color var(--motion-fast) var(--ease-standard),
    filter var(--motion-fast) var(--ease-standard);
}

.g-btn:disabled,
.g-btn[aria-disabled="true"] {
  opacity: 0.5;
  cursor: not-allowed;
  pointer-events: none;
}

/* In-flight action (login, submit) — keep label, block double submit */
.g-btn[aria-busy="true"] {
  opacity: 0.72;
  cursor: wait;
  position: relative;
}

.g-btn[aria-busy="true"]::after {
  content: "";
  width: 0.65rem;
  height: 0.65rem;
  margin-left: var(--s2);
  border: 2px solid currentColor;
  border-right-color: transparent;
  border-radius: 50%;
  animation: g-spin 0.7s linear infinite;
  flex-shrink: 0;
}

@keyframes g-spin {
  to {
    transform: rotate(360deg);
  }
}

.g-btn--primary {
  background: var(--verde);
  color: var(--on-action);
  border-color: var(--verde);
}

/* Primary action that fills a form column (login) */
.g-form > .g-btn--primary {
  width: 100%;
  margin-top: var(--s1);
}

@media (hover: hover) {
  .g-btn--primary:hover:not(:disabled) {
    filter: brightness(1.06);
  }
}

.g-btn--secondary {
  background: var(--foglio);
  border-color: var(--bordo-input);
  color: var(--ink);
}

@media (hover: hover) {
  .g-btn--secondary:hover:not(:disabled) {
    background: var(--foglio-2);
  }
}

.g-btn--danger {
  background: var(--destructive);
  border-color: var(--destructive);
  color: var(--on-action);
}

@media (hover: hover) {
  .g-btn--danger:hover:not(:disabled) {
    filter: brightness(1.05);
  }
}

.g-btn--ghost {
  background: transparent;
  border-color: var(--bordo-input);
  color: var(--ink-muted);
}

@media (hover: hover) {
  .g-btn--ghost:hover:not(:disabled) {
    background: var(--foglio-2);
    color: var(--ink);
  }
}

.g-btn--chrome {
  background: transparent;
  border-color: rgba(243, 245, 240, 0.35);
  color: #f3f5f0;
  min-height: var(--touch-min);
}

@media (hover: hover) {
  .g-btn--chrome:hover:not(:disabled) {
    background: rgba(243, 245, 240, 0.08);
    border-color: rgba(243, 245, 240, 0.55);
  }
}

.g-btn--timbro {
  background: var(--timbro);
  border-color: var(--timbro);
  color: var(--on-action);
}

@media (hover: hover) {
  .g-btn--timbro:hover:not(:disabled) {
    filter: brightness(1.05);
  }
}

/* Topbar logout — the same 2rem chrome control as the theme button next to it
   (shell.css `.g-theme`): one box, one border, one radius, one focus ring. */
.g-btn--esci {
  gap: var(--s1);
  min-height: 2rem;
  padding: 0 var(--s3) 0 var(--s2);
  font-size: var(--fs-13);
  line-height: 1;
  border-color: rgba(243, 245, 240, 0.55);
  border-radius: var(--r-control);
}

@media (hover: hover) {
  .g-btn--esci:hover:not(:disabled) {
    background: rgba(243, 245, 240, 0.08);
    border-color: rgba(243, 245, 240, 0.55);
  }
}

/* A decorative icon inside a button: drawn by a mask, coloured by the text. */
.g-btn__icon {
  flex: 0 0 auto;
  width: 1.125rem;
  height: 1.125rem;
  background: currentColor;
}

.g-btn__icon--esci {
  -webkit-mask: url("/web/brand/icone/esci.svg") center / contain no-repeat;
  mask: url("/web/brand/icone/esci.svg") center / contain no-repeat;
}

/* Badges — word + dot, never colour alone */
.g-badge {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  font-family: var(--sans);
  font-size: var(--fs-13);
  line-height: 1.2;
  padding: 0.2rem 0.5rem;
  border-radius: 999px;
  background: var(--foglio-2);
  color: var(--ink);
}

.g-badge::before {
  content: "";
  width: 0.45rem;
  height: 0.45rem;
  border-radius: 50%;
  background: currentColor;
  flex-shrink: 0;
}

.g-badge--fatto {
  color: var(--st-fatto);
}
.g-badge--corso {
  color: var(--st-corso);
}
.g-badge--programmata {
  color: var(--st-programmata);
}
.g-badge--verifica {
  color: var(--st-verifica);
}
.g-badge--eccezione {
  color: var(--st-eccezione);
}
.g-badge--firma {
  /* Full tint only for «serve la tua firma» (design-system) — shared, not coda-only */
  background: color-mix(in srgb, var(--st-firma) 12%, var(--foglio));
  color: var(--st-firma);
  font-weight: 700;
}

.g-badge--firma::before {
  background: var(--st-firma);
}
.g-badge--approvato {
  color: var(--st-approvato);
}
.g-badge--revisione {
  color: var(--st-revisione);
}
.g-badge--rifiutato {
  color: var(--st-rifiutato);
}
.g-badge--sospeso {
  color: var(--st-sospeso);
}

/* Forms */
.g-form {
  display: flex;
  flex-direction: column;
  gap: var(--s3);
  max-width: 28rem;
  width: 100%;
}

.g-field {
  display: flex;
  flex-direction: column;
  gap: var(--s1);
  font-size: var(--fs-13);
}

.g-check {
  display: flex;
  align-items: center;
  gap: var(--s2);
  min-height: var(--touch-min);
  font-weight: 500;
}

:where(.g-check) input {
  width: 1.25rem;
  height: 1.25rem;
  flex-shrink: 0;
}

.g-field > :is(span, label) {
  color: var(--ink-muted);
  font-weight: 500;
}

/* Le sezioni del form di configurazione. Ventidue campi in una colonna sola erano tre
   schermate di scroll senza un appiglio: chi cercava «da dove arrivano le richieste» doveva
   leggerli tutti per sapere che era il primo. Il `fieldset` non è decorazione — è ciò che
   lega un gruppo di controlli a un nome, anche per chi naviga con uno screen reader. */
.g-sezione {
  border: 0;
  border-top: 1px solid var(--bordo-input);
  margin: 0;
  padding: var(--s4) 0 0;
  display: flex;
  flex-direction: column;
  gap: var(--s3);
}

.g-sezione:first-of-type {
  border-top: 0;
  padding-top: 0;
}

.g-sezione__titolo {
  padding: 0;
  color: var(--ink);
  font-size: var(--fs-13);
  font-weight: 600;
  letter-spacing: 0.01em;
}

.g-field__hint {
  color: var(--ink-muted);
  font-size: var(--fs-12);
  margin: 0;
  line-height: 1.35;
}

:where(.g-field) input,
:where(.g-field textarea),
:where(.g-field) select {
  font: inherit;
  /* ≥16px always: iPad / landscape iPhone still zoom if this stays at 15px */
  font-size: max(1rem, var(--fs-15));
  padding: 0.55rem 0.7rem;
  border: 1px solid var(--bordo-input);
  border-radius: var(--r-control);
  background: var(--foglio);
  color: var(--ink);
  width: 100%;
  min-height: 2.5rem;
  /* Prevent layout overflow from long values */
  max-width: 100%;
  touch-action: manipulation;
}

/* Un numero di ore non ha bisogno della larghezza di un indirizzo, e un campo largo quanto il
   suo contenuto dice da solo che cosa ci va scritto. Selettore con la stessa specificità di
   `.g-field input` e più avanti nel file: la prima stesura era `.g-field__input--breve` da
   sola, e il `max-width: 100%` qui sopra — una classe in più e più avanti — la vinceva. È lo
   stesso inciampo della checkbox documentato poco sotto, alla seconda occorrenza. */
.g-field input.g-field__input--breve {
  max-width: 9rem;
}

/* Same specificity as `.g-field input` and later in the file: otherwise a
   checkbox inside a fieldset.g-field becomes a full-width 2.5rem text field. */
.g-field input[type="checkbox"],
.g-field input[type="radio"] {
  width: 1.25rem;
  height: 1.25rem;
  min-height: 0;
  padding: 0;
  border: none;
  border-radius: 0;
  background: none;
  appearance: auto;
  -webkit-appearance: auto;
}

.g-field select {
  /* Native select: consistent chrome across WebKit/Blink */
  appearance: none;
  -webkit-appearance: none;
  background-image:
    linear-gradient(45deg, transparent 50%, var(--ink-muted) 50%),
    linear-gradient(135deg, var(--ink-muted) 50%, transparent 50%);
  background-position:
    calc(100% - 1.1rem) 50%,
    calc(100% - 0.7rem) 50%;
  background-size:
    0.35rem 0.35rem,
    0.35rem 0.35rem;
  background-repeat: no-repeat;
  padding-right: 2rem;
}

:where(.g-field) textarea {
  min-height: 5.5rem;
  resize: vertical;
}

.g-field input:focus,
:where(.g-field textarea):focus,
.g-field select:focus {
  outline: 2px solid var(--arancio);
  outline-offset: 1px;
  border-color: var(--arancio);
}

.g-field input:disabled,
:where(.g-field textarea):disabled,
.g-field select:disabled {
  background: var(--foglio-2);
  color: var(--ink-muted);
  cursor: not-allowed;
}

.g-field input[aria-invalid="true"],
.g-field textarea[aria-invalid="true"],
.g-field select[aria-invalid="true"] {
  border-color: var(--destructive);
}

.g-field input[aria-invalid="true"]:focus,
.g-field textarea[aria-invalid="true"]:focus,
.g-field select[aria-invalid="true"]:focus {
  outline-color: var(--destructive);
}

.g-error {
  color: var(--destructive);
  font-size: var(--fs-13);
  margin: var(--s2) 0 0;
}

.g-ok {
  color: var(--success);
  font-size: var(--fs-13);
  margin: var(--s2) 0 0;
}

/* Structured feedback — not a bare colour swap on .g-error */
.g-callout {
  margin: var(--s3) 0 0;
  padding: var(--s3) var(--s4);
  border-radius: var(--r-control);
  border: 1px solid var(--bordo);
  background: var(--foglio-2);
  font-size: var(--fs-13);
  line-height: 1.45;
  color: var(--ink);
}

.g-callout--ok {
  border-color: color-mix(in srgb, var(--success) 35%, var(--bordo));
  background: color-mix(in srgb, var(--success) 8%, var(--foglio));
  color: var(--ink);
}

.g-callout--error {
  border-color: color-mix(in srgb, var(--destructive) 35%, var(--bordo));
  background: color-mix(in srgb, var(--destructive) 8%, var(--foglio));
}

.g-callout--warn {
  border-color: color-mix(in srgb, var(--warning) 40%, var(--bordo));
  background: color-mix(in srgb, var(--warning) 10%, var(--foglio));
}

/* Screen-reader only — labels that must not paint (criterion 5) */
.g-sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* Tabs — catalog filters, section switches (not a second nav) */
.g-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s1);
  margin: var(--s3) 0 0;
  border-bottom: 1px solid var(--bordo);
}

.g-tabs__btn {
  appearance: none;
  background: transparent;
  border: none;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
  padding: var(--s2) var(--s3);
  min-height: 2.5rem;
  font: inherit;
  font-size: var(--fs-13);
  font-weight: 600;
  color: var(--ink-muted);
  cursor: pointer;
  touch-action: manipulation;
  border-radius: var(--r-control) var(--r-control) 0 0;
}

@media (hover: hover) {
  .g-tabs__btn:hover {
    color: var(--ink);
    background: var(--foglio-2);
  }
}

.g-tabs__btn:focus-visible {
  outline: 2px solid var(--arancio);
  outline-offset: 1px;
}

.g-tabs__btn[aria-selected="true"],
.g-tabs__btn.is-active {
  color: var(--ink);
  border-bottom-color: var(--arancio);
}

/* Closed-by-default write forms / secondary facts (nav = place, details = task) */
.g-disclose {
  margin-top: var(--s4);
  border: 1px solid var(--bordo);
  border-radius: var(--r-card);
  background: var(--foglio);
  padding: 0 var(--s4);
}

.g-disclose[open] {
  padding-bottom: var(--s4);
}

.g-disclose > summary {
  cursor: pointer;
  font-weight: 600;
  font-size: var(--fs-15);
  line-height: 1.35;
  padding: var(--s3) 0;
  min-height: var(--touch-min);
  display: flex;
  align-items: center;
  gap: var(--s2);
  list-style: none;
}

.g-disclose > summary::-webkit-details-marker,
.g-disclose > summary::marker {
  display: none;
  content: none;
}

.g-disclose > summary::before {
  content: "▸";
  color: var(--ink-muted);
  font-size: var(--fs-13);
  line-height: 1;
  flex-shrink: 0;
}

.g-disclose[open] > summary::before {
  content: "▾";
}

:where(.g-disclose)[open] > summary {
  border-bottom: 1px solid var(--bordo);
  margin-bottom: var(--s3);
}

:where(.g-disclose > summary):focus {
  outline: none;
}

:where(.g-disclose > summary):focus-visible {
  outline: 2px solid var(--arancio);
  outline-offset: 2px;
  border-radius: var(--r-control);
}

:where(.g-disclose) .g-form,
:where(.g-disclose) .g-form--inline,
:where(.g-disclose) .g-form--policy {
  margin-top: 0;
  max-width: none;
}

.g-form__fields {
  display: flex;
  flex-direction: column;
  gap: var(--s3);
}

.g-disclose--quiet {
  border: none;
  background: transparent;
  border-radius: 0;
  padding: 0;
  margin-top: var(--s5);
  border-top: 1px solid var(--bordo);
  padding-top: var(--s2);
}

.g-disclose--quiet[open] > summary {
  border-bottom: none;
  margin-bottom: var(--s2);
}

/* Back control (detail → list) */
.g-linkback {
  display: inline-flex;
  align-items: center;
  gap: var(--s1);
  background: none;
  border: 0;
  color: var(--verde);
  font: inherit;
  font-weight: 600;
  font-size: var(--fs-13);
  cursor: pointer;
  padding: 0.25rem 0;
  margin: 0 0 var(--s3);
  min-height: 2.25rem;
  text-decoration: none;
  touch-action: manipulation;
}

@media (hover: hover) {
  .g-linkback:hover {
    text-decoration: underline;
    color: var(--ink);
  }
}

.g-linkback:focus-visible {
  outline: 2px solid var(--arancio);
  outline-offset: 2px;
  border-radius: 2px;
}

/* Role / perimeter chip (topbar + cards) */
.g-chip {
  display: inline-flex;
  align-items: center;
  font-family: var(--mono);
  font-size: var(--fs-10);
  font-weight: 500;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  padding: 0.15rem 0.45rem;
  border-radius: 999px;
  border: 1px solid var(--bordo);
  background: var(--foglio-2);
  color: var(--ink-muted);
  line-height: 1.2;
  max-width: 8rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Una chip dentro una scheda, non nel chrome: più respiro e inchiostro pieno, perché lì
   è un dato che si legge, non un'etichetta di contorno. Era un `.g-chip` riscritto in
   `libreria.css` — stessa specificità, caricato dopo, quindi vinceva anche sui chip dei
   ruoli in topbar, che appartengono alla shell. */
.g-chip--scheda {
  padding: 0.25rem 0.5rem;
  color: var(--ink);
  line-height: 1;
}

.g-topbar__user .g-chip {
  border-color: rgba(243, 245, 240, 0.28);
  background: rgba(243, 245, 240, 0.08);
  color: rgba(243, 245, 240, 0.78);
}

/* Panels / cards */
.g-panel {
  background: var(--foglio);
  border: 1px solid var(--bordo);
  border-radius: var(--r-card);
  padding: var(--s5);
  box-shadow: var(--shadow-card);
}

/* A nested surface is quieter than a page panel but keeps the same geometry. */
.g-card {
  background: var(--foglio);
  border: 1px solid var(--bordo);
  border-radius: var(--r-card);
  padding: var(--s4);
  box-shadow: var(--shadow-card);
}

.g-panel__head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--s3);
  margin-bottom: var(--s3);
}

.g-panel__head .g-title {
  margin-bottom: 0;
}

.g-login-brand {
  display: flex;
  justify-content: center;
  margin: 0 0 var(--s5);
}

.g-login-brand img {
  display: block;
  width: 56px;
  height: 56px;
}

.g-panel--login {
  max-width: 24rem;
  width: 100%;
  margin: 0 auto;
  padding: var(--s6) var(--s5);
  text-align: center;
}

.g-panel--login .g-title {
  font-size: var(--fs-25);
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.2;
  margin: 0 0 var(--s3);
  text-wrap: balance;
}

.g-panel--login .g-lede {
  max-width: 22rem;
  margin: 0 auto var(--s5);
  font-size: var(--fs-15);
  line-height: 1.5;
  text-wrap: pretty;
}

.g-panel--login .g-form {
  max-width: none;
  text-align: left;
  gap: var(--s4);
}

.g-panel--login .g-form > .g-btn--primary {
  margin-top: var(--s2);
  width: 100%;
  text-wrap: balance;
  padding-inline: var(--s4);
}

/* S14 — empty / error / loading: cosa è successo · cosa NON · prossimo passo */
.g-empty-state {
  border: 1px dashed var(--bordo-input);
  border-radius: var(--r-card);
  padding: var(--s5);
  background: var(--foglio-2);
  max-width: 36rem;
}

/* empty.js host when the parent is a list — never a bare div under ul/ol */
.g-empty-host {
  list-style: none;
  margin: 0;
  padding: 0;
}
.g-empty-host .g-empty-state {
  max-width: none;
}

/* Nested in a panel: avoid a second “card inside a card” */
.g-panel > .g-empty-state,
.g-panel .g-empty-state {
  max-width: none;
  margin-top: var(--s4);
  border-style: solid;
  border-color: var(--bordo);
  background: var(--carta);
}

.g-empty-state__kicker {
  font-family: var(--mono);
  font-size: var(--fs-10);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-muted);
  margin: 0 0 var(--s2);
}

.g-empty-state__title {
  font-size: var(--fs-20);
  font-weight: 700;
  margin: 0 0 var(--s3);
  line-height: 1.25;
}

.g-empty-state__body {
  margin: 0 0 var(--s2);
  color: var(--ink);
  line-height: 1.45;
}

.g-empty-state__not {
  margin: 0 0 var(--s3);
  color: var(--ink-muted);
  font-size: var(--fs-13);
  line-height: 1.4;
}

.g-empty-state__next {
  margin: 0;
  font-weight: 600;
  line-height: 1.45;
}

.g-empty-state__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s2);
  margin-top: var(--s4);
}

/* `.g-panel .g-empty-state` (0,2,0) fissa `margin-top: var(--s4)` e vinceva sempre su questa
   (0,1,0), qualunque fosse l'ordine: il modificatore non ha mai spostato un pixel. Stessa cura
   di `.g-field input.g-field__input--breve` — terza occorrenza della stessa forma in un giorno. */
:where(.g-panel) .g-empty-state--after,
.g-empty-state--after {
  margin-top: var(--s5);
}

.g-skeleton {
  height: 0.85rem;
  border-radius: 0.25rem;
  background: linear-gradient(
    90deg,
    var(--foglio-2) 0%,
    var(--bordo) 50%,
    var(--foglio-2) 100%
  );
  background-size: 200% 100%;
  animation: g-shimmer var(--motion-med) ease-in-out infinite;
  margin-bottom: var(--s2);
}

@keyframes g-shimmer {
  0% {
    background-position: 100% 0;
  }
  100% {
    background-position: -100% 0;
  }
}

@media (prefers-reduced-motion: reduce) {
  .g-skeleton {
    animation: none;
    background: var(--foglio-2);
  }
}

/* Shapes (S14, shell/empty.js): a placeholder the size of what lands does not make the
   content jump. Measures live here — never in a `style` attribute (CSP `style-src 'self'`).
   Every variant is a `.g-skeleton`, so the reduced-motion rule above already covers it. */
.g-skeleton-row {
  margin-bottom: var(--s3);
}

.g-skeleton--title {
  max-width: 60%;
}

.g-skeleton--meta {
  height: 0.7rem;
  max-width: 35%;
}

.g-skeleton-band {
  display: flex;
  gap: var(--s5);
  flex-wrap: wrap;
}

.g-skeleton--corpo {
  min-height: 6rem;
  height: auto;
}

.g-skeleton--kpi {
  height: 2rem;
  width: 3.5ch;
  margin-bottom: 0;
}

/* The figure's skeleton is the figure's box: `line-height: 1` makes that one em. A taller
   placeholder grew every card for the length of the read and shrank it on arrival. */
.g-morning__n.g-skeleton {
  height: 1em;
  margin-bottom: 0;
}

/* A list that reserves its first row (`data-attende`) loads inside that row: the `riga`
   skeleton takes exactly the row's box, so painting it moves nothing below the list, and
   the row that answers — one item, the empty sentence, the error — lands in the same place. */
.g-list[data-attende]:empty,
.g-empty-state.g-loading--riga {
  box-sizing: border-box;
  min-height: calc(2 * var(--s3) + 2px + 1lh);
}

.g-empty-state.g-loading--riga {
  display: flex;
  align-items: center;
  gap: var(--s3);
  margin-top: 0;
  padding: var(--s3) var(--s4);
}

.g-loading--riga .g-empty-state__kicker {
  margin: 0;
}

.g-skeleton--riga {
  flex: 1;
  max-width: 40%;
  margin-bottom: 0;
}

/* Dialog S08 */
.g-dialog {
  border: 1px solid var(--bordo);
  border-radius: var(--r-card);
  padding: var(--s5);
  max-width: 28rem;
  width: calc(100% - 2rem);
  background: var(--foglio);
  color: var(--ink);
  box-shadow: 0 12px 40px rgba(32, 40, 43, 0.18);
  /* The dialog must never leave the page. Browsers differ on the dialog:modal UA styles
     (Safari/WebKit-only webviews omit the max-height/overflow), and the firma confirm is
     the tallest dialog in the product — without a cap its bottom, and the sign button,
     sit out of reach. Mobile re-caps at 90dvh below. */
  max-height: calc(100% - 2 * var(--s5));
  overflow-y: auto;
  overscroll-behavior: contain;
}

.g-dialog::backdrop {
  background: rgba(32, 40, 43, 0.45);
}

.g-dialog__menu {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s2);
  justify-content: flex-end;
  margin: var(--s4) 0 0;
  padding: 0;
  list-style: none;
}

.g-dialog__summary {
  background: var(--foglio-2);
  border: 1px solid var(--bordo);
  border-radius: 0.4rem;
  padding: var(--s3) var(--s4);
  font-size: var(--fs-13);
  margin: var(--s3) 0;
}

:where(.g-dialog__summary) dt {
  color: var(--ink-muted);
  font-size: var(--fs-10);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  margin-top: var(--s2);
  font-family: var(--mono);
}

:where(.g-dialog__summary dt):first-child {
  margin-top: 0;
}

.g-dialog__summary dd {
  margin: 0.15rem 0 0;
  font-weight: 600;
  /* Long ids and address lists must wrap inside the grid's 1fr column, not push the
     dialog wider than its max-width or spill past it. */
  min-width: 0;
  overflow-wrap: anywhere;
}

/* Undo toast (ADR-0018) — fixed chrome; [hidden] must win over display:flex */
.g-toast {
  position: fixed;
  bottom: max(var(--s5), env(safe-area-inset-bottom, 0px));
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  align-items: center;
  gap: var(--s3);
  background: var(--chrome);
  color: #f3f5f0;
  padding: var(--s3) var(--s4);
  border-radius: var(--r-card);
  box-shadow: 0 8px 28px rgba(32, 40, 43, 0.28);
  z-index: 50;
  width: min(calc(100vw - 2 * var(--s3)), 28rem);
  max-width: min(92vw, 28rem);
  font-size: var(--fs-13);
  box-sizing: border-box;
}

.g-toast__timer {
  opacity: 0.85;
  min-width: 2.25rem;
  text-align: right;
  font-variant-numeric: tabular-nums;
}

/* Lists */
.g-list {
  list-style: none;
  margin: var(--s3) 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--s2);
}

.g-list__item {
  border: 1px solid var(--bordo);
  border-radius: var(--r-card);
  padding: var(--s3) var(--s4);
  background: var(--foglio);
}

.g-list__item button:not(.g-btn) {
  font: inherit;
  cursor: pointer;
  background: none;
  border: none;
  color: var(--verde);
  font-weight: 600;
  text-decoration: none;
  padding: 0.4rem 0.75rem;
  min-height: var(--touch-min);
}

@media (hover: hover) {
  .g-list__item button:not(.g-btn):hover {
    text-decoration: underline;
  }
}

.g-list__item button:not(.g-btn):focus-visible {
  outline: 2px solid var(--arancio);
  outline-offset: 2px;
}

:where(.g-list__item) .g-actions {
  margin-top: var(--s3);
  padding-top: var(--s3);
  border-top: 1px solid var(--bordo);
}

.g-list__meta {
  font-size: var(--fs-13);
  color: var(--ink-muted);
  overflow-wrap: anywhere;
}

.g-list__row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s2) var(--s3);
  align-items: baseline;
  justify-content: space-between;
}

.g-list__title {
  font-weight: 600;
  font-size: var(--fs-15);
}

.g-list__warn {
  font-size: var(--fs-13);
  margin-top: var(--s1);
  color: var(--ink);
}

.g-hash {
  font-family: var(--mono);
  font-size: var(--fs-12);
  word-break: break-all;
}

/* Content blocks inside a panel */
.g-block {
  margin-top: var(--s6);
  padding-top: var(--s5);
  border-top: 1px solid var(--bordo);
}

.g-block:first-of-type {
  margin-top: var(--s4);
  padding-top: 0;
  border-top: none;
}

.g-subtitle {
  font-size: var(--fs-20);
  font-weight: 600;
  margin: 0 0 var(--s2);
  line-height: 1.25;
  color: var(--ink);
}

.g-subtitle--sm {
  font-size: var(--fs-17);
  margin-top: var(--s4);
}

.g-dl {
  display: grid;
  grid-template-columns: minmax(7rem, 10rem) 1fr;
  gap: var(--s2) var(--s3);
  margin: var(--s3) 0 var(--s4);
  font-size: var(--fs-15);
}

:where(.g-dl) dt {
  color: var(--ink-muted);
  font-size: var(--fs-12);
  font-family: var(--mono);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  margin: 0;
  padding-top: var(--s1);
}

/* A grid track's minimum is its content: a long address or reference with no break point
   widened the value column past the page instead of wrapping inside it. */
.g-dl dd {
  min-width: 0;
  margin: 0;
  overflow-wrap: anywhere;
}

.g-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s2);
  align-items: center;
}

.g-form--inline,
.g-form--policy,
.g-form--filters,
.g-form--search,
.g-form--config {
  margin-top: var(--s3);
  max-width: 28rem;
}

.g-form--config .g-field textarea {
  font-family: var(--mono);
  /* NON `--fs-12`: `.g-field textarea` (riga ~415) fissa `max(1rem, …)` con la stessa
     specificità e ottocento righe più in su, quindi questa vinceva e portava il campo a
     12,5px — che è il caso che quel commento dice di voler evitare. Il floor tornava solo
     sotto i 640px, quindi su un iPad in verticale la textarea zoomava all'atterraggio del
     cursore. Il mono si può avere senza scendere sotto i 16px. */
  font-size: max(1rem, var(--fs-15));
}

.g-form--filters {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(12rem, 1fr));
  gap: var(--s3) var(--s4);
  align-items: end;
  max-width: 48rem;
}

.g-form--search {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s2);
  align-items: end;
  max-width: 40rem;
}

.g-form--search .g-field {
  flex: 1;
  min-width: 12rem;
}

.g-voce-testo {
  margin-top: var(--s2);
  font-size: var(--fs-13);
  line-height: 1.45;
}

/* —— Tablet dense (align with shell pad scale) —— */
@media (max-width: 859px) {
  .g-panel {
    padding: var(--s4);
  }

  .g-form--filters {
    grid-template-columns: repeat(auto-fill, minmax(10rem, 1fr));
  }

  /* `--touch-min` from 859px down (design-system §Spazio e griglia), not from 640: between
     the two a tablet in portrait had 40px buttons, tabs and fields and a 36px back link.
     `.g-btn` here also lifts `.g-btn--esci` (2rem on desktop). */
  .g-btn,
  .g-tabs__btn,
  .g-linkback {
    min-height: var(--touch-min);
  }

  .g-field input,
  .g-field textarea,
  .g-field select {
    min-height: var(--touch-min);
    /* Explicit 16px floor if tokens ever shrink body text */
    font-size: max(1rem, var(--fs-15));
  }
}

/* Mobile: design-system S13 / A-17 — firma usable at 375px */
@media (max-width: 640px) {
  .g-title {
    font-size: var(--fs-25);
  }

  /* `:not(.g-subtitle--sm)`: senza, questa regola — stessa specificità e più avanti nel file —
     scavalcherebbe `.g-subtitle--sm`. Oggi i due valori coincidono, quindi non si vedrebbe
     niente; si vedrebbe il giorno che `--sm` cambia, e solo su telefono. */
  .g-subtitle:not(.g-subtitle--sm) {
    font-size: var(--fs-17);
  }

  .g-panel {
    padding: var(--s4);
  }

  .g-panel--login {
    padding: var(--s5) var(--s4);
    /* Full width of content column on phone */
    max-width: none;
  }

  .g-panel__head {
    flex-direction: column;
    align-items: stretch;
  }

  .g-panel__head .g-btn {
    width: 100%;
  }

  .g-empty-state {
    padding: var(--s4);
    max-width: none;
  }

  .g-empty-state__title {
    font-size: var(--fs-17);
  }

  /* Native dialog: full usable width, room for home indicator */
  .g-dialog {
    width: calc(100% - 2 * var(--s3));
    max-width: none;
    margin: auto;
    padding: var(--s4);
    max-height: min(90dvh, 100%);
    overflow-y: auto;
  }

  /* The menu stays at the dialog's foot while the content scrolls under it: S08's summary is
     taller than a phone, and a keyboard takes half of what is left. The negative margins and
     the matching padding carry the solid background to the dialog's edges, so nothing
     scrolling underneath shows through. */
  .g-dialog__menu {
    position: sticky;
    bottom: calc(-1 * var(--s4));
    flex-direction: column-reverse;
    align-items: stretch;
    margin: var(--s4) calc(-1 * var(--s4)) calc(-1 * var(--s4));
    padding: var(--s3) var(--s4) var(--s4);
    background: var(--foglio);
    border-top: 1px solid var(--bordo);
  }

  .g-dialog__menu .g-btn {
    width: 100%;
  }

  .g-dl {
    grid-template-columns: 1fr;
    gap: var(--s1);
  }

  .g-dl dt {
    margin-top: var(--s2);
  }

  .g-dl dt:first-child {
    margin-top: 0;
  }

  /* Primary + secondary actions: stack full width (signing, forms) */
  .g-actions {
    flex-direction: column;
    align-items: stretch;
  }

  .g-actions .g-btn {
    width: 100%;
  }

  .g-tabs {
    gap: 0;
  }

  .g-tabs__btn {
    flex: 1 1 auto;
    min-width: 0;
    justify-content: center;
    text-align: center;
  }

  .g-empty-state__actions {
    flex-direction: column;
  }

  .g-empty-state__actions .g-btn {
    width: 100%;
  }

  .g-form--config {
    max-width: none;
  }

  .g-form--filters {
    grid-template-columns: 1fr;
    max-width: none;
  }

  .g-form--search {
    flex-direction: column;
    align-items: stretch;
    max-width: none;
  }

  .g-form--search .g-field {
    min-width: 0;
  }

  .g-form--inline,
  .g-form--policy {
    max-width: none;
  }

  .g-list__item {
    padding: var(--s3);
  }

  .g-list__row {
    flex-direction: column;
    align-items: flex-start;
  }

  .g-toast {
    bottom: max(var(--s3), env(safe-area-inset-bottom, 0px));
    left: var(--s3);
    right: var(--s3);
    transform: none;
    width: auto;
    max-width: none;
  }

  .g-block {
    margin-top: var(--s5);
    padding-top: var(--s4);
  }
}

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms;
    animation-iteration-count: 1;
    transition-duration: 0.01ms;
    scroll-behavior: auto;
  }

  .g-btn[aria-busy="true"]::after {
    animation: none;
    border-right-color: currentColor;
    opacity: 0.5;
  }
}


/* ————————————————————————————————————————————————————————————————
 * Shared list/detail components moved here from surface files (B69):
 * one owner for every `.g-*` name. `.g-queue`/`.g-kv` are the queue
 * variants of `.g-list`/`.g-dl`; the KPI card serves the morning
 * (`.g-morning`) and the cabina counters (`.g-stats`) from ONE block.
 * ———————————————————————————————————————————————————————————————— */

/* Queue (status first, then name — design-system) */
.g-queue {
  list-style: none;
  margin: var(--s4) 0 0;
  padding: 0;
  border: 1px solid var(--bordo);
  border-radius: var(--r-card);
  background: var(--foglio);
  overflow: hidden;
}

.g-queue__item {
  display: grid;
  grid-template-columns: auto 1fr auto;
  gap: var(--s3) var(--s4);
  align-items: center;
  padding: var(--s3) var(--s4);
  border-bottom: 1px solid var(--bordo);
  outline: none;
}

.g-queue__item:last-child {
  border-bottom: none;
}

/* Pointer and hover only on a row that opens something: the one that says so with
   `role="button"` (coda's list). «In ingresso» rows are decided on in place, and the rows of
   Operatività open nothing — both looked clickable and did nothing. */
.g-queue__item[role="button"] {
  cursor: pointer;
}

@media (hover: hover) {
  .g-queue__item[role="button"]:hover {
    background: var(--foglio-2);
  }
}

.g-queue__item:focus-visible {
  background: var(--foglio-2);
  box-shadow: inset 0 0 0 2px var(--arancio);
}

.g-queue__title {
  font-size: var(--fs-17);
  font-weight: 600;
  line-height: 1.3;
}

.g-queue__meta {
  font-size: var(--fs-12);
  color: var(--ink-muted);
  margin-top: var(--s1);
}

.g-queue__age {
  margin-top: var(--s1);
  font-size: var(--fs-12);
  font-weight: 600;
}

.g-queue__age--stale {
  color: var(--warning);
}

.g-kv {
  display: grid;
  gap: var(--s2);
  margin: 0 0 var(--s3);
}

.g-kv div {
  display: grid;
  grid-template-columns: 5.5rem 1fr;
  gap: var(--s2);
  align-items: baseline;
}

:where(.g-kv) dt {
  font-family: var(--mono);
  font-size: var(--fs-10);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--ink-muted);
  margin: 0;
}

.g-kv dd {
  min-width: 0;
  margin: 0;
  font-size: var(--fs-15);
  overflow-wrap: anywhere;
}

/* Queue & kv on the phone (S13) — moved with their components. The ingresso rows keep
 * their own third-column override in coda.css (`.g-ingresso__item > :nth-child(3)`):
 * that column holds Processa/Scarta and must survive this hiding. */
@media (max-width: 640px) {
  .g-queue__item {
    grid-template-columns: auto 1fr;
    grid-template-rows: auto auto;
    gap: var(--s2) var(--s3);
    padding: var(--s3);
    align-items: start;
    min-height: var(--touch-min);
  }

  .g-queue__item > :nth-child(1) {
    grid-column: 1;
    grid-row: 1;
    align-self: center;
  }

  .g-queue__item > :nth-child(2) {
    grid-column: 2;
    grid-row: 1 / span 2;
    min-width: 0;
  }

  .g-queue__item > :nth-child(3) {
    display: none;
  }

  .g-queue__title {
    font-size: var(--fs-15);
  }

  .g-kv div {
    grid-template-columns: 1fr;
    gap: var(--s1);
  }
}

/* One KPI card, two consumers. */
.g-morning {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr));
  gap: var(--s4);
  margin-top: var(--s4);
}

.g-morning__card {
  background: var(--foglio);
  border: 1px solid var(--bordo);
  border-radius: var(--r-card);
  padding: var(--s4);
  display: flex;
  flex-direction: column;
  gap: var(--s2);
  box-shadow: var(--shadow-card);
  min-height: 100%;
}

.g-morning__n {
  font-size: var(--fs-31);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  margin: 0;
  line-height: 1;
  color: var(--chrome);
}

.g-morning__label {
  font-size: var(--fs-13);
  color: var(--ink-muted);
  margin: 0 0 var(--s2);
  flex: 1;
  line-height: 1.4;
}

.g-morning__card .g-btn {
  align-self: flex-start;
  margin-top: auto;
}

/* A card's status line: what the page it links to still has to do. Written after the read,
   so the page reserves its line (`data-attende`). */
.g-morning__stato {
  font-size: var(--fs-15);
  font-weight: 600;
  color: var(--ink);
  margin: 0;
  line-height: 1.4;
}

.g-stats {
  list-style: none;
  margin: var(--s5) 0 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: var(--s3);
}

.g-stat {
  border: 1px solid var(--bordo);
  border-radius: var(--r-card);
  padding: var(--s4);
  background: var(--foglio);
  box-shadow: var(--shadow-card);
}

.g-stat__n {
  display: block;
  font-size: var(--fs-25);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  line-height: 1.15;
  color: var(--chrome);
}

.g-stat__label {
  display: block;
  margin-top: var(--s2);
  font-size: var(--fs-13);
  color: var(--ink-muted);
  line-height: 1.35;
}

@media (max-width: 1023px) {
  .g-stats {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

@media (max-width: 640px) {
  .g-morning {
    grid-template-columns: 1fr;
    gap: var(--s3);
  }

  .g-morning__n {
    font-size: var(--fs-25);
  }

  .g-morning__card .g-btn {
    width: 100%;
    align-self: stretch;
  }

  .g-stats {
    grid-template-columns: 1fr 1fr;
    gap: var(--s2);
  }

  :where(.g-stat:nth-child(5)) {
    grid-column: 1 / -1;
  }

  .g-stat {
    padding: var(--s3);
  }
}

.g-btn:focus-visible {
  outline: 2px solid var(--arancio);
  outline-offset: 3px;
}

:where(.g-btn--primary):focus-visible,
:where(.g-btn--timbro):focus-visible,
:where(.g-btn--danger):focus-visible {
  box-shadow: 0 0 0 2px var(--foglio);
}

/* Keep hidden content out of layout. Last in the file on purpose: a state rule wins over a
   component's `display` by coming after it, without `!important`. Components declared below
   an earlier copy of this rule painted with `hidden` on — the role-gated cards of the
   morning among them. Page stylesheets load after this file, so a page rule that gives an
   element a box says `:not([hidden])` (test_a_hidden_element_is_never_painted_by_its_component). */
[hidden] {
  display: none;
}
