/* ============================================================
   OfficinaGest — Sistema di design "Autofficina Basso"
   ------------------------------------------------------------
   Identità rossa preservata ed elevata: profondità, gerarchia,
   rifiniture e movimento vivace ma controllato. Lo strumento
   resta protagonista; il movimento è feedback, non decorazione.
   ============================================================ */

/* ============================================================
   1. TOKEN
   ============================================================ */
:root {
    /* --- Brand (rosso Autofficina Basso) ---
       Il rosso canonico resta #d9453c e resta l'identità. Col testo bianco però
       misura 4.31:1, cioè sotto il 4.5:1 richiesto dal testo normale: quindi le
       SUPERFICI piene che portano testo bianco (sidebar, banda, bottoni, teste
       del calendario) partono da --brand-strong, che è lo stesso rosso un passo
       più giù nella rampa (5.45:1). Il colore non cambia, cambia il gradino. */
    --officina-rosso: #d9453c;          /* canonico — accenti, calendario, badge */
    --officina-rosso-scuro: #b9342c;
    /* Voce di sidebar selezionata. Era rgba(255,255,255,0.18): schiariva il fondo
       e lasciava il testo bianco a 4.04:1. Una tinta scura scende invece a 6.87:1
       e per giunta si distingue meglio dall'hover, che è chiaro. */
    --officina-rosso-attivo: rgba(0, 0, 0, 0.14);

    --brand: #d9453c;                   /* accento — 4.31:1 su bianco: icone/bordi (3:1) e
                                           testo grande sì, testo piccolo no */
    --brand-strong: #c1372e;            /* superfici con testo bianco (5.45:1), hover bottoni */
    --brand-press: #a52a23;             /* pressione (7.11:1 col bianco) */
    --brand-deep: #9c281f;              /* sidebar profonda (7.67:1 col bianco) */
    --brand-tint: #fdeceb;              /* sfondi tenui */
    --brand-tint-2: #fbdedc;
    --brand-ink: #93251d;               /* testo rosso leggibile su chiaro (8.32:1 su bianco) */
    --brand-glow: rgba(217, 69, 60, 0.22);  /* solo decorativo: ombre e pulse, mai focus */

    /* --- Focus ring (due bande) --- */
    --focus-alone: #ffffff;             /* banda interna chiara */
    --focus-anello: #17181b;            /* banda esterna scura */

    /* --- Neutri --- */
    --bg: #f5f6f8;                       /* sfondo app */
    --surface: #ffffff;                  /* card, pannelli */
    --surface-2: #fafbfc;                /* righe alternate, zone tenui */
    --surface-3: #f0f1f4;                /* input riposo, hover tenue */
    --border: #e6e8ec;                   /* bordi standard */
    --border-strong: #d4d7dd;

    --ink: #17181b;                      /* testo primario (17.75:1 su --surface) */
    --ink-2: #565a61;                    /* testo secondario (6.93:1 su --surface) */
    /* Muted. Era #868c95 = 3.39:1 su bianco, sotto il 4.5:1 del testo piccolo, e il
       commento che lo riservava al "testo grande" non ha mai impedito di usarlo per le
       etichette orarie del calendario a 11px o per i placeholder. Scurito invece di
       rincorrere le chiamate: il token è consumato solo come testo piccolo, quindi il
       contratto giusto è quello del testo piccolo.
       Ora: 5.29:1 su --surface, 5.11 su --surface-2, 4.90 su --bg, 4.69 su --surface-3,
       4.63 su --brand-tint — AA a qualunque dimensione, su ogni fondo dell'app. */
    --ink-3: #666c75;

    /* --- Stati semantici --- */
    --success: #1c9d6b;
    --success-tint: #e6f6ef;
    --warning: #b8860b;
    --warning-ink: #8a6400;
    --warning-tint: #fdf4e0;
    --danger: #d9453c;
    --danger-tint: #fdeceb;
    --info: #2f6fed;
    --info-tint: #e9f0fe;

    /* Icona degli errori di validazione (§11). E' un token e non un url() inline
       perche' la stessa forma serve a .validation-message e alla summary, e
       perche' cambiarla in un punto solo evita che le due divergano.
       Usata come mask: il fill del path e' irrilevante, conta l'alpha. */
    --icona-errore: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0zM8 4a.905.905 0 0 0-.9.995l.35 3.507a.552.552 0 0 0 1.1 0l.35-3.507A.905.905 0 0 0 8 4zm.002 6a1 1 0 1 0 0 2 1 1 0 0 0 0-2z'/%3E%3C/svg%3E");

    /* --- Spaziatura --- */
    --space-1: 0.25rem;
    --space-2: 0.5rem;
    --space-3: 0.75rem;
    --space-4: 1rem;
    --space-5: 1.5rem;
    --space-6: 2rem;
    --space-7: 2.75rem;

    /* --- Raggi --- */
    --radius-sm: 0.5rem;
    --radius: 0.75rem;
    --radius-lg: 1rem;
    --radius-pill: 999px;

    /* --- Ombre (morbide, a strati) --- */
    --shadow-xs: 0 1px 2px rgba(20, 22, 28, 0.05);
    --shadow-sm: 0 1px 2px rgba(20, 22, 28, 0.05), 0 2px 6px rgba(20, 22, 28, 0.05);
    --shadow-md: 0 2px 4px rgba(20, 22, 28, 0.05), 0 8px 20px rgba(20, 22, 28, 0.08);
    --shadow-lg: 0 8px 16px rgba(20, 22, 28, 0.08), 0 20px 48px rgba(20, 22, 28, 0.14);
    --shadow-brand: 0 6px 18px rgba(217, 69, 60, 0.28);
    /* Anello di focus a DUE bande. Era `0 0 0 3px var(--brand-glow)`, cioè rosso al 22%:
       1.35:1 su bianco e 1.09:1 sulla sidebar (rosso su rosso), contro i 3:1 di WCAG
       1.4.11. Un anello a tinta unica non può passare ovunque, perché l'app ha fondi che
       vanno dal bianco al rosso profondo. Due bande sì: le box-shadow esterne si posano
       sul fondo del contenitore, quindi bianco (2px) + quasi-nero (3px) garantiscono che
       almeno una delle due stacchi. Verificato per forza bruta su tutto lo spazio RGB a
       passo 5: il caso peggiore è 4.21:1 (rgb(245,0,75)), sempre sopra 3:1. Le due bande
       stanno poi a 17.75:1 fra loro, quindi l'anello si legge come forma anche quando è
       il fondo a essere ambiguo. */
    --ring: 0 0 0 2px var(--focus-alone), 0 0 0 5px var(--focus-anello);

    /* --- Movimento --- */
    --dur-fast: 120ms;
    --dur: 180ms;
    --dur-slow: 280ms;
    --ease-out: cubic-bezier(0.25, 1, 0.5, 1);     /* out-quart */
    --ease-out-expo: cubic-bezier(0.16, 1, 0.3, 1);

    /* --- Z-index (scala semantica) ---
       Regola d'ordine: la chrome ancorata sta SOTTO tutto cio' che si apre.
       --z-dropdown valeva 1000, cioe' meno di --z-sticky: i menu "..." delle
       liste finivano sotto la sidebar e l'ultima voce restava inarrivabile.
       Un overlay che perde contro un elemento di contorno e' sempre un bug,
       quindi dropdown e drawer sono stati portati sopra --z-sticky.
       Restano tutti sotto --z-backdrop: con una modale aperta nulla la scavalca. */
    --z-base: 1;
    --z-sticky: 1020;          /* sidebar desktop, header del portale, topbar */
    --z-dropdown: 1030;        /* menu "...", select aperte */
    --z-drawer-scrim: 1035;    /* velo dietro la sidebar off-canvas (mobile) */
    --z-drawer: 1036;          /* la sidebar quando e' aperta come drawer */
    --z-backdrop: 1040;
    --z-modal: 1050;
    --z-toast: 1080;
    --z-tooltip: 1090;

    --sidebar-larghezza: 280px;
    --sidebar-larghezza-rail: 76px;   /* collassata: sole icone */
    --topbar-altezza: 56px;
}

