/* DUC Magazzino Libri — Apple HIG polish (Round 2, Blocco E,
   design/2026-09-08-piano-round2.md §Blocco E). Niente rewrite: tema
   Filament via CSS + poche view. Registrato via Css::make('duc-hig', ...)
   in AdminPanelProvider DOPO duc-brand (l'ordine conta: qui sovrascriviamo
   variabili/selettori di Filament, duc-brand resta la fonte del brand/font
   custom) e via <link> in scan/layout.blade.php e mappa/layout.blade.php —
   stesso pattern di duc-brand.css/icons-animate.css, quindi questo file
   vive SIA dentro il pannello Filament (body.fi-body, dark via classe
   esplicita html.dark) SIA nelle pagine pubbliche /cerca, /s/{token},
   /mappa (nessun toggle dark, seguono @media(prefers-color-scheme:dark) —
   lezione Fase 10a/10b: ogni regola dark qui sotto che tocca le pagine
   pubbliche è scoped `body:not(.fi-body)` per non lasciare che la media
   query OS-level trapeli nel pannello Filament, che ha un toggle esplicito
   e non deve seguire l'OS. */

/* =========================================================================
   1. Tipografia — stack di sistema per la UI (Filament + scan + mappa).
   Barlow resta per lockup/H1 di pagina (duc-brand.css, invariato), JetBrains
   Mono per i codici (.duc-mono, invariato). --font-family è una custom
   property letta da --font-sans di Filament (font-sans: var(--font-family),
   ui-sans-serif, ...) — la reimpostiamo su html.fi (specificità 0,1,1) che
   batte il :root del blocco <style> inline di Filament (specificità 0,1,0),
   caricato DOPO i nostri asset ma con selettore meno specifico: niente
   !important necessario. ========================================== */
html.fi {
    --font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Text', 'Helvetica Neue', Inter, sans-serif;
}

/* Scala corpo testo: 15px desktop / 17px mobile (iOS body). Applicata al
   solo elemento <body> (eredita, non tocca le rem di Tailwind — niente
   rem sul tag <html> per non riscalare padding/icone di tutti i
   componenti Filament, che sono dimensionati in rem: rischio di rottura
   layout non giustificato per un ritocco tipografico). */
body.fi-body { font-size: 15px; }
@media (max-width: 768px) {
    body.fi-body { font-size: 17px; }
}
/* Caption 13px: badge e testo secondario Filament usano già text-xs
   (12px) / text-sm (14px) via Tailwind — nessuna sovrascrittura globale
   per non toccare centinaia di selettori interni (rischio "non rompere
   Filament"); i caption custom nelle view mobile sono già 13px
   (.duc-mono, badge-stato) o esplicitati sotto. */

/* =========================================================================
   2. Superfici e colori — sfondo grouped, card senza bordo, ombra leggera.
   ========================================================================= */