/* ============================================================
   2. BASE
   ============================================================ */
html, body {
    height: 100%;
    background-color: var(--bg);
    color: var(--ink);
    font-family: "Inter", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
    -webkit-font-smoothing: antialiased;
    text-rendering: optimizeLegibility;
    font-feature-settings: "cv05", "ss01";
}

::selection {
    background: var(--brand-tint-2);
    color: var(--brand-ink);
}

/* Scrollbar discreta, in tono col brand */
* {
    scrollbar-width: thin;
    scrollbar-color: var(--border-strong) transparent;
}
*::-webkit-scrollbar { width: 10px; height: 10px; }
*::-webkit-scrollbar-thumb {
    background: var(--border-strong);
    border-radius: var(--radius-pill);
    border: 3px solid transparent;
    background-clip: padding-box;
}
*::-webkit-scrollbar-thumb:hover { background: #b9bdc5; background-clip: padding-box; }

a { color: var(--brand-ink); text-decoration-color: color-mix(in srgb, var(--brand-ink) 35%, transparent); }
a:hover { color: var(--brand-strong); }

/* L'outline è trasparente e non `none`: in forced-colors (contrasto elevato di Windows)
   le box-shadow vengono scartate dal browser, e senza un outline dichiarato il focus
   sparirebbe del tutto. Lì lo ricoloriamo col colore di sistema — vedi §26.
   Niente border-radius qui: forzarlo deformava al focus gli elementi tondi (btn-close,
   pallino-colore). L'anello segue già il raggio dell'elemento. */
:focus-visible {
    outline: 2px solid transparent;
    outline-offset: 2px;
    box-shadow: var(--ring);
}

/* ============================================================
   2-bis. SPLASH DI AVVIO — fondo rosso brand + logo
   ============================================================
   Markup in App.razor, rimozione in modale.js (evento load).
   Il logo e' un background: se /img/logo-bianco.png manca non
   appare nessuna icona rotta, resta il nome dell'officina. */
#splash-avvio {
    position: fixed;
    inset: 0;
    z-index: 2000;                        /* sopra tutto, anche i toast */
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.4rem;
    background: linear-gradient(168deg, #c1372e 0%, #b32f27 55%, #9c281f 100%);
    color: #fff;
    transition: opacity 0.4s var(--ease-out);
}
#splash-avvio.splash-esci {
    opacity: 0;
    pointer-events: none;
}
.splash-logo {
    width: min(220px, 60vw);
    height: 100px;
    background: url('/img/logo-bianco.png') center / contain no-repeat;
}
.splash-nome {
    font-weight: 700;
    font-size: 1.15rem;
    letter-spacing: -0.01em;
}

/* ============================================================
   3. MOVIMENTO — keyframe e primitive
   ============================================================ */
@keyframes fade-up {
    from { opacity: 0; transform: translateY(10px); }
    to   { opacity: 1; transform: translateY(0); }
}
@keyframes fade-in {
    from { opacity: 0; }
    to   { opacity: 1; }
}
@keyframes pop-in {
    0%   { opacity: 0; transform: translateY(8px) scale(0.97); }
    100% { opacity: 1; transform: translateY(0) scale(1); }
}
@keyframes backdrop-in {
    from { opacity: 0; }
    to   { opacity: 1; }
}
@keyframes shimmer {
    100% { transform: translateX(100%); }
}
@keyframes pulse-ring {
    0%   { box-shadow: 0 0 0 0 var(--brand-glow); }
    70%  { box-shadow: 0 0 0 8px rgba(217, 69, 60, 0); }
    100% { box-shadow: 0 0 0 0 rgba(217, 69, 60, 0); }
}

/* Le entrate sono additive: il default (e reduced-motion) è già visibile.
   Solo quando il movimento è consentito le applichiamo. */
@media (prefers-reduced-motion: no-preference) {
    .dashboard-cards > *,
    .item-card,
    .cal-evento {
        animation: fade-up var(--dur-slow) var(--ease-out-expo) both;
    }
    /* Stagger: le prime righe entrano a cascata, poi tutte insieme */
    .dashboard-cards > *:nth-child(1) { animation-delay: 20ms; }
    .dashboard-cards > *:nth-child(2) { animation-delay: 55ms; }
    .dashboard-cards > *:nth-child(3) { animation-delay: 90ms; }
    .dashboard-cards > *:nth-child(4) { animation-delay: 125ms; }
    .dashboard-cards > *:nth-child(5) { animation-delay: 160ms; }
    .dashboard-cards > *:nth-child(6) { animation-delay: 195ms; }

    .item-card:nth-child(1) { animation-delay: 20ms; }
    .item-card:nth-child(2) { animation-delay: 45ms; }
    .item-card:nth-child(3) { animation-delay: 70ms; }
    .item-card:nth-child(4) { animation-delay: 95ms; }
    .item-card:nth-child(5) { animation-delay: 120ms; }
    .item-card:nth-child(6) { animation-delay: 145ms; }
    .item-card:nth-child(7) { animation-delay: 170ms; }
    .item-card:nth-child(8) { animation-delay: 195ms; }
}

/* ============================================================
   4. LAYOUT PRINCIPALE
   ============================================================ */
.app-container {
    display: flex;
    min-height: 100vh;
}

.app-main {
    flex: 1;
    min-width: 0;
    padding: var(--space-6) var(--space-7);
    max-width: 100%;
    overflow-x: auto;
}
@media (prefers-reduced-motion: no-preference) {
    /* `backwards`, NON `both`. Il fill in avanti tiene l'animazione "in effetto"
       per sempre, e un'animazione su opacity rende questo contenitore un
       contesto d'impilamento permanente: backdrop (1040) e modale (1050), che
       stanno QUI dentro, si confrontavano con la sidebar (1020) non piu' da
       pari ma come figli di un contesto senza z-index — e perdevano. Il velo
       delle modali non copriva la sidebar. Verificato con elementsFromPoint:
       con both vince .sidebar-link, con backwards vince il backdrop.
       Per un'entrata senza delay backwards e' identico a schermo: il fill serve
       solo durante il ritardo, e qui il ritardo non c'e'. Lo stesso vale per
       .portale-main (§22). La pezza :has() di §9 resta per i dropdown DENTRO
       le card, che hanno la stessa animazione con stagger. */
    .app-main { animation: fade-in var(--dur-slow) var(--ease-out) backwards; }
}

/* ============================================================
   5. SIDEBAR
   ============================================================ */
.sidebar {
    width: var(--sidebar-larghezza);
    min-width: var(--sidebar-larghezza);
    /* Partiva da #d9453c: in cima al gradiente il testo bianco stava a 4.31:1, sotto AA.
       Da #c1372e (--brand-strong) la rampa è la stessa, ma il punto peggiore è 5.45:1. */
    background: linear-gradient(168deg, #c1372e 0%, #b32f27 55%, #9c281f 100%);
    color: #fff;
    display: flex;
    flex-direction: column;
    min-height: 100vh;
    position: sticky;
    top: 0;
    height: 100vh;
    overflow-y: auto;
    z-index: var(--z-sticky);
    box-shadow: inset -1px 0 0 rgba(0, 0, 0, 0.06), 4px 0 24px rgba(156, 40, 31, 0.12);
}
.sidebar::-webkit-scrollbar-thumb { background: rgba(255, 255, 255, 0.25); background-clip: padding-box; }

.sidebar-header {
    display: flex;
    align-items: center;
    gap: 0.55rem;                        /* sostituisce le .me-2 tolte dal markup */
    font-weight: 700;
    font-size: 1.05rem;
    letter-spacing: -0.01em;
    padding: 1.4rem 1.35rem 1.1rem;
}
/* Figlio diretto, non discendente: dentro l'intestazione c'e' anche la chevron
   del bottone di collasso, che non deve prendere ne' la dimensione del logo ne'
   la sua ombra. */
.sidebar-header > i {
    font-size: 1.2rem;
    filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.2));
}

/* Logo bianco nell'intestazione della sidebar: il wordmark sostituisce icona
   E scritta, quindi si prende lo spazio del titolo. Puo' restringersi (min-width
   0 + object-fit) perche' sul tablet la sidebar scende a 240px. */
.sidebar-logo {
    height: 48px;
    max-width: 158px;
    min-width: 0;
    flex-shrink: 1;
    object-fit: contain;
    object-position: left center;
    filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.2));
}

/* L'icona che rimpiazza il wordmark nel rail: fuori dal rail non si vede.
   Dimensione e ombra arrivano gia' da .sidebar-header > i. */
.sidebar-icona-rail { display: none; }
.sidebar-compatta .sidebar-logo { display: none; }
.sidebar-compatta .sidebar-icona-rail { display: block; }

/* Badge del login: il logo e' bianco su trasparente e sul bianco della card
   sparirebbe — vive su una targa rossa. Rettangolare, non quadrata: il
   wordmark 300x115 in un quadrato diventerebbe un francobollo. */
.login-logo {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 1rem 1.4rem;
    border-radius: 18px;
    background: linear-gradient(160deg, #c1372e 0%, #9c281f 100%);
    box-shadow: var(--shadow-brand);
}
.login-logo img {
    width: 185px;
    max-width: 100%;
    height: auto;
}

.sidebar-nav {
    flex: 1;
    display: flex;
    flex-direction: column;
    padding: 0 0.7rem;
    gap: 1px;
}

.sidebar-link {
    position: relative;
    display: flex;
    align-items: center;
    gap: 0.75rem;
    color: #fff;                          /* piena opacità per leggibilità */
    text-decoration: none;
    padding: 0.58rem 0.8rem;
    border-radius: var(--radius-sm);
    font-size: 0.94rem;
    font-weight: 500;
    transition: background-color var(--dur) var(--ease-out),
                color var(--dur) var(--ease-out),
                transform var(--dur) var(--ease-out);
}
.sidebar-link i {
    font-size: 1.02rem;
    opacity: 0.92;
    transition: transform var(--dur) var(--ease-out), opacity var(--dur) var(--ease-out);
}
.sidebar-link:hover {
    background-color: rgba(255, 255, 255, 0.10);   /* 0.12 lasciava il testo bianco a 4.50:1 netti */
    color: #fff;
    transform: translateX(2px);
}
.sidebar-link:hover i { opacity: 1; transform: scale(1.08); }

.sidebar-link.active {
    background-color: var(--officina-rosso-attivo);
    color: #fff;
    font-weight: 600;
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.08);
}
/* Indicatore di selezione: barretta che entra animata (affordance nav standard) */
.sidebar-link.active::before {
    content: "";
    position: absolute;
    left: -0.7rem;
    top: 50%;
    width: 3px;
    height: 1.15rem;
    background: #fff;
    border-radius: var(--radius-pill);
    transform: translateY(-50%) scaleY(1);
    transform-origin: center;
    box-shadow: 0 0 8px rgba(255, 255, 255, 0.5);
}
@media (prefers-reduced-motion: no-preference) {
    .sidebar-link.active::before { animation: fade-in var(--dur) var(--ease-out) both; }
}

.sidebar-divider {
    border: none;
    border-top: 1px solid rgba(255, 255, 255, 0.18);
    margin: 0.7rem 0.8rem;
}

.sidebar-footer {
    display: flex;
    align-items: center;
    gap: 0.55rem;                        /* sostituisce le .me-2 tolte dal markup */
    padding: 0.9rem 1.35rem;
    font-size: 0.9rem;
    border-top: 1px solid rgba(255, 255, 255, 0.18);
    background: rgba(0, 0, 0, 0.06);
}
.sidebar-footer .btn-link { transition: transform var(--dur) var(--ease-out), opacity var(--dur); opacity: 0.85; }
.sidebar-footer .btn-link:hover { opacity: 1; transform: translateX(2px); }

/* ============================================================
   6. INTESTAZIONI E TIPOGRAFIA
   ============================================================ */
.page-title {
    font-size: 1.65rem;
    font-weight: 700;
    letter-spacing: -0.02em;
    line-height: 1.15;
    margin: 0;
    color: var(--ink);
    text-wrap: balance;
}

.section-title {
    font-weight: 700;
    font-size: 1.05rem;
    letter-spacing: -0.01em;
    margin: 1.6rem 0 0.8rem;
    color: var(--ink);
}

/* ============================================================
   7. RICERCA
   ============================================================ */
.search-box {
    position: relative;
    width: 260px;
}
.search-box .bi-search {
    position: absolute;
    left: 0.8rem;
    top: 50%;
    transform: translateY(-50%);
    color: var(--ink-3);
    pointer-events: none;
    transition: color var(--dur) var(--ease-out);
}
.search-box input {
    padding-left: 2.3rem;
    background-color: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    transition: border-color var(--dur) var(--ease-out), box-shadow var(--dur) var(--ease-out);
}
.search-box input:focus {
    background-color: var(--surface);
    border-color: var(--brand);
    box-shadow: var(--ring);
}
.search-box:focus-within .bi-search { color: var(--brand); }

/* Anteprima dei template email (Impostazioni): iframe sandbox affiancato
   all'editor. Stessa altezza del textarea da 9 righe, cosi' la coppia
   editor/anteprima si legge come un unico blocco. */
.anteprima-template {
    width: 100%;
    height: 218px;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: #fff;
}
.anteprima-editor {
    font-family: ui-monospace, Consolas, monospace;
    font-size: 0.85rem;
}

/* ✕ di azzeramento: compare solo a campo pieno (markup condizionale in
   PageHeader). L'input riserva lo spazio a destra per non far scorrere il
   testo sotto il bottone. */
.search-box input { padding-right: 2.1rem; }
.search-clear {
    position: absolute;
    right: 0.35rem;
    top: 50%;
    transform: translateY(-50%);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.6rem;
    height: 1.6rem;
    padding: 0;
    border: none;
    border-radius: var(--radius-sm);
    background: transparent;
    color: var(--ink-3);
    font-size: 0.8rem;
    cursor: pointer;
    transition: color var(--dur-fast) var(--ease-out), background-color var(--dur-fast) var(--ease-out);
}
.search-clear:hover { color: var(--ink); background: var(--surface-3); }

/* ============================================================
   8. BOTTONI
   ============================================================ */
.btn {
    --bs-btn-font-weight: 600;
    border-radius: var(--radius-sm);
    transition: background-color var(--dur) var(--ease-out),
                border-color var(--dur) var(--ease-out),
                color var(--dur) var(--ease-out),
                box-shadow var(--dur) var(--ease-out),
                transform var(--dur-fast) var(--ease-out);
    will-change: transform;
}
.btn:active { transform: translateY(1px) scale(0.985); }
.btn:focus-visible { box-shadow: var(--ring); }