body.fi-body { background-color: #F2F2F7; }
html.dark body.fi-body { background-color: #000000; }

/* Card: Filament usa già rounded-xl (12px, invariato) ma con un "ring"
   (bordo sottile via box-shadow) — lo sostituiamo con l'ombra HIG piatta
   0 1px 2px rgba(0,0,0,.06) e, in dark, sfondo #1C1C1E (spec) al posto del
   gray-900 di Filament. Selettori scelti = i contenitori "carta" reali
   verificati nel CSS sorgente Filament (sezioni, tabelle, widget stat,
   modale, toast) — non un token globale (--gray-* è condiviso da troppi
   componenti non-carta: bordi, icone, sfondi disabilitati — sovrascriverlo
   avrebbe un raggio d'azione troppo ampio per essere verificato in questa
   sessione). */
.fi-section,
.fi-ta-ctn,
.fi-wi-stats-overview-stat,
.fi-modal-window:not(.fi-modal-slide-over *),
.fi-no-notification:not(.fi-inline) {
    box-shadow: 0 1px 2px rgba(0, 0, 0, .06) !important;
}
html.dark .fi-section,
html.dark .fi-ta-ctn,
html.dark .fi-wi-stats-overview-stat,
html.dark .fi-modal-window:not(.fi-modal-slide-over *),
html.dark .fi-no-notification:not(.fi-inline) {
    background-color: #1C1C1E !important;
    box-shadow: 0 1px 2px rgba(0, 0, 0, .3) !important;
}

/* Bottoni: raggio 10px (spec). Solo il raggio — altezza/densità del
   pulsante Filament (px-3 py-2, text-sm) restano quelle di default: sono
   condivise da centinaia di icon-button nelle tabelle, imporre 44px
   ovunque avrebbe rotto la densità delle liste (non richiesto dallo
   spec, che parla di "bottoni primari full-width nei FORM MOBILE"). */
.fi-btn { border-radius: 10px; }
.fi-input-wrp { border-radius: 10px; }

/* Round 2 E review fix: bottone primario pieno — Filament 4
   (ButtonComponentColorMap::resolveTextForEachBackground, vendor/filament/
   support/src/View/Components/ColorMaps/ButtonComponentColorMap.php)
   sceglie lo shade di sfondo in base al contrasto testo/sfondo, non al
   brand: per l'hue di #1961AC il testo scuro (950) supera 4.5:1 gia' sullo
   shade 600, quindi l'euristica scarta il candidato "testo chiaro su
   600/500" e ripiega sul fallback "sfondo 400 chiaro + testo scuro"
   (verificato via DOM: class fi-bg-color-400 + fi-text-color-950 in light
   mode). Risultato: bottone azzurro pallido con testo scuro invece di blu
   DUC pieno con testo bianco. Non e' un problema di duc-brand.css (nessuna
   sovrascrittura di --primary-*, verificato) ne' di duc-hig.css stesso
   (che prima di questo fix non toccava .fi-btn-color-primary): e' proprio
   l'algoritmo di scelta shade del vendor per QUESTO hue. Fix mirato ai soli
   bottoni pieni (":not(.fi-outlined)" esclude i bottoni outline, es. il
   piglio "Annulla" fuori da questa palette, e non tocca badge/link primary
   che restano sullo shade 700 leggibile — verificato via DOM, nessun fix
   necessario li'). Stesso trattamento in light e dark per coerenza brand
   (in dark il vendor gia' sceglieva 600/testo bianco, qui riallineato
   all'hex esatto invece dello shade approssimato). */
.fi-btn.fi-color-primary:not(.fi-outlined) {
    background-color: #1961AC !important;
    color: #ffffff !important;
}
.fi-btn.fi-color-primary:not(.fi-outlined):hover {
    background-color: #154F86 !important;
    color: #ffffff !important;
}
html.dark .fi-btn.fi-color-primary:not(.fi-outlined) {
    background-color: #1961AC !important;
    color: #ffffff !important;
}
html.dark .fi-btn.fi-color-primary:not(.fi-outlined):hover {
    background-color: #154F86 !important;
    color: #ffffff !important;
}

/* Colonna "Titolo" (Libri) / "libro.titolo" (Scatole, Movimenti): ->wrap()
   senza min-width lascia che l'algoritmo table-layout:auto del browser
   restringa la colonna al contenuto piu' corto, causando un wrap
   aggressivo (1-2 parole a riga) mentre altre colonne (es. l'ultima,
   azioni) restano piu' larghe del necessario. Selettore con il punto
   letterale escapato: Filament genera la classe dal nome colonna
   (fi-ta-cell-libro.titolo), non lo trasforma in trattino — verificato
   via DOM. */
.fi-ta-header-cell-titolo,
.fi-ta-cell-titolo,
.fi-ta-header-cell-libro\.titolo,
.fi-ta-cell-libro\.titolo {
    min-width: 22rem;
}

/* Form mobile: bottoni primari (header actions delle pagine Crea/Modifica,
   footer delle action modali) full-width, altezza 44px min, impilati. */
@media (max-width: 768px) {
    .fi-header-actions-ctn {
        width: 100%;
    }
    /* Feedback round2 (QA KO1, 2026-09-22): il markup di Filament v4 annida
       i bottoni dentro UN SOLO figlio diretto di .fi-header-actions-ctn,
       il vero contenitore flex `.fi-ac.fi-align-start` (verificato via DOM:
       .fi-header-actions-ctn ha childCount 1). La vecchia regola
       column-reverse/align-items/gap era scritta su .fi-header-actions-ctn
       stesso: essendo quel nodo un flex container con un solo elemento
       (il wrapper .fi-ac), la direzione invertita non aveva alcun effetto
       visibile sui bottoni — che restavano nell'ordine DOM naturale
       (`.fi-ac` e' `display:flex; flex-direction:row` di default). Le regole
       di impilamento vanno quindi sul vero contenitore, `.fi-header-actions-
       ctn .fi-ac`, non sul suo genitore.
       Direzione `column` (NON column-reverse come nella vecchia regola
       mai entrata in vigore): l'ordine visivo resta quello dell'array
       delle header actions, cioe' lo stesso che gli utenti vedevano gia'
       col wrap orizzontale — cosi' "Salva" (EditLibro) e "Nuovo libro"
       (ListLibros), primi nei rispettivi array, stanno in cima alla pila
       senza regole speciali, e nessun'altra pagina cambia ordine. */
    .fi-header-actions-ctn .fi-ac {
        display: flex;
        flex-direction: column;
        align-items: stretch;
        width: 100%;
        gap: .5rem;
    }
    .fi-header-actions-ctn .fi-btn,
    .fi-header-actions-ctn .fi-ac-action-group {
        width: 100%;
    }
    .fi-header-actions-ctn .fi-btn { min-height: 44px; }
    .fi-modal-footer-actions .fi-btn { min-height: 44px; }

    /* Lotto B: il tasto "Salva" in testata della scheda libro (EditLibro,
       classe duc-azione-salva) e' il primo dell'array e con la pila in
       ordine naturale qui sopra sta gia' in cima: la classe resta come
       aggancio esplicito (nessuna regola necessaria oggi). */

    /* Footer azioni delle pagine Crea/Modifica (Salva, Salva & nuovo,
       Annulla) — verificato via DOM (screenshot mobile-light-03-libro-form):
       vive in .fi-sc-actions > .fi-ac, non in .fi-header-actions-ctn. */
    .fi-sc-actions .fi-ac {
        flex-direction: column-reverse;
        align-items: stretch;
        width: 100%;
        gap: .5rem;
    }
    .fi-sc-actions .fi-ac .fi-btn { width: 100%; min-height: 44px; }

    /* Round 2 E review fix: la tab bar e' position:fixed, quindi copre
       QUALSIASI contenuto che si trovi nella sua banda (ultimi 49px +
       safe-area del viewport) a QUALUNQUE scroll — non solo l'ultimo
       elemento a fine pagina. Verificato via getBoundingClientRect() a
       scrollY=0: su un form corto le azioni Salva/Salva&nuovo/Annulla
       possono atterrare esattamente li' al primo render. Il padding-bottom
       di body.fi-body (sezione 3 sotto) copre solo la fine reale del
       documento; qui aggiungiamo un margine dopo il blocco azioni cosi'
       la banda tab-bar resta sempre libera indipendentemente da quanto e'
       lungo il form sopra. */
    .fi-sc-actions .fi-ac {
        margin-bottom: calc(49px + env(safe-area-inset-bottom) + 16px);
    }

    /* Round 6 B2.1: stesso problema del blocco sopra ma sulle liste
       Filament (/admin/libri, /admin/scatole, /admin/movimenti). Il
       padding-bottom di body.fi-body (sezione 3) copre solo la fine reale
       del documento HTML, ma .fi-main-ctn e' un flex column min-height:
       100dvh — su una tabella corta (poche righe) il contenuto puo'
       comunque atterrare nella banda della tab bar prima che il body
       scrollabile abbia margine sufficiente per spingerlo oltre.
       Aggiungiamo margine dopo l'ultimo blocco reale della pagina
       (paginazione se presente, altrimenti il contenitore tabella) cosi'
       le azioni di riga dell'ultima riga e i controlli di paginazione
       restano sempre sopra la tab bar, indipendentemente da quante righe
       ci sono. Misurato: bar top ~610px, link ultima riga fino a ~671px
       (overlap ~61px) prima del fix — vedi
       reports/2026-09-15-round5-evidence/audit/master/m2c-scatole-list-overlap.json. */
    .fi-pagination {
        margin-bottom: calc(49px + env(safe-area-inset-bottom) + 16px);
    }
    .fi-ta-ctn:last-of-type {
        margin-bottom: calc(49px + env(safe-area-inset-bottom) + 16px);
    }
    .fi-page-content > *:last-child {
        margin-bottom: calc(49px + env(safe-area-inset-bottom) + 16px);
    }
}

/* =========================================================================
   3. Tab bar inferiore mobile (Filament) — 5 azioni principali (Home/
   Libri/Scatole/Scansiona/Altro) al posto della sidebar hamburger.
   Round 2b (2026-09-09, feedback operatore "barra scarna"): "Altro" non
   riapre più la sidebar Filament — apre un bottom sheet proprio (§3b) con
   tutte le altre voci di navigazione. L'hamburger di default resta
   nascosto sotto 768px: il foglio "Altro" copre già ogni voce che la
   sidebar mostrerebbe (generate da filament()->getNavigation(), stesso
   canAccess/shouldRegisterNavigation), quindi ripristinarlo duplicherebbe
   l'azione senza aggiungere nulla — l'unica cosa che la sidebar ha e il
   foglio no è il pannello di ricerca globale (§3b nota in fondo).
   Markup: resources/views/filament/partials/tab-bar-mobile.blade.php,
   iniettato via renderHook(BODY_END). z-index 20: sotto il foglio "Altro"
   e la sidebar/overlay Filament (z-30, §3b) così quando si aprono come
   drawer/sheet coprono la tab bar, come atteso. ========================= */
.duc-tabbar { display: none; }

/* Round 6 M: durante il pseudo-fullscreen della mappa (fallback iOS/WebKit
   quando l'elemento non ha Fullscreen API — vedi resources/views/mappa/
   _scaffale.blade.php) la tab bar deve sparire davvero (display:none), non
   solo restare sotto z-index: a schermi piccoli sarebbe comunque visibile
   sotto la mappa a posizione fixed. */
body:has(.duc-pseudo-fullscreen) .duc-tabbar { display: none !important; }

@media (max-width: 768px) {
    body.fi-body .fi-topbar-open-sidebar-btn { display: none !important; }

    body.fi-body { padding-bottom: calc(49px + env(safe-area-inset-bottom)); }

    .duc-tabbar {
        display: flex;
        position: fixed;
        left: 0;
        right: 0;
        bottom: 0;
        z-index: 20;
        height: calc(49px + env(safe-area-inset-bottom));
        padding-bottom: env(safe-area-inset-bottom);
        background: rgba(249, 249, 249, .82);
        backdrop-filter: blur(20px) saturate(180%);
        -webkit-backdrop-filter: blur(20px) saturate(180%);
        border-top: 1px solid rgba(60, 60, 67, .29);
    }
    html.dark .duc-tabbar {
        background: rgba(22, 22, 24, .78);
        border-top-color: rgba(84, 84, 88, .6);
    }
    /* La tab bar vive anche dentro scan/layout.blade.php (pagina pubblica,
       nessun toggle .dark — segue l'OS). Senza questa regola scoped, in
       dark-mode reale la tab bar restava chiara mentre il resto della
       pagina scuro (bug trovato via screenshot mobile-dark-10-cerca in
       questa stessa sessione — stesso pattern di leak di Fase 10a/10b). */
    @media (prefers-color-scheme: dark) {
        body:not(.fi-body) .duc-tabbar {
            background: rgba(22, 22, 24, .78);
            border-top-color: rgba(84, 84, 88, .6);
        }
    }

    .duc-tabbar-item {
        flex: 1 1 0;
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        gap: 2px;
        border: none;
        background: none;
        padding: 0;
        /* #8A8A8E (iOS "tertiaryLabel" nominale) su sfondo translucido chiaro
           misura ~3.2:1 con getComputedStyle+luminanza — sotto WCAG AA 4.5:1
           per testo 10px non-bold. Scurito a #6E6E73 -> ~5:1 (adversarial
           check di questa sessione, vedi report). */
        color: #6E6E73;
        font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Text', 'Helvetica Neue', Inter, sans-serif;
        font-size: 10px;
        font-weight: 500;
        text-decoration: none;
        cursor: pointer;
        -webkit-tap-highlight-color: transparent;
    }
    .duc-tabbar-icon { width: 24px; height: 24px; }
    .duc-tabbar-item.is-active { color: #1961AC; }
    html.dark .duc-tabbar-item { color: #98989F; }
    html.dark .duc-tabbar-item.is-active { color: #4f9fe0; }
    @media (prefers-color-scheme: dark) {
        body:not(.fi-body) .duc-tabbar-item { color: #98989F; }
        body:not(.fi-body) .duc-tabbar-item.is-active { color: #4f9fe0; }
    }

    /* Round 6 Blocco 1: i controlli "Scansiona QR"/"Esci" nel top-bar di
       scan/mappa layout diventano ridondanti con la tab bar (voci
       Scansiona/Menu) sotto 768px — nascosti qui, restano visibili su
       desktop dove non c'e' tab bar (vedi scan/layout.blade.php,
       mappa/layout.blade.php). */
    .duc-desktop-only { display: none !important; }
}

/* =========================================================================
   3b. Foglio "Altro" (Round 2b, 2026-09-09) — bottom sheet proprio con la
   griglia di TUTTE le voci di navigazione Filament non già in tab bar
   (Movimenti, Posizioni, Scaffali, Inventario, Import, Etichette, Report,
   Mappa, Registro/Utenti se autorizzati) + riga utente/azioni in fondo.
   Markup generato in tab-bar-mobile.blade.php da filament()->getNavigation()
   (rispetta canAccess di ogni Resource/Page). Overlay+pannello statici
   (niente Alpine/Livewire: il partial vive fuori dal componente Livewire
   di pagina), apertura/chiusura via [hidden] + classe .is-open, JS inline
   nello stesso blade. z-index 30: stesso livello della sidebar/overlay
   Filament (§3), sopra la tab bar (z-index 20).
   NON sostituisce la sidebar Filament: quella resta raggiungibile solo se
   l'hamburger viene ripristinato (oggi nascosto, §3) — nessuna perdita
   reale: l'unica cosa che la sidebar aveva e il foglio non duplica è la
   ricerca globale Filament, che pero' NON vive nella sidebar ma nel
   topbar (fi-topbar-end, sempre renderizzato, nessuna regola qui la
   nasconde sotto 768px — verificato in vendor/filament/filament/resources/
   views/livewire/topbar.blade.php: globalSearchPosition di default e'
   Topbar quando hasTopbar() e' true, mai Sidebar in questa app). Il campo
   di ricerca globale resta quindi raggiungibile su mobile esattamente
   come su desktop — importante perche' e' anche il punto di innesco del
   trigger "modalità riservata" (vedi riservata/modal.blade.php) per
   master/admin. Disponibile SOLO sotto 768px, stesso breakpoint della tab bar.
   ========================================================================= */
.duc-sheet-overlay { display: none; }

@media (max-width: 768px) {
    .duc-sheet-overlay {
        display: block;
        position: fixed;
        inset: 0;
        z-index: 30;
        background: rgba(0, 0, 0, 0);
        transition: background-color 250ms cubic-bezier(.32, .72, 0, 1);
    }
    .duc-sheet-overlay.is-open {
        background: rgba(0, 0, 0, .4);
    }
    .duc-sheet-overlay[hidden] { display: none; }

    .duc-sheet {
        position: absolute;
        left: 0;
        right: 0;
        bottom: 0;
        max-height: min(80dvh, calc(100dvh - env(safe-area-inset-top) - 24px));
        overflow-y: auto;
        -webkit-overflow-scrolling: touch;
        background: rgba(249, 249, 249, .96);
        backdrop-filter: blur(20px) saturate(180%);
        -webkit-backdrop-filter: blur(20px) saturate(180%);
        border-radius: 16px 16px 0 0;
        padding: 8px 16px max(16px, env(safe-area-inset-bottom)) max(16px, env(safe-area-inset-left));
        padding-right: max(16px, env(safe-area-inset-right));
        transform: translateY(100%);
        transition: transform 250ms cubic-bezier(.32, .72, 0, 1);
    }
    .duc-sheet-overlay.is-open .duc-sheet { transform: translateY(0); }
    html.dark .duc-sheet {
        background: rgba(22, 22, 24, .96);
    }
    @media (prefers-color-scheme: dark) {
        body:not(.fi-body) .duc-sheet { background: rgba(22, 22, 24, .96); }
    }

    .duc-sheet-handle {
        width: 36px;
        height: 5px;
        border-radius: 999px;
        background: rgba(120, 120, 128, .36);
        margin: 8px auto 12px;
    }
    html.dark .duc-sheet-handle { background: rgba(140, 140, 148, .48); }
    @media (prefers-color-scheme: dark) {
        body:not(.fi-body) .duc-sheet-handle { background: rgba(140, 140, 148, .48); }
    }

    .duc-sheet-grid {
        display: grid;
        grid-template-columns: repeat(3, 1fr);
        gap: 4px;
    }
    .duc-sheet-item {
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        gap: 6px;
        /* 76px min-height: garantisce >=44px di tap target reale anche con
           label su 2 righe (icona 28px + label 2 righe 11px + gap). */
        min-height: 76px;
        padding: 10px 4px;
        border-radius: 12px;
        text-decoration: none;
        color: #1C1C1E;
        text-align: center;
        -webkit-tap-highlight-color: transparent;
    }
    .duc-sheet-item:active { background: rgba(120, 120, 128, .16); }
    .duc-sheet-item-icon svg { width: 28px; height: 28px; }
    .duc-sheet-item-label {
        font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Text', 'Helvetica Neue', Inter, sans-serif;
        font-size: 12px;
        font-weight: 500;
        line-height: 1.2;
    }
    .duc-sheet-item.is-active { color: #1961AC; }
    .duc-sheet-item.is-active .duc-sheet-item-icon svg { color: #1961AC; }
    html.dark .duc-sheet-item { color: #F2F2F7; }
    html.dark .duc-sheet-item.is-active,
    html.dark .duc-sheet-item.is-active .duc-sheet-item-icon svg { color: #4f9fe0; }

    /* Round 6 fix (coordinatore, misurato su /s/{token}: user card a
       y=713 in un foglio alto 527px, sotto la piega): user card in cima
       al foglio, riga compatta — avatar+nome+ruolo+Esci sulla stessa
       riga — cosi' resta visibile senza scroll all'apertura. Sostituisce
       .duc-sheet-footer (rimossa: il footer impilato spingeva la user
       card in fondo). */
    .duc-sheet-utente {
        display: flex;
        align-items: center;
        gap: 10px;
        padding: 4px 4px 12px;
        margin-bottom: 8px;
        border-bottom: 1px solid rgba(60, 60, 67, .29);
    }
    html.dark .duc-sheet-utente { border-bottom-color: rgba(84, 84, 88, .6); }
    .duc-sheet-utente .fi-avatar { width: 36px; height: 36px; flex-shrink: 0; }
    .duc-sheet-utente-info { flex: 1 1 auto; min-width: 0; }
    .duc-sheet-utente-nome {
        font-size: 15px;
        font-weight: 600;
        color: #1C1C1E;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }
    html.dark .duc-sheet-utente-nome { color: #F2F2F7; }

    /* Riga secondaria (tema/blocca riservata), solo quando presente —
       sotto la user card, sopra i gruppi di navigazione. */
    .duc-sheet-utente-extra {
        display: flex;
        align-items: center;
        gap: 8px;
        padding-bottom: 10px;
        margin-bottom: 4px;
        border-bottom: 1px solid rgba(60, 60, 67, .29);
    }
    html.dark .duc-sheet-utente-extra { border-bottom-color: rgba(84, 84, 88, .6); }
    .duc-sheet-utente-extra .fi-theme-switcher { flex-shrink: 0; }
    .duc-sheet-utente-extra .duc-sheet-azione-form { flex: 1 1 auto; }

    .duc-sheet-azione-form { margin: 0; }
    .duc-sheet-utente-esci-form { flex-shrink: 0; width: auto; }
    .duc-sheet-azione {
        display: block;
        width: 100%;
        min-height: 44px;
        padding: 10px 14px;
        border: none;
        border-radius: 10px;
        background: rgba(120, 120, 128, .12);
        color: #1961AC;
        font-size: 15px;
        font-weight: 600;
        text-align: center;
        cursor: pointer;
        -webkit-tap-highlight-color: transparent;
    }
    /* Variante compatta: bottone "Esci" nella riga utente e "Blocca
       riservata" nella riga extra — larghezza intrinseca, non piena, cosi'
       condividono la riga con avatar/nome o col theme switcher. */
    .duc-sheet-azione-compatta {
        width: auto;
        min-height: 36px;
        padding: 8px 14px;
        font-size: 14px;
    }
    /* Round 2c a11y fix (report v6-a11y §Contrasto misurato): #4f9fe0 su
       rgba(120,120,128,.24) alpha-blended sopra .duc-sheet = 3.63:1, sotto
       soglia WCAG 4.5. Sfondo solido #1C1C1E (stesso token gia' usato per
       le card scure altrove in questo file, §2) + testo #0A84FF (blu
       "system" iOS dark) = 4.66:1, verificato WCAG. */
    html.dark .duc-sheet-azione { background: #1C1C1E; color: #0A84FF; }
    .duc-sheet-azione-pericolo { color: #b91c1c; }
    html.dark .duc-sheet-azione-pericolo { color: #f87171; }

    /* Round 6 Blocco 1: il foglio ora raggruppa le voci (Magazzino/
       Catalogo/Amministrazione, App\Support\NavigazioneMobile::sheetGroups())
       — titolo di gruppo + label secondaria del ruolo nella user card, unici
       elementi nuovi rispetto a Round 2b. */
    .duc-sheet-gruppo-titolo {
        margin: 14px 4px 6px;
        font-size: 12px;
        font-weight: 700;
        text-transform: uppercase;
        letter-spacing: .02em;
        color: #6E6E73;
    }
    .duc-sheet-gruppo-titolo:first-of-type { margin-top: 4px; }
    html.dark .duc-sheet-gruppo-titolo { color: #98989F; }

    .duc-sheet-utente-ruolo {
        font-size: 13px;
        color: #6E6E73;
    }
    html.dark .duc-sheet-utente-ruolo { color: #98989F; }
}

/* =========================================================================
   4. Modali Filament come bottom sheet su mobile. Le classi
   fi-transition-* sono classi CSS reali toggled da Alpine (x-transition
   con soli nomi di classe, non sintassi transition inline) — vedi
   vendor/filament/support/resources/views/components/modal/index.blade.php.
   Slide-over invariati (già a schermo intero via .fi-modal-slide-over).
   ========================================================================= */
@media (max-width: 768px) {
    .fi-modal:not(.fi-modal-slide-over):not(.fi-width-screen) > .fi-modal-window-ctn {
        display: flex;
        align-items: flex-end;
        justify-content: center;
        padding: 0;
    }
    .fi-modal:not(.fi-modal-slide-over):not(.fi-width-screen) > .fi-modal-window-ctn > .fi-modal-window {
        width: 100%;
        max-width: 100%;
        margin: 0;
        border-radius: 16px 16px 0 0;
        max-height: min(85dvh, calc(100dvh - env(safe-area-inset-top) - 24px));
        overflow-y: auto;
        padding-top: 1.25rem;
        padding-bottom: env(safe-area-inset-bottom);
        position: relative;
        transition-property: transform, opacity;
        transition-timing-function: cubic-bezier(.32, .72, 0, 1);
    }
    .fi-modal:not(.fi-modal-slide-over):not(.fi-width-screen) > .fi-modal-window-ctn > .fi-modal-window.fi-transition-enter,
    .fi-modal:not(.fi-modal-slide-over):not(.fi-width-screen) > .fi-modal-window-ctn > .fi-modal-window.fi-transition-leave {
        transition-duration: 250ms;
    }
    /* Handle 36x5px in cima al foglio. */
    .fi-modal:not(.fi-modal-slide-over):not(.fi-width-screen) > .fi-modal-window-ctn > .fi-modal-window::before {
        content: '';
        position: absolute;
        top: 8px;
        left: 50%;
        transform: translateX(-50%);
        width: 36px;
        height: 5px;
        border-radius: 999px;
        background: rgba(120, 120, 128, .36);
    }
    html.dark .fi-modal:not(.fi-modal-slide-over):not(.fi-width-screen) > .fi-modal-window-ctn > .fi-modal-window::before {
        background: rgba(140, 140, 148, .48);
    }
    /* Stato iniziale/finale: da sotto lo schermo invece di scala+opacità. */
    .fi-modal:not(.fi-modal-slide-over):not(.fi-width-screen) .fi-transition-enter-start,
    .fi-modal:not(.fi-modal-slide-over):not(.fi-width-screen) .fi-transition-leave-end {
        transform: translateY(100%) !important;
        opacity: 1 !important;
    }
    .fi-modal:not(.fi-modal-slide-over):not(.fi-width-screen) .fi-transition-enter-end,
    .fi-modal:not(.fi-modal-slide-over):not(.fi-width-screen) .fi-transition-leave-start {
        transform: translateY(0) !important;
        opacity: 1 !important;
    }
}

/* =========================================================================
   5. Controlli — segmented control (fi-tabs, se usati come filtro),
   toggle iOS. ========================================================= */
.fi-tabs:not(.fi-contained) {
    background: rgba(120, 120, 128, .12);
    box-shadow: none !important;
    border-radius: 10px;
}
html.dark .fi-tabs:not(.fi-contained) { background: rgba(120, 120, 128, .24); }
.fi-tabs:not(.fi-contained) .fi-tabs-item.fi-active {
    background: #ffffff;
    box-shadow: 0 1px 2px rgba(0, 0, 0, .12);
    border-radius: 8px;
}
html.dark .fi-tabs:not(.fi-contained) .fi-tabs-item.fi-active {
    background: #3A3A3C;
}

/* Toggle iOS: track 51x31, verde #34C759 acceso. Il traslato "on" resta
   translate-x-5 (20px, classe Tailwind invariata): con track 51px e bordo
   2px lo spazio utile è 47px, meno il pomello 27px = 20px — combacia. */
.fi-toggle {
    width: 51px;
    height: 31px;
}
.fi-toggle > :first-child { width: 27px; height: 27px; }
.fi-toggle.fi-toggle-on { background-color: #34C759 !important; }

/* =========================================================================
   6. Feedback — toast in alto centrale, blur, stati vuoti (icona+frase
   già pattern standard Filament EmptyState, nessuna modifica necessaria).
   ========================================================================= */
.fi-no {
    top: max(1rem, env(safe-area-inset-top)) !important;
    bottom: auto !important;
    inset-inline: 1rem !important;
    width: fit-content;
    max-width: calc(100vw - 2rem);
    margin-inline: auto;
    transform: none;
    flex-direction: column !important;
}

.fi-ta { scroll-margin-top: 5rem; }
.duc-save-confirmation { color: #15803d; font-size: .875rem; font-weight: 500; }
html.dark .duc-save-confirmation { color: #86efac; }
@media (max-width: 767px) {
    .duc-save-actions .fi-sc-actions .fi-ac { margin-bottom: 0; }
    .duc-save-actions { padding-bottom: calc(49px + env(safe-area-inset-bottom) + 16px); }
}
.duc-da-verificare, .duc-da-verificare > td { background-color: #fff8e6; }
.duc-da-verificare:hover, .duc-da-verificare:hover > td { background-color: #fff0c2; }
html.dark .duc-da-verificare, html.dark .duc-da-verificare > td { background-color: #3b301c; }
html.dark .duc-da-verificare:hover, html.dark .duc-da-verificare:hover > td { background-color: #4a3b20; }
.fi-no-notification:not(.fi-inline) {
    border-radius: 14px;
    backdrop-filter: blur(20px) saturate(180%);
    -webkit-backdrop-filter: blur(20px) saturate(180%);
    background-color: rgba(255, 255, 255, .85) !important;
}
html.dark .fi-no-notification:not(.fi-inline) {
    background-color: rgba(28, 28, 30, .82) !important;
}

/* =========================================================================
   6b. Round 6 B2.5 — "Conferma scarico"/"Conferma carico"
   (scan/scatola.blade.php) erano entrambi blu .principale, indistinguibili
   a colpo d'occhio. resources/views/scan/layout.blade.php e' fuori
   ownership per questo blocco (Do NOT edit), quindi qui in duc-hig.css
   (scoped body:not(.fi-body), pagine scan/mappa pubbliche) invece di
   aggiungere un token --successo-forte nel <style> di quel layout.
   var(--pericolo) esiste gia' li' (root del layout, non toccato) e passa
   AA su sfondo pieno con testo bianco (#b91c1c ~6.5:1, gia' verificato
   altrove nello stesso file come colore testo). --successo (#16a34a) su
   sfondo pieno con testo bianco misura invece solo ~3.3:1 (sotto AA
   4.5:1) — qui usiamo il valore letterale #15803d (~5:1 con testo
   bianco) al posto di un var(), visto che non possiamo dichiarare un
   nuovo custom property nel file dei token. "Sposta" resta blu neutro
   (.principale), invariato. ========================================= */
body:not(.fi-body) button.principale-scarico {
    background: var(--pericolo);
}
body:not(.fi-body) button.principale-scarico:active {
    background: #991616;
}
body:not(.fi-body) button.principale-carico {
    background: #15803d;
}
body:not(.fi-body) button.principale-carico:active {
    background: #0f5c2c;
}

/* =========================================================================
   7. Superfici pubbliche mobile (scan/mappa) — tab bar identica, safe
   area, iOS type scale già presente nei layout (body 15-16px, caption
   13px .duc-mono) — qui solo la tab bar e il contenimento sotto di essa.
   Dark qui SEMPRE scoped body:not(.fi-body): niente toggle in queste
   pagine, seguono l'OS per design (lezione Fase 10a). ==================== */
body:not(.fi-body) { padding-bottom: 0; }
@media (max-width: 768px) {
    body:not(.fi-body):has(.duc-tabbar) {
        padding-bottom: calc(49px + env(safe-area-inset-bottom));
    }

    /* Round 2 E review fix: stesso problema della sezione 2 (tab bar fixed
       che copre la sua banda a qualunque scroll, non solo a fine pagina) ma
       sulle pagine scan pubbliche — riprodotto su /s/{token} (scarico):
       "Conferma scarico" (button.principale) atterra GIA' a scrollY=0
       dentro la banda della tab bar su schermi 390x844 (verificato via
       getBoundingClientRect, non un artefatto dello screenshot fullPage —
       il form "Vendita/Conto vendita/Omaggio" e' abbastanza alto da
       spingere il CTA li'). Un margin-bottom da solo non basta: sposta
       solo cio' che viene DOPO, non il bottone stesso, che resta nella
       stessa posizione di flusso. Serve che il CTA si stacchi dal flusso
       normale una volta raggiunto: position:sticky con bottom = altezza
       tab bar (+ respiro) lo tiene sempre visibile appena sopra la tab bar
       mentre si scrolla, senza mai finirci sotto — pattern standard per
       CTA di conferma sopra una tab bar iOS, puro CSS (nessuna modifica a
       markup/JS). Si aggancia al genitore scrollabile (main, body): resta
       sticky finche' il blocco form che lo contiene e' a schermo. */
    body:not(.fi-body) button.principale,
    body:not(.fi-body) a.principale,
    body:not(.fi-body) input[type="submit"] {
        position: sticky;
        bottom: calc(49px + env(safe-area-inset-bottom) + 12px);
        z-index: 5;
    }

    body:not(.fi-body):has(.duc-tabbar) button.principale,
    body:not(.fi-body):has(.duc-tabbar) a.principale,
    body:not(.fi-body):has(.duc-tabbar) input[type="submit"] {
        margin-bottom: calc(49px + env(safe-area-inset-bottom) + 16px);
    }

    /* Round 6 B2.1: pagine scan senza CTA .principale in fondo (es. /cerca
       con lista risultati lunga, /libri/{id} scheda con azioni non
       .principale, /mappa legenda) — il padding-bottom del body basta di
       solito, ma qui aggiungiamo margine di sicurezza sull'ultimo blocco
       reale di <main> cosi' l'ultimo elemento interagibile resta sempre
       sopra la tab bar anche se il contenuto e' un elenco variabile in
       lunghezza (last-child cambia a runtime via Livewire/JS). */
    body:not(.fi-body):has(.duc-tabbar) main > *:last-child {
        margin-bottom: calc(49px + env(safe-area-inset-bottom) + 16px);
    }

    /* Round 5 F1 fix: .form-ricerca (resources/views/scan/layout.blade.php)
       e' una riga flex con l'input di /cerca — il submit "Cerca" inline
       (button.principale) e' un figlio di quella riga, non un CTA di fondo
       pagina come i due blocchi sopra. Il margin-bottom sticky pensato per
       il CTA di fine form entra nel cross-size del flex item e stira
       l'input alla stessa altezza (126px). Qui il bottone resta nel
       normale flusso del form: niente sticky, niente margine. Selettore
       piu' specifico delle regole sopra (stessa origine, stesso ordine di
       cascata) per vincere senza toccare gli altri CTA principale. */
    body:not(.fi-body) .form-ricerca button.principale,
    body:not(.fi-body):has(.duc-tabbar) .form-ricerca button.principale {
        position: static;
        bottom: auto;
        margin-bottom: 0;
    }
}

/* =========================================================================
   8. Toast Livewire / conferma con vibrazione — nessun CSS necessario,
   vedi resources/views/scan/conferma.blade.php per lo script vibrate(10).
   ========================================================================= */

/* =========================================================================
   9. Round 2c a11y — tap target 44px su mobile (report v6-a11y §Tap target
   < 44×44). Solo sotto 768px: la densita' desktop (icon-btn 36x36 di
   default Filament, sort header senza padding) resta invariata sopra
   768px — non richiesto dallo spec e romperebbe la densita' delle liste
   desktop (stesso principio di §1 bottoni). .fi-ta-actions e' il
   contenitore reale delle azioni di riga Filament (Trovalo/Modifica/
   Sposta/Storna/Stampa etichetta — verificato in vendor/filament/tables).
   ========================================================================= */
@media (max-width: 768px) {
    .fi-ta-actions a,
    .fi-ta-actions button {
        display: inline-flex;
        align-items: center;
        min-height: 44px;
        padding-top: 12px;
        padding-bottom: 12px;
    }
    .fi-ta-header-cell-sort-btn,
    .fi-icon-btn,
    .fi-user-menu-trigger,
    .fi-topbar-item-btn,
    .fi-topbar-database-notifications-btn {
        min-width: 44px;
        min-height: 44px;
        display: inline-flex;
        align-items: center;
        justify-content: center;
    }
}

/* =========================================================================
   10. Round 2c a11y — focus visibile (WCAG 2.4.7). Filament azzera
   l'outline su molti elementi via utility Tailwind (outline:none/ring
   trasparente, report v6-a11y §Tastiera: 22/25 elementi senza indicatore)
   — :focus-visible da solo perderebbe contro un selettore con classe
   Tailwind di pari o maggiore specificita', quindi !important. Un solo
   set di regole per pannello Filament E pagine pubbliche scan/mappa
   (questo file vive in entrambi i contesti, vedi nota di testa) — dark
   scoped come il resto del file: html.dark esplicito nel pannello
   (toggle), @media(prefers-color-scheme:dark) body:not(.fi-body) nelle
   pagine pubbliche (seguono l'OS, nessun toggle li'). ========================== */
a:focus-visible,
button:focus-visible,
[role="button"]:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
.fi-ta-header-cell button:focus-visible {
    outline: 2px solid #1961AC !important;
    outline-offset: 2px !important;
}
html.dark a:focus-visible,
html.dark button:focus-visible,
html.dark [role="button"]:focus-visible,
html.dark input:focus-visible,
html.dark select:focus-visible,
html.dark textarea:focus-visible,
html.dark .fi-ta-header-cell button:focus-visible {
    outline-color: #4C9AFF !important;
}
@media (prefers-color-scheme: dark) {
    body:not(.fi-body) a:focus-visible,
    body:not(.fi-body) button:focus-visible,
    body:not(.fi-body) [role="button"]:focus-visible,
    body:not(.fi-body) input:focus-visible,
    body:not(.fi-body) select:focus-visible,
    body:not(.fi-body) textarea:focus-visible,
    body:not(.fi-body) .fi-ta-header-cell button:focus-visible {
        outline-color: #4C9AFF !important;
    }
}

/* =========================================================================
   11. Round 2c a11y — prefers-reduced-motion (WCAG 2.3.3). Il preflight
   Filament azzera gia' le transizioni SOLO dentro il pannello (regola
   generata da Tailwind, non copre le pagine pubbliche scan/mappa ne' le
   transizioni esplicite di questo file — sheet "Altro" §3b, icone
   icons-animate.css). Regola universale, un solo punto per tutti i
   contesti. ========================================================= */
@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
        scroll-behavior: auto !important;
    }
}

/* Round 3: keep confirmation in its form; sticky bottom overlapped motives. */
@media (max-width: 768px) {
    #pannello-scarico button[type="submit"],
    #pannello-carico button[type="submit"],
    #pannello-sposta button[type="submit"] { position: static; margin-bottom: 0; }
    .fi-ta-header-cell-titolo, .fi-ta-cell-titolo,
    .fi-ta-header-cell-libro\.titolo, .fi-ta-cell-libro\.titolo { min-width: 10rem; }
    .fi-ta-cell-copertina-preview { padding-left: .65rem; padding-right: .25rem; }
}

/* Book records keep identity, cover, stock and actions together on phones. */
@media (max-width: 768px) {
    .duc-catalogo .fi-ta-table, .duc-catalogo .fi-ta-table tbody { display:block; width:100%; }
    .duc-catalogo .fi-ta-table thead { display:none; }
    .duc-catalogo .fi-ta-row { display:grid; grid-template-columns:64px minmax(0,1fr); padding:16px; gap:8px 12px; }
    .duc-catalogo .fi-ta-row > td { padding:0; min-width:0; }
    .duc-catalogo .fi-ta-cell-copertina-preview { grid-column:1; grid-row:1 / span 3; }
    .duc-catalogo .fi-ta-cell-titolo { grid-column:2; grid-row:1; min-width:0; overflow-wrap:anywhere; }
    .duc-catalogo .fi-ta-cell-giacenza-totale { grid-column:2; grid-row:2; }
    .duc-catalogo .fi-ta-cell-sottoscorta-badge { grid-column:2; grid-row:3; }
    .duc-catalogo .fi-ta-cell:has(.fi-ta-actions) { grid-column:1 / -1; }
}
@media (max-width: 768px) {
    .duc-catalogo .fi-ta-cell .fi-ta-text,
    .duc-catalogo .fi-ta-cell .fi-ta-image { padding:0; }
    .duc-catalogo .fi-ta-cell-sottoscorta-badge:not(:has(.fi-badge)) { display:none; }
    .duc-catalogo .fi-ta-cell-copertina-preview { grid-row:1 / span 2; }
}

/* Lotto A (A4, feedback round2): tablet 768-1024px — stessa strategia "a
   scheda" del blocco <768px qui sopra, estesa perche' a queste larghezze
   (sidebar 14rem inclusa) le colonne visibili di default (copertina,
   titolo+autore, giacenza, stato, N. scatole, Anno/edizione + azioni) non
   entrano in una riga di tabella normale senza scroll orizzontale.
   scatole_count e anno_edizione hanno `visibleFrom('md')` in LibrosTable:
   a differenza del blocco <768px, in questo intervallo SONO nel DOM (md =
   768px in su) e vanno quindi posizionate esplicitamente nella grid —
   altrimenti l'auto-placement le sovrapporrebbe alle celle gia'
   posizionate sopra/sotto. */
@media (min-width: 768px) and (max-width: 1024px) {
    .duc-catalogo .fi-ta-table, .duc-catalogo .fi-ta-table tbody { display:block; width:100%; }
    .duc-catalogo .fi-ta-table thead { display:none; }
    .duc-catalogo .fi-ta-row {
        display:grid;
        grid-template-columns:72px minmax(0,1fr) auto;
        column-gap:12px;
        row-gap:4px;
        padding:16px;
        align-items:start;
    }
    .duc-catalogo .fi-ta-row > td { padding:0; min-width:0; }
    /* Cella selezione (checkbox bulk action): senza una posizione
       esplicita l'auto-placement della grid la spingerebbe in una riga
       tutta sua in fondo (tutte le righe 1-5 sotto sono gia' piene) —
       qui accanto al titolo, in alto a destra. */
    .duc-catalogo .fi-ta-selection-cell { grid-column:3; grid-row:1; justify-self:end; }
    .duc-catalogo .fi-ta-cell-copertina-preview { grid-column:1; grid-row:1 / span 4; }
    .duc-catalogo .fi-ta-cell-titolo { grid-column:2; grid-row:1; min-width:0; overflow-wrap:anywhere; }
    .duc-catalogo .fi-ta-cell-giacenza-totale { grid-column:2; grid-row:2; min-width:0; }
    .duc-catalogo .fi-ta-cell-stato-catalogo { grid-column:3; grid-row:2; justify-self:end; }
    .duc-catalogo .fi-ta-cell-scatole-count { grid-column:2; grid-row:3; }
    .duc-catalogo .fi-ta-cell-anno-edizione { grid-column:3; grid-row:3; justify-self:end; min-width:0; overflow-wrap:anywhere; }
    .duc-catalogo .fi-ta-cell-sottoscorta-badge { grid-column:2 / span 2; grid-row:4; }
    .duc-catalogo .fi-ta-cell:has(.fi-ta-actions) { grid-column:1 / -1; grid-row:5; }
    .duc-catalogo .fi-ta-cell .fi-ta-text,
    .duc-catalogo .fi-ta-cell .fi-ta-image { padding:0; }
    .duc-catalogo .fi-ta-cell-sottoscorta-badge:not(:has(.fi-badge)) { display:none; }
}

/* Lotto A (A4, feedback round2): da 1024px in su la tabella Libri torna al
   layout <table> normale di Filament (le regole "a scheda" qui sopra si
   fermano a 1024px) — ma il contenitore azioni di riga ("Nuovo
   movimento"/"Modifica"/"Trovalo") e' forzato da Filament su UNA riga sola
   da 640px in su (classe vendor `sm:fi-not-wrapped`, vedi
   vendor/filament/tables/resources/views/index.blade.php riga ~1361), e
   con piu' azioni visibili quella riga sfora abbondantemente la larghezza
   disponibile: e' la vera causa dello scroll orizzontale residuo (il
   `<table>` cresce alla sua larghezza naturale, il div
   `.fi-ta-content-ctn` lo scrolla). Qui permettiamo alle azioni di andare
   a capo su piu' righe, con una larghezza massima per la cella: il
   `<table>` (table-layout:auto) rispetta questo vincolo nel calcolo delle
   colonne, la riga si allunga in verticale invece che la tabella in
   orizzontale. */
@media (min-width: 1024px) {
    .duc-catalogo .fi-ta-cell:has(.fi-ta-actions) {
        max-width: 168px;
    }
    .duc-catalogo .fi-ta-actions {
        flex-wrap: wrap;
        row-gap: 4px;
    }
    /* La regola generica piu' sopra (§ colonna "Titolo") impone
       min-width:22rem su TUTTE le tabelle con colonna titolo (Libri,
       Scatole, Movimenti) — qui la restringiamo SOLO per il catalogo
       Libri (selettore piu' specifico, 2 classi), che con seconda riga
       autori (A4) non ha piu' bisogno di cosi' tanto spazio per restare
       leggibile. */
    .duc-catalogo .fi-ta-cell-titolo,
    .duc-catalogo .fi-ta-header-cell-titolo {
        min-width: 9rem;
    }
    /* Le intestazioni ordinabili di Filament sono whitespace-nowrap di
       serie (vendor/filament/tables/resources/css/header-cell.css,
       `&:not(.fi-wrapped)`): con etichette come "Anno / edizione" o
       "N. scatole" e' l'intestazione stessa, non il contenuto delle
       righe (valori corti), a imporre la larghezza minima della colonna.
       Permettere il wrap su due righe qui recupera spazio senza toccare
       il contenuto o l'ordinabilita'. */
    .duc-catalogo .fi-ta-header-cell,
    .duc-catalogo .fi-ta-header-cell-sort-btn {
        white-space: normal;
    }
}

/* Filament stacks tables only below its 640px `sm` breakpoint. Giacenze
   follows the app shell instead: mobile through 768px, desktop from 769px. */
@media (max-width: 768px) {
    .duc-giacenze .fi-ta-table-stacked-on-mobile,
    .duc-giacenze .fi-ta-table-stacked-on-mobile > thead,
    .duc-giacenze .fi-ta-table-stacked-on-mobile > tbody {
        display: block;
        width: 100%;
        white-space: normal;
    }
    .duc-giacenze .fi-ta-table-stacked-on-mobile > thead > tr:not(.fi-ta-table-stacked-header-row) {
        display: none;
    }
    .duc-giacenze .fi-ta-table-stacked-on-mobile > thead > .fi-ta-table-stacked-header-row {
        display: block;
    }
    .duc-giacenze .fi-ta-table-stacked-on-mobile .fi-ta-table-stacked-header-cell {
        display: flex;
        width: 100%;
    }
    .duc-giacenze .fi-ta-table-stacked-on-mobile > tbody > tr {
        position: relative;
        display: block;
        padding: 10px 0;
    }
    .duc-giacenze .fi-ta-table-stacked-on-mobile > tbody > tr > .fi-ta-cell:not(.fi-ta-selection-cell) {
        display: grid;
        grid-template-columns: 6rem minmax(0, 1fr);
        align-items: baseline;
        column-gap: 12px;
        padding-left: 16px;
        padding-right: 16px;
        min-width: 0;
    }
    .duc-giacenze .fi-ta-table-stacked-on-mobile .fi-ta-cell-label {
        display: block;
        padding-top: 8px;
    }
    .duc-giacenze .fi-ta-table-stacked-on-mobile .fi-ta-cell-content {
        display: block;
        overflow-wrap: anywhere;
    }
    .duc-giacenze .fi-ta-table-stacked-on-mobile .fi-ta-cell-stato,
    .duc-giacenze .fi-ta-table-stacked-on-mobile .fi-ta-cell-virtuale {
        display: none !important;
    }
    .duc-giacenze .fi-ta-table-stacked-on-mobile .fi-ta-cell:has(.fi-ta-actions) {
        display: block !important;
        width: 100%;
        box-sizing: border-box;
        padding-top: 10px;
        padding-bottom: 10px;
    }
    .duc-giacenze .fi-ta-table-stacked-on-mobile .fi-ta-actions {
        display: flex !important;
        flex-direction: row !important;
        width: 100%;
        flex-wrap: wrap;
        justify-content: flex-start;
        gap: 8px 12px;
    }
}

.duc-preview-badge {
    display: block;
    width: fit-content;
    max-width: 100%;
    margin: 0 0 16px;
    padding: 7px 12px;
    border: 2px solid #7c2d12;
    border-radius: 999px;
    background: #ffedd5;
    color: #7c2d12;
    box-shadow: 0 2px 8px rgba(0, 0, 0, .18);
    font-size: 12px;
    font-weight: 800;
    line-height: 1.2;
    letter-spacing: .02em;
}
html.dark .duc-preview-badge {
    border-color: #fdba74;
    background: #7c2d12;
    color: #fff7ed;
}

/* Lotto A (A2, feedback round2): paginazione sopra la tabella "Elenco
   Libri" (resources/views/filament/partials/paginazione-sopra.blade.php,
   render hook TOOLBAR_BEFORE). Stesso componente <x-filament::pagination>
   del fondo tabella: solo lo spazio verticale attorno e' nostro, il resto
   eredita gia' lo stile Filament esistente (niente doppio tema da
   mantenere). Wrap su piu' righe su schermi stretti: il pulsante "Nuovo
   libro" (A3) e la ricerca restano sopra, non deve competere per spazio. */
.duc-paginazione-sopra {
    padding: 0 1rem .75rem;
}
.duc-paginazione-sopra .fi-pagination {
    flex-wrap: wrap;
    row-gap: .5rem;
}