/* L'etichetta è bianca a 1rem/600 — testo normale, quindi 4.5:1. Su --brand erano 4.31:1:
   tutta la rampa scende di un gradino (5.45 → 7.11 → 7.67) mantenendo l'ordine
   riposo/hover/pressione e il rosso di brand. Il disabled resta com'è: WCAG 1.4.3 esclude
   esplicitamente i controlli inattivi, e schiarirlo è proprio ciò che lo fa leggere come
   disattivato. */
.btn-danger {
    --bs-btn-bg: var(--brand-strong);
    --bs-btn-border-color: var(--brand-strong);
    --bs-btn-hover-bg: var(--brand-press);
    --bs-btn-hover-border-color: var(--brand-press);
    --bs-btn-active-bg: var(--brand-deep);
    --bs-btn-active-border-color: var(--brand-deep);
    --bs-btn-disabled-bg: #e89c97;
    --bs-btn-disabled-border-color: #e89c97;
    box-shadow: var(--shadow-xs);
}
.btn-danger:hover { box-shadow: var(--shadow-brand); transform: translateY(-1px); }
.btn-danger:active { transform: translateY(0) scale(0.985); }

.btn-outline-secondary {
    --bs-btn-color: var(--ink-2);
    --bs-btn-border-color: var(--border-strong);
    --bs-btn-hover-bg: var(--surface-3);
    --bs-btn-hover-border-color: var(--border-strong);
    --bs-btn-hover-color: var(--ink);
    --bs-btn-active-bg: var(--surface-3);
    --bs-btn-active-color: var(--ink);
}

.btn-group .btn { will-change: auto; }

.btn-outline-light {
    /* Bordo = il contorno del controllo: 3:1 (WCAG 1.4.11). Al 60% sul rosso dell'header
       portale stava a 2.88:1; all'80% sta a 4.02:1. */
    --bs-btn-border-color: rgba(255, 255, 255, 0.8);
    --bs-btn-hover-bg: rgba(255, 255, 255, 0.16);
    --bs-btn-hover-border-color: #fff;
}

/* ============================================================
   9. CARD ELEMENTO LISTA (stile Glide, rifinito)
   ============================================================ */
.item-card {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 0.95rem 1.25rem;
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 0.55rem;
    box-shadow: var(--shadow-xs);
    transition: border-color var(--dur) var(--ease-out),
                box-shadow var(--dur) var(--ease-out),
                transform var(--dur) var(--ease-out);
}
.item-card .item-label {
    color: var(--brand-ink);
    font-size: 0.7rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}
.item-card .item-title {
    font-weight: 650;
    color: var(--ink);
    letter-spacing: -0.01em;
}
.item-card .item-subtitle {
    color: var(--ink-2);
    font-size: 0.88rem;
}

/* La riga con il menu "..." aperto deve stare DAVANTI alle righe successive.
   Ogni .item-card è un contesto d'impilamento (per l'animazione/transform),
   quindi diamo z-index esplicito alla card che ha il dropdown aperto. */
.item-card:has(.dropdown-menu.show) {
    position: relative;
    z-index: var(--z-dropdown);
}

.item-card-cliccabile {
    cursor: pointer;
}
.item-card-cliccabile:hover {
    border-color: var(--brand-tint-2);
    box-shadow: var(--shadow-md);
    transform: translateY(-2px);
}
.item-card-cliccabile:active { transform: translateY(0); box-shadow: var(--shadow-sm); }

/* ============================================================
   10. CARD BOOTSTRAP (pannelli dashboard ecc.)
   ============================================================ */
.card {
    border-radius: var(--radius) !important;
    border-color: var(--border) !important;
}
.card.shadow-sm { box-shadow: var(--shadow-sm) !important; }
.card.border-0 { border: 1px solid var(--border) !important; }

/* ============================================================
   11. FORM
   ============================================================ */
.form-label {
    font-weight: 600;
    font-size: 0.88rem;
    color: var(--ink-2);
    margin-bottom: 0.35rem;
}
.form-control, .form-select {
    border-radius: var(--radius-sm);
    border-color: var(--border-strong);
    color: var(--ink);
    transition: border-color var(--dur) var(--ease-out), box-shadow var(--dur) var(--ease-out);
}
.form-control::placeholder { color: var(--ink-3); }
.form-control:focus, .form-select:focus {
    border-color: var(--brand);
    box-shadow: var(--ring);
}
.form-control:disabled, .form-select:disabled {
    background-color: var(--surface-3);
    color: var(--ink-3);
}

/* --- Messaggi di validazione -------------------------------------------------
   <ValidationMessage> di Blazor emette .validation-message, <ValidationSummary>
   una <ul class="validation-errors">. Bootstrap non conosce nessuna delle due
   (stila .invalid-feedback, che Blazor non usa mai): senza queste regole
   ereditavano --ink, cioe' un messaggio d'errore nero indistinguibile dal testo
   normale.

   Il colore e' --brand-ink e NON --danger: questo e' testo piccolo, quindi la
   soglia e' 4.5:1. --danger (#d9453c) sta a 4.31:1 su bianco e non passa.
   --brand-ink (#93251d) invece regge su ogni fondo chiaro dell'app: 8.32:1 su
   --surface, 8.03 su --surface-2, 7.70 su --bg, 7.37 su --surface-3, 7.28 su
   --brand-tint, 7.61 su --warning-tint. Il caso peggiore e' 7.28:1.

   L'icona non e' decorazione: WCAG 1.4.1 vieta di affidare l'informazione al
   solo colore, e qui il colore e' l'unica cosa che distingue l'errore dal
   .form-text di aiuto che spesso lo precede. E' una mask e non un
   background-image perche' cosi' prende currentColor: segue il testo anche in
   forced-colors, dove un SVG a colore fisso resterebbe del tono sbagliato. */
.validation-message,
.validation-errors li {
    display: flex;
    align-items: flex-start;
    gap: 0.35rem;
    margin-top: 0.3rem;
    color: var(--brand-ink);
    font-size: 0.85rem;
    font-weight: 600;
    line-height: 1.35;
}

.validation-message::before,
.validation-errors li::before {
    content: "";
    flex-shrink: 0;
    width: 0.95em;
    height: 0.95em;
    margin-top: 0.16em;                  /* allinea l'icona alla prima riga, non al blocco */
    background-color: currentColor;
    -webkit-mask: var(--icona-errore) center / contain no-repeat;
    mask: var(--icona-errore) center / contain no-repeat;
}

/* La summary e' una lista: via i pallini, che duplicherebbero l'icona. */
.validation-errors {
    list-style: none;
    margin: 0 0 var(--space-4);
    padding: 0;
}

/* Il campo che ha causato l'errore. Blazor marca gli input con .invalid (non
   .is-invalid di Bootstrap, che infatti non si attiva mai). Il bordo porta
   informazione, quindi vale la soglia 3:1 dei componenti UI (WCAG 1.4.11):
   --brand la passa su tutti i fondi chiari (4.31:1 su --surface, 3.99 su --bg,
   3.82 su --surface-3). Qui --brand va bene e --brand-ink no: per il testo
   serviva il gradino scuro, per un bordo serve che si veda il rosso.
   Niente stile per .valid: segnare in verde ogni campo corretto e' rumore che
   rende meno visibile proprio l'unico campo che conta. */
.form-control.invalid,
.form-select.invalid {
    border-color: var(--brand);
}
.form-control.invalid:focus,
.form-select.invalid:focus {
    border-color: var(--brand-strong);
}

/* Un errore che compare e' feedback, non decorazione: entra, ma solo se il
   movimento e' consentito (cfr. §3). */
@media (prefers-reduced-motion: no-preference) {
    .validation-message,
    .validation-errors li {
        animation: fade-up var(--dur) var(--ease-out) both;
    }
}

/* ============================================================
   12. BADGE
   ============================================================ */
.badge {
    font-weight: 600;
    letter-spacing: 0.01em;
    border-radius: var(--radius-pill);
    padding: 0.34em 0.7em;
}
.badge.bg-danger {
    background-color: var(--danger-tint) !important;
    color: var(--brand-ink) !important;
}
.badge.bg-success { background-color: var(--success-tint) !important; color: #14724e !important; }
.badge.bg-warning { background-color: var(--warning-tint) !important; color: var(--warning-ink) !important; }
.badge.bg-secondary { background-color: var(--surface-3) !important; color: var(--ink-2) !important; }

/* ============================================================
   13. ALERT
   ============================================================ */
.alert {
    border: 1px solid transparent;
    border-radius: var(--radius);
    font-size: 0.92rem;
}
.alert-warning {
    background-color: var(--warning-tint);
    border-color: color-mix(in srgb, var(--warning) 28%, transparent);
    color: var(--warning-ink);
}
.alert-danger {
    background-color: var(--danger-tint);
    border-color: color-mix(in srgb, var(--danger) 28%, transparent);
    color: var(--brand-ink);
}
.alert-success {
    background-color: var(--success-tint);
    border-color: color-mix(in srgb, var(--success) 28%, transparent);
    color: #14724e;
}

/* ============================================================
   14. DROPDOWN (menu "...")
   ============================================================ */
.dropdown-menu {
    border: 1px solid var(--border);
    border-radius: var(--radius);
    box-shadow: var(--shadow-lg);
    padding: 0.35rem;
    z-index: var(--z-dropdown);
}
@media (prefers-reduced-motion: no-preference) {
    .dropdown-menu.show { animation: pop-in var(--dur) var(--ease-out-expo) both; }
}
.dropdown-item {
    border-radius: var(--radius-sm);
    font-size: 0.92rem;
    padding: 0.45rem 0.7rem;
    transition: background-color var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out);
}
.dropdown-item:hover { background-color: var(--surface-3); }
.dropdown-item.text-danger:hover { background-color: var(--danger-tint); }

/* ============================================================
   15. MODALE (entrata con scala morbida, niente bounce)
   ============================================================ */
.modal { z-index: var(--z-modal); }
.modal-backdrop {
    z-index: var(--z-backdrop);
    background-color: rgba(20, 22, 28, 0.45);
}
.modal-backdrop.show { opacity: 1; }
@media (prefers-reduced-motion: no-preference) {
    .modal-backdrop.show { animation: backdrop-in var(--dur) var(--ease-out) both; }
}
.modal-content {
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-lg);
}
@media (prefers-reduced-motion: no-preference) {
    .modal.show .modal-content { animation: pop-in var(--dur-slow) var(--ease-out-expo) both; }
}
.modal-header { padding: 1.3rem 1.4rem 0.4rem; }
.modal-title { font-weight: 700; letter-spacing: -0.01em; color: var(--ink); }
.modal-body { padding: 0.8rem 1.4rem 1.2rem; }
.modal-footer { padding: 0.6rem 1.4rem 1.3rem; }
.btn-close { transition: transform var(--dur) var(--ease-out), opacity var(--dur); }
.btn-close:hover { transform: rotate(90deg); opacity: 1; }

/* ============================================================
   16. SPINNER + SKELETON
   ============================================================ */
.spinner-border.text-danger { color: var(--brand) !important; }
.skeleton {
    position: relative;
    overflow: hidden;
    background: var(--surface-3);
    border-radius: var(--radius-sm);
}
.skeleton::after {
    content: "";
    position: absolute;
    inset: 0;
    transform: translateX(-100%);
    background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.6), transparent);
}
@media (prefers-reduced-motion: no-preference) {
    .skeleton::after { animation: shimmer 1.3s infinite; }
}

/* ============================================================
   17. PAGINA LOGIN
   ============================================================ */
.login-page {
    min-height: 100vh;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 1.5rem;
    background:
        radial-gradient(1100px 520px at 12% -8%, rgba(217, 69, 60, 0.14), transparent 60%),
        radial-gradient(900px 480px at 100% 110%, rgba(156, 40, 31, 0.12), transparent 60%),
        var(--bg);
}
.login-card {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-lg);
    padding: 2.6rem;
    width: 100%;
    max-width: 410px;
}
@media (prefers-reduced-motion: no-preference) {
    .login-card { animation: pop-in 360ms var(--ease-out-expo) both; }
}
.login-card .display-4 { color: var(--brand) !important; }
.login-card .btn-danger { box-shadow: var(--shadow-brand); }

/* ============================================================
   18. BANDA ROSSA (dettaglio documento)
   ============================================================ */
.banda-rossa {
    /* come la sidebar: parte da --brand-strong perché ci va sopra del testo bianco */
    background: linear-gradient(160deg, #c1372e 0%, #b32f27 100%);
    color: #fff;
    margin: 0 calc(-1 * var(--space-7));
    padding: 1.6rem var(--space-7) 2rem;
    box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.08);
}

/* ============================================================
   19. CALENDARIO SETTIMANALE
   ============================================================ */
.cal-grid {
    display: flex;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    overflow: hidden;
    background: var(--surface);
    box-shadow: var(--shadow-sm);
}
.cal-times {
    width: 56px;
    min-width: 56px;
    border-right: 1px solid var(--border);
}
.cal-time-label {
    height: 60px;
    font-size: 0.7rem;
    font-variant-numeric: tabular-nums;
    color: var(--ink-3);
    text-align: right;
    padding-right: 6px;
    transform: translateY(-7px);
}
.cal-day {
    flex: 1;
    min-width: 0;
    border-right: 1px solid var(--border);
}
.cal-day:last-child { border-right: none; }
.cal-day-header {
    height: 38px;
    line-height: 38px;
    text-align: center;
    /* 0.85rem/600 = testo normale: serve 4.5:1. Il vecchio #d9453c in cima dava 4.31:1. */
    background: linear-gradient(180deg, #c1372e, #a52a23);
    color: #fff;
    font-size: 0.85rem;
    font-weight: 600;
    letter-spacing: 0.01em;
}
.cal-times .cal-day-header { background: var(--surface); }
/* Scesa di un gradino insieme alla testa normale, per restare distinguibile da quella. */
.cal-day-oggi .cal-day-header { background: linear-gradient(180deg, #a52a23, #9c281f); }
.cal-day-body {
    position: relative;
    background-image: repeating-linear-gradient(
        to bottom,
        transparent 0, transparent 59px,
        var(--border) 59px, var(--border) 60px);
}
.cal-day-oggi .cal-day-body { background-color: var(--brand-tint); }
.cal-slot {
    position: absolute;
    left: 0;
    right: 0;
    height: 30px;
    cursor: pointer;
    transition: background-color var(--dur-fast) var(--ease-out);
}
.cal-slot:hover { background-color: rgba(217, 69, 60, 0.08); }
.cal-evento {
    position: absolute;
    right: 2px;
    border-radius: var(--radius-sm);
    color: #fff;
    font-size: 0.72rem;
    font-weight: 600;
    line-height: 1.25;
    padding: 4px 6px;
    overflow: hidden;
    cursor: pointer;
    box-shadow: 0 1px 4px rgba(0, 0, 0, 0.22);
    z-index: var(--z-base);
    transition: transform var(--dur) var(--ease-out), box-shadow var(--dur) var(--ease-out), filter var(--dur) var(--ease-out);
}
.cal-evento:hover {
    filter: brightness(0.95);
    transform: scale(1.015);
    box-shadow: var(--shadow-md);
    z-index: var(--z-base);
}

/* ============================================================
   20. CALENDARIO MENSILE (Orari)
   ============================================================ */
.mese-grid {
    display: grid;
    grid-template-columns: repeat(7, 1fr);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    overflow: hidden;
    background: var(--surface);
    box-shadow: var(--shadow-sm);
}
.mese-intestazione {
    text-align: center;
    font-size: 0.78rem;
    font-weight: 600;
    color: var(--ink-3);
    padding: 8px 0;
    border-bottom: 1px solid var(--border);
    text-transform: uppercase;
    letter-spacing: 0.03em;
}
.mese-cella {
    min-height: 76px;
    border-right: 1px solid var(--border);
    border-bottom: 1px solid var(--border);
    padding: 4px 6px;
    cursor: pointer;
    transition: background-color var(--dur-fast) var(--ease-out);
}
.mese-cella:hover { background-color: var(--brand-tint); }
.mese-numero {
    font-size: 0.85rem;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    margin-bottom: 2px;
    color: var(--ink);
}
.mese-altro .mese-numero { color: var(--ink-3); font-weight: 400; }
.mese-oggi { background-color: var(--brand-tint); }
.mese-oggi .mese-numero { color: var(--brand-ink); }

/* Giorno chiuso da ORARIO SETTIMANALE (es. sabato/domenica): grigio e inerte.
   Va distinto a colpo d'occhio dalla chiusura straordinaria (badge rosso):
   questa e' la routine, quella e' l'eccezione. Dopo .mese-oggi apposta: se
   oggi cade in un giorno chiuso, deve leggersi comunque come chiuso. */
.mese-chiuso {
    background-color: var(--surface-3);
    cursor: default;
}
.mese-chiuso:hover { background-color: var(--surface-3); }   /* niente invito al click */
.mese-chiuso .mese-numero { color: var(--ink-3); }
.mese-chiuso-etichetta {
    display: block;
    font-size: 0.68rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--ink-3);
}

/* ============================================================
   20-bis. CALENDARIO HOME — vista MENSILE (eventi come chip)
   e vista GIORNO (una colonna per meccanico)
   ============================================================ */

/* Le celle del mese in Home crescono con gli eventi; il click sul vuoto crea. */
.cal-mese .mese-cella {
    min-height: 96px;
    display: flex;
    flex-direction: column;
    gap: 2px;
    align-items: stretch;
}

/* Il numero e' un bottone (porta alla vista Giorno) ma deve sembrare il numero
   di sempre: reset del bottone, affordance solo all'hover. */
.cal-mese-numero {
    align-self: flex-start;
    border: none;
    background: transparent;
    padding: 0 3px;
    border-radius: var(--radius-sm);
    cursor: pointer;
}
.cal-mese-numero:hover { background: var(--brand-tint-2); color: var(--brand-ink); }

/* Chip evento: pallino del meccanico + ora e cliente su una riga. */
.cal-mese-evento {
    display: flex;
    align-items: center;
    gap: 4px;
    width: 100%;
    border: none;
    background: var(--surface);
    border-radius: var(--radius-sm);
    padding: 1px 4px;
    font-size: 0.72rem;
    font-weight: 600;
    color: var(--ink);
    text-align: left;
    cursor: pointer;
    box-shadow: var(--shadow-xs);
    transition: background-color var(--dur-fast) var(--ease-out), box-shadow var(--dur-fast) var(--ease-out);
}
.cal-mese-evento:hover { background: var(--brand-tint); box-shadow: var(--shadow-sm); }
.cal-mese-evento-testo {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* "+N altri": porta alla vista Giorno, dove si vede tutto. */
.cal-mese-piu {
    border: none;
    background: transparent;
    color: var(--brand-ink);
    font-size: 0.72rem;
    font-weight: 600;
    text-align: left;
    padding: 0 4px;
    cursor: pointer;
}
.cal-mese-piu:hover { text-decoration: underline; }

/* Testa colonna della vista Giorno: nome del meccanico col suo pallino. */
.cal-col-testa {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    padding: 0 4px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* ============================================================
   21. PALLINO COLORE MECCANICO
   ============================================================ */
.pallino-colore {
    display: inline-block;
    width: 16px;
    height: 16px;
    border-radius: 50%;
    flex-shrink: 0;
    box-shadow: 0 0 0 2px var(--surface), 0 1px 2px rgba(0, 0, 0, 0.18);
}

/* Variante piccola per chip e teste colonna del calendario Home. DOPO
   .pallino-colore: a parita' di specificita' vince l'ultima regola. */
.pallino-colore.pallino-mini {
    width: 10px;
    height: 10px;
    box-shadow: 0 0 0 1.5px var(--surface);
}

/* ============================================================
   22. PORTALE CLIENTE
   ============================================================ */
.portale-page { min-height: 100vh; background-color: var(--bg); }
.portale-header {
    background: linear-gradient(168deg, #c1372e 0%, #b32f27 100%);
    color: #fff;
    padding: 0.9rem 0;
    box-shadow: var(--shadow-sm);
    position: sticky;
    top: 0;
    z-index: var(--z-sticky);
}
.portale-header-inner {
    max-width: 900px;
    margin: 0 auto;
    padding: 0 1.25rem;
    display: flex;
    align-items: center;
    justify-content: space-between;
}
/* Wordmark bianco nell'header rosso del portale. Puo' restringersi: su
   telefono lo spazio se lo prendono le voci di menu. */
.portale-logo {
    height: 36px;
    min-width: 0;
    flex-shrink: 1;
    object-fit: contain;
    object-position: left center;
    filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.2));
}
.portale-link {
    color: rgba(255, 255, 255, 0.92);
    text-decoration: none;
    font-size: 0.95rem;
    font-weight: 500;
    padding: 0.3rem 0.1rem;
    position: relative;
    transition: color var(--dur) var(--ease-out);
}
.portale-link::after {
    content: "";
    position: absolute;
    left: 0; right: 0; bottom: -2px;
    height: 2px;
    background: #fff;
    border-radius: var(--radius-pill);
    transform: scaleX(0);
    transform-origin: left;
    transition: transform var(--dur) var(--ease-out-expo);
}
.portale-link:hover { color: #fff; }
.portale-link:hover::after { transform: scaleX(1); }
.portale-link.active { color: #fff; font-weight: 600; }
.portale-link.active::after { transform: scaleX(1); }
.portale-main {
    max-width: 900px;
    margin: 0 auto;
    padding: 2rem 1.25rem;
}
@media (prefers-reduced-motion: no-preference) {
    /* backwards per lo stesso motivo di .app-main (§4): con both le modali del
       portale finivano sotto l'header sticky. */
    .portale-main { animation: fade-up var(--dur-slow) var(--ease-out-expo) backwards; }
}

/* ============================================================
   23. DASHBOARD ADMIN
   ============================================================ */
.dashboard-cards {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(168px, 1fr));
    gap: 0.85rem;
}
.dash-card {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 1.1rem 1.2rem;
    box-shadow: var(--shadow-xs);
    transition: border-color var(--dur) var(--ease-out),
                box-shadow var(--dur) var(--ease-out),
                transform var(--dur) var(--ease-out);
}
.dash-card[role=button] { cursor: pointer; }
.dash-card[role=button]:hover {
    transform: translateY(-3px);
    box-shadow: var(--shadow-md);
    border-color: var(--brand-tint-2);
}
.dash-card[role=button]:active { transform: translateY(-1px); }
.dash-valore {
    font-size: 1.6rem;
    font-weight: 750;
    line-height: 1.1;
    letter-spacing: -0.02em;
    color: var(--ink);
    font-variant-numeric: tabular-nums;
}
.dash-label {
    font-size: 0.8rem;
    color: var(--ink-2);
    margin-top: 0.3rem;
    font-weight: 500;
}
/* Stato d'allerta: superficie tinta + accento, niente side-stripe */
.dash-alert {
    background: var(--warning-tint);
    border-color: color-mix(in srgb, var(--warning) 32%, transparent);
}
.dash-alert .dash-valore { color: var(--warning-ink); }
.dash-alert .dash-label { color: var(--warning-ink); }
@media (prefers-reduced-motion: no-preference) {
    .dash-alert[role=button] { animation: fade-up var(--dur-slow) var(--ease-out-expo) both, pulse-ring 2.4s ease-out 0.6s 2; }
}

.dash-riga {
    border-radius: var(--radius-sm);
    padding-left: 0.4rem;
    padding-right: 0.4rem;
    transition: background-color var(--dur-fast) var(--ease-out);
}
.dash-riga:hover { background: var(--brand-tint); }
.dash-riga:last-child { border-bottom: none !important; }

/* ============================================================
   24. SIDEBAR APRIBILE — rail (desktop) e drawer (mobile)
   ============================================================
   Due comportamenti dallo stesso markup, decisi qui e non da C#:
   - da 993px la sidebar resta in flusso e il toggle la stringe a rail di icone;
   - fino a 992px esce dal flusso, va fuori schermo e rientra come drawer.
   MainLayout tiene solo due booleani (.sidebar-compatta, .drawer-aperto) e non
   sa nulla di larghezze: il breakpoint e' una questione di CSS. */

/* La colonna che affianca la sidebar. min-width:0 non e' cosmetica: senza,
   un flex item non scende mai sotto la larghezza del suo contenuto piu' largo,
   ed e' cosi' che una tabella larga fa comparire lo scroll orizzontale su
   tutta la pagina invece che dentro il suo .table-responsive. */
.app-colonna {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    min-height: 100vh;
}

.sidebar {
    transition: width var(--dur-slow) var(--ease-out),
                min-width var(--dur-slow) var(--ease-out),
                transform var(--dur-slow) var(--ease-out);
}

/* --- Bottone di collasso, dentro l'intestazione della sidebar --- */
.sidebar-toggle {
    margin-left: auto;
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 30px;
    height: 30px;
    padding: 0;
    border: 1px solid rgba(255, 255, 255, 0.28);
    border-radius: var(--radius-sm);
    background: rgba(255, 255, 255, 0.08);
    color: #fff;
    font-size: 0.85rem;
    cursor: pointer;
    transition: background-color var(--dur) var(--ease-out),
                border-color var(--dur) var(--ease-out);
}
.sidebar-toggle:hover {
    background: rgba(255, 255, 255, 0.18);
    border-color: rgba(255, 255, 255, 0.5);
}

/* --- Rail: sidebar collassata (solo desktop) --- */
.sidebar-compatta .sidebar {
    width: var(--sidebar-larghezza-rail);
    min-width: var(--sidebar-larghezza-rail);
}

/* Il testo si nasconde ma NON con display:none, che lo toglierebbe anche
   all'albero di accessibilita': in rail lo screen reader deve continuare a
   leggere "Clienti", non "link". Stessa tecnica di .visually-hidden. */
.sidebar-compatta .sidebar-testo {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

.sidebar-compatta .sidebar-header {
    flex-direction: column;
    gap: 0.7rem;
    padding: 1.1rem 0.5rem 0.9rem;
}
.sidebar-compatta .sidebar-toggle { margin-left: 0; }

.sidebar-compatta .sidebar-nav { padding: 0 0.5rem; }
.sidebar-compatta .sidebar-link {
    justify-content: center;
    padding-left: 0;
    padding-right: 0;
}
.sidebar-compatta .sidebar-link i { font-size: 1.15rem; }
.sidebar-compatta .sidebar-link:hover { transform: none; }   /* il translateX sborda dal rail */
.sidebar-compatta .sidebar-link.active::before { left: -0.5rem; }

.sidebar-compatta .sidebar-footer {
    flex-direction: column;
    gap: 0.6rem;
    padding: 0.9rem 0.5rem;
}
.sidebar-compatta .sidebar-divider { margin: 0.7rem 0.4rem; }

/* --- Topbar: esiste solo sotto i 993px (accesa in §25) --- */
.topbar {
    display: none;
    align-items: center;
    gap: 0.75rem;
    height: var(--topbar-altezza);
    padding: 0 0.9rem;
    background: linear-gradient(168deg, #c1372e 0%, #b32f27 100%);
    color: #fff;
    position: sticky;
    top: 0;
    z-index: var(--z-sticky);
    box-shadow: var(--shadow-sm);
}
.topbar-toggle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    /* 44x44: soglia di target tattile (WCAG 2.5.5). Su un telefono questo e'
       l'unico modo di raggiungere la navigazione, quindi non si stringe. */
    width: 44px;
    height: 44px;
    margin-left: -0.35rem;
    padding: 0;
    border: none;
    border-radius: var(--radius-sm);
    background: transparent;
    color: #fff;
    font-size: 1.4rem;
    cursor: pointer;
    transition: background-color var(--dur) var(--ease-out);
}
.topbar-toggle:hover, .topbar-toggle:focus-visible { background: rgba(255, 255, 255, 0.16); }
.topbar-titolo {
    font-weight: 700;
    font-size: 1rem;
    letter-spacing: -0.01em;
}

/* --- Velo del drawer: inerte finche' il drawer e' chiuso --- */
.drawer-scrim {
    display: none;
    position: fixed;
    inset: 0;
    z-index: var(--z-drawer-scrim);
    background: rgba(20, 22, 28, 0.45);
    opacity: 0;
    pointer-events: none;
    transition: opacity var(--dur) var(--ease-out);
}

/* ============================================================
   25. RESPONSIVE
   ============================================================
   Quattro soglie:
     <= 1200px  desktop stretto — si recupera respiro sui margini
     <=  992px  contenuti piu' densi; la sidebar RESTA IN FLUSSO
                (240px o rail): si lavora su di lei e sulla pagina
                insieme, niente sovraimpressione
     <=  640px  telefono — solo qui topbar + drawer sopra i contenuti
     <=  576px  telefono stretto — le righe si impilano
   ============================================================ */

/* --- Desktop stretto ------------------------------------------------ */
@media (max-width: 1200px) {
    .app-main { padding: var(--space-5) var(--space-5); }
    .banda-rossa { margin: 0 calc(-1 * var(--space-5)); padding: 1.5rem var(--space-5) 1.8rem; }
}

/* --- Fino a 992px: contenuti piu' densi, sidebar ANCORA in flusso ---
   Qui niente drawer: chi lavora con la finestra affiancata (o su tablet)
   deve poter cliccare la sidebar E la pagina insieme. La sidebar si
   stringe a 240px, e chi vuole ancora piu' spazio la collassa a rail
   col toggle di sempre (scelta che persiste). */
@media (max-width: 992px) {
    .sidebar { --sidebar-larghezza: 240px; }

    .app-main { padding: 1.1rem; }
    .banda-rossa { margin: 0 -1.1rem; padding: 1.3rem 1.1rem 1.5rem; }
    .page-title { font-size: 1.4rem; }

    /* Intestazione di pagina: da riga unica a titolo sopra, comandi sotto. */
    .page-header { gap: 0.75rem; }
    .page-header .page-title { flex: 1 0 100%; margin-bottom: 0.15rem; }
    .search-box { width: auto; flex: 1 1 200px; }

    /* Voci di menu e di dropdown a misura di dito (WCAG 2.5.5). */
    .sidebar-link { padding-top: 0.7rem; padding-bottom: 0.7rem; }
    .dropdown-item { padding-top: 0.6rem; padding-bottom: 0.6rem; }

    /* Il calendario settimanale non si comprime: sette giorni su 360px darebbero
       colonne da 43px. Scorre in orizzontale con la colonna delle ore ancorata,
       altrimenti si perde il riferimento dell'orario appena si scorre. */
    .cal-grid { overflow-x: auto; -webkit-overflow-scrolling: touch; }
    .cal-times {
        position: sticky;
        left: 0;
        z-index: var(--z-base);
        background: var(--surface);
    }
    .cal-day { min-width: 116px; }

    .mese-cella { min-height: 62px; }

    /* Modale a tutta larghezza utile, con il corpo che scorre da solo: su un
       telefono un form lungo dentro una modale centrata finisce sotto il bordo
       e il bottone di conferma diventa irraggiungibile. */
    .modal-dialog { margin: 0.5rem; }
    .modal-dialog-centered { min-height: calc(100% - 1rem); }
    .modal-body { max-height: 70vh; overflow-y: auto; }
    .modal-header { padding: 1rem 1rem 0.3rem; }
    .modal-body, .modal-footer { padding-left: 1rem; padding-right: 1rem; }
}

/* --- Telefono: SOLO qui la sidebar diventa drawer -------------------
   Sotto i 641px anche il rail ruberebbe un quinto dello schermo: la
   sidebar esce dal flusso e rientra dall'hamburger, sopra un velo.
   E' l'unica fascia in cui copre i contenuti — su richiesta esplicita:
   dal tablet in su si lavora sempre con sidebar e pagina affiancate. */
@media (max-width: 640px) {
    .topbar { display: flex; }

    .app-colonna { min-height: 100dvh; }

    /* Fuori schermo, non display:none: deve poter scorrere dentro e fuori, e
       restare nell'albero del documento perche' i link sono gli stessi. */
    .sidebar {
        position: fixed;
        top: 0;
        left: 0;
        height: 100vh;
        height: 100dvh;              /* Android: la barra URL cambia l'altezza
                                        del viewport, 100vh lascerebbe il footer
                                        della sidebar sotto il bordo */
        width: var(--sidebar-larghezza);
        min-width: var(--sidebar-larghezza);
        max-width: 86vw;
        transform: translateX(-100%);
        z-index: var(--z-drawer);
        box-shadow: none;
    }
    .drawer-aperto .sidebar {
        transform: translateX(0);
        box-shadow: 8px 0 32px rgba(20, 22, 28, 0.28);
    }

    .drawer-scrim { display: block; }
    .drawer-aperto .drawer-scrim { opacity: 1; pointer-events: auto; }

    /* Col drawer aperto la pagina sotto non deve scorrere: senza questo, su
       Android il trascinamento sul velo scorre il contenuto retrostante e si
       torna in cima alla lista appena si chiude il menu. */
    html:has(.drawer-aperto) { overflow: hidden; }

    /* Nel drawer il rail non esiste: il toggle e' l'hamburger e la sidebar
       o e' fuori schermo o e' larga. Annullare qui evita che uno stato
       .sidebar-compatta lasciato dal desktop produca un drawer di 76px. */
    .sidebar-compatta .sidebar {
        width: var(--sidebar-larghezza);
        min-width: var(--sidebar-larghezza);
    }
    .sidebar-compatta .sidebar-testo {
        position: static;
        width: auto;
        height: auto;
        margin: 0;
        overflow: visible;
        clip: auto;
        white-space: normal;
    }
    .sidebar-compatta .sidebar-header { flex-direction: row; padding: 1.4rem 1.35rem 1.1rem; }
    /* Il drawer e' sempre largo: torna il wordmark, via l'icona da rail. */
    .sidebar-compatta .sidebar-logo { display: block; }
    .sidebar-compatta .sidebar-icona-rail { display: none; }
    .sidebar-compatta .sidebar-nav { padding: 0 0.7rem; }
    .sidebar-compatta .sidebar-link { justify-content: flex-start; padding-left: 0.8rem; padding-right: 0.8rem; }
    .sidebar-compatta .sidebar-footer { flex-direction: row; padding: 0.9rem 1.35rem; }
    .sidebar-toggle { display: none; }        /* comanda l'hamburger della topbar */
}

/* --- Telefono stretto ----------------------------------------------- */
@media (max-width: 576px) {
    .app-main { padding: 0.85rem; }
    .banda-rossa { margin: 0 -0.85rem; padding: 1.15rem 0.85rem 1.35rem; }
    .page-title { font-size: 1.3rem; }

    /* Il bottone "Aggiungi" prende la riga: affiancato alla ricerca su 360px
       restava largo un'icona e mezza. */
    .page-header > .btn { flex: 1 0 100%; }
    .search-box { flex: 1 0 100%; }

    /* La card di lista si impila: titolo e sottotitolo sopra, menu sotto a
       destra. In riga, un nome lungo spingeva il menu "..." fuori dal bordo. */
    .item-card {
        flex-direction: column;
        align-items: stretch;
        gap: 0.5rem;
        padding: 0.85rem 1rem;
    }
    .item-card > :first-child { min-width: 0; }
    .item-card > :last-child { display: flex; justify-content: flex-end; }

    .dashboard-cards { grid-template-columns: 1fr 1fr; gap: 0.6rem; }
    .dash-card { padding: 0.9rem; }
    .dash-valore { font-size: 1.35rem; }

    .cal-day { min-width: 104px; }
    .mese-cella { min-height: 52px; padding: 3px 4px; }
    .mese-numero { font-size: 0.78rem; }
}

/* Schermi molto stretti (360px e meno): una colonna sola, niente eccezioni. */
@media (max-width: 400px) {
    .dashboard-cards { grid-template-columns: 1fr; }
}

/* ============================================================
   26. REDUCED MOTION — neutralizza ogni movimento residuo
   ============================================================ */
@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: 0.001ms !important;
        animation-delay: 0ms !important;         /* lo stagger non deve ritardare la comparsa */
        animation-iteration-count: 1 !important;
        transition-duration: 0.001ms !important;
        transition-delay: 0ms !important;
        scroll-behavior: auto !important;
    }
    /* Azzerare la durata rende lo spostamento istantaneo, non inesistente: gli stati che
       traslano o ruotano vanno tolti a mano, altrimenti restano salti secchi di posizione. */
    .btn:active, .btn-danger:hover, .btn-danger:active,
    .item-card-cliccabile:hover, .item-card-cliccabile:active,
    .dash-card[role=button]:hover, .dash-card[role=button]:active,
    .sidebar-link:hover, .sidebar-link:hover i,
    .sidebar-footer .btn-link:hover,
    .btn-close:hover,
    .cal-evento:hover { transform: none !important; }

    /* Il drawer e' l'eccezione: qui il transform NON e' decorazione, e' la
       posizione stessa dell'elemento. Azzerarlo come sopra lascerebbe la
       sidebar aperta a schermo in permanenza. Resta il salto istantaneo fra
       fuori e dentro, che e' esattamente cio' che reduced-motion chiede. */
    @media (max-width: 640px) {
        .sidebar { transform: translateX(-100%) !important; }
        .drawer-aperto .sidebar { transform: translateX(0) !important; }
    }
}

/* ============================================================
   27. FORCED COLORS (contrasto elevato di Windows)
   ============================================================
   In questa modalità il browser scarta le box-shadow: l'anello di focus del §2 sparirebbe.
   L'outline trasparente dichiarato lì sopravvive, e qui prende il colore di sistema. */
@media (forced-colors: active) {
    :focus-visible {
        outline-color: Highlight;
        outline-width: 3px;
    }
}
