/* ============================================================================
   perf-lite.css — Modalità leggera per GPU integrate / macchine deboli.
   ----------------------------------------------------------------------------
   Attivata da <html class="perf-lite">, impostata PRIMA del primo paint dal
   boot inline midoPerfLiteBootJs() (auto su hardware debole o forzata da
   localStorage 'mido-perf'; vedi theme_assets.php). Caricata ULTIMA fra i CSS
   del tema così le sue regole vincono la cascade senza scatenare guerre di
   specificità: quando la classe non c'è, le regole sono inerti (costo zero).

   Strategia (analisi perf 2026-06-06 — vedi memoria perf_macchine_deboli):
   1. Azzera ogni `backdrop-filter` (blur): è il costo #1 su GPU integrata
      perché il blur di header/topbar STICKY full-width si ricalcola a OGNI
      frame di scroll. Nessuna perdita funzionale — il glass diventa una
      superficie piatta; i 3 bar sticky vengono resi opachi (punto 1b) così
      senza blur il testo resta nitido sul contenuto che scorre sotto.
   2. Riduce animazioni/transizioni come fa già il guard prefers-reduced-motion
      (core.css:859): le animazioni "ambient" infinite (LED, shimmer, glow,
      halo) smettono di tenere sveglio il compositor anche a pagina ferma.
   ============================================================================ */

/* 0. I TOKEN DI RICCHEZZA (2026-07-31) — il meccanismo principale del contratto.
   I valori Full stanno in core.css («Contratto Full/Lite»); qui si ribaltano sui
   valori piatti. Non è una scorciatoia stilistica: è il modo per NON dover
   accendere un effetto e poi spegnerlo a forza. Un componente scrive
   `box-shadow: var(--mido-elev)` e basta — in Lite quel token non dipinge nulla,
   senza che il layer di coda debba conoscere il selettore del componente.
   L'`!important` è concentrato QUI, sulle otto definizioni di token (motivo nel
   commento subito sotto), e non sparso su una regola per ogni componente: è la
   differenza fra otto dichiarazioni in un posto e una guerra di specificità.
   Le regole 1-3 più sotto restano perché coprono un'altra categoria: effetti che
   il tema accende in modo NON tokenizzato (blur, filter, aloni), che finché non
   passano anche loro dai token vanno spenti per selettore. */
/* [!] `!important` sui token, e serve davvero: il blocco auto-dark di core.css è
   `@media (prefers-color-scheme: dark) { :root:not([data-theme]) { … } }`, cioè
   specificità (0,2,0) — `:root` (0,1,0) + `:not([data-theme])` (0,1,0). Questo
   selettore è `html.perf-lite`, (0,1,1): PERDE. Senza `!important`, su una macchina
   col sistema in scuro e nessun tema esplicito, Lite non riceveva i valori piatti e
   bottoni, progress, input e intestazioni restavano identici a Full (misurato: 4
   superfici su 9 differenziavano invece di 9). È l'unico punto del contratto dove
   serve, perché è l'unico che deve battere un blocco di token, non una regola di
   componente. */
html.perf-lite {
    /* `0 0 transparent` e NON `none`: diverse superfici compongono l'elevazione con
       un inset highlight (`box-shadow: var(--mido-elev), inset 0 1px 0 …`), e
       `box-shadow: none, inset …` è sintassi INVALIDA — il browser scarta l'intera
       dichiarazione, quindi in Lite sarebbe sparito anche l'inset, e per ripiego la
       superficie avrebbe preso l'ombra di una regola qualsiasi più in basso nella
       cascade. Verificato in browser: `none, inset 0 1px 0 red` viene rifiutato,
       `0 0 transparent, inset 0 1px 0 red` no. Un'ombra a offset e raggio zero e
       colore trasparente non dipinge nulla: costo zero, ma è un valore valido in
       lista. */
    --mido-elev:        0 0 transparent !important;
    --mido-elev-strong: 0 0 transparent !important;
    --mido-elev-raised: 0 0 transparent !important;
    --mido-rail:        0px !important;    /* il layer del filo d'accento collassa e sparisce */
    --mido-ambient:     0 !important;
    --mido-edge-tint:   0% !important;     /* bordo neutro: sotto viene irrobustito (punto 5) */
    --mido-sheen:       none !important;   /* superfici a tinta piena: piatte, senza velo di luce */
    /* NON `none`, e non è una svista: l'ombra di un pannello FLUTTUANTE è ciò che lo
       separa dal contenuto sotto. Un dropdown bianco senza ombra su pagina bianca è
       illeggibile — sarebbe una regressione funzionale, non un risparmio. Qui scende
       a un'ombra più semplice (un layer invece di tre), non a zero. */
    --mido-elev-overlay: var(--shadow-lg) !important;
}

/* 1. Niente blur né filtri: spegne in un colpo tutti i ~45 backdrop-filter del
   tema e i `filter` decorativi (drop-shadow su loghi/icone), che rasterizzano su
   un layer separato e ridipingono — dentro un header sticky, a ogni scroll.
   `filter` stava in una regola 3a separata con la MEDESIMA lista di selettori:
   unite, perché tre regole universali identiche sono tre passate di match su ogni
   elemento, proprio sulle macchine che questo file esiste per aiutare. Il reset
   delle animazioni resta separato (punto 2): stessi selettori ma motivazione
   diversa, e serve leggibile perché ci si aggancia la allowlist.
   NOTA misurata (2026-07-31): a riposo `filter` non ha bersagli — i 3 del tema
   sono tutti dietro `:hover` (`.brand:hover .brand-logo-icon`,
   `.chart-card.is-interactive:hover canvas`, più un'icona carousel non usata).
   La riga resta perché è lì che il costo si paga (durante l'hover) e perché
   intercetta i `filter` che qualcuno aggiungerà in futuro. */
html.perf-lite *,
html.perf-lite *::before,
html.perf-lite *::after {
    backdrop-filter: none !important;
    -webkit-backdrop-filter: none !important;
    filter: none !important;
}

/* 1b. I bar sticky full-width usavano il blur per restare leggibili sul
   contenuto che scorre sotto: senza blur li rendiamo opachi (var(--surface)
   piena invece di color-mix all'78/85%). Solo questi 3 — dropdown/tooltip/
   popover sono piccoli e transitori, restano semi-trasparenti senza problemi. */
html.perf-lite .app-header,
html.perf-lite .app-topbar,
html.perf-lite .sec-nav {
    background-color: var(--surface) !important;
}

/* 2. Animazioni/transizioni ridotte — stessa tecnica del guard
   prefers-reduced-motion (core.css:859). Le animazioni infinite ambient
   (pulse/glow/shimmer/halo) girano una volta e si fermano; lo stesso vale per
   gli spinner di caricamento — comportamento già accettato dal progetto per
   gli utenti reduced-motion, quindi coerente. */
html.perf-lite *,
html.perf-lite *::before,
html.perf-lite *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    /* Senza questo, un'animazione con `fill-mode: both` e un delay resta ferma sul
       proprio keyframe iniziale per tutto il delay: le card della flotta hanno un
       reveal scaglionato (`.mido-table-card`, delay fino a ~315ms) e in Lite
       comparivano a scatti invece che subito, perché la durata era già 0.01ms ma il
       ritardo no. Azzerarlo qui chiude l'intera classe di casi, non il solo reveal. */
    animation-delay: 0ms !important;
}

/* 2b. Scroll a scatto invece che animato: `scroll-behavior: smooth` è dichiarato in
   tre punti del tema (core.css, ui.css, console-shell.css) e la sua animazione è la
   più lunga che il portale produca — un salto di 2000px interpolato su una macchina
   che fatica a dipingerne uno. Stando qui, in coda alla cascade, le neutralizza tutte
   e tre senza toccarne nessuna: in Full lo smooth deve restare. Niente `!important`:
   il guard reduced-motion di core.css lo dichiara già così e deve continuare a
   vincere, che è il comportamento voluto.
   Copre la navigazione a frammento (skip-link, ancore); gli scroll programmatici che
   passano `behavior:'smooth'` da JS vincono sulla proprietà CSS e restano fuori. */
html.perf-lite {
    scroll-behavior: auto;
}

/* 2c. Barra di avanzamento scroll (ui.css §11, `animation-timeline: scroll(root)`):
   una timeline legata allo scroll ignora `animation-duration`, quindi il reset
   del punto 2 non la spegne — la inchioderebbe piena per tutta la pagina.
   Non è un segnale funzionale (non è nella allowlist del punto 2b): si nasconde. */
html.perf-lite .scroll-progress-bar {
    display: none;
}

/* [!] La allowlist vive DENTRO `prefers-reduced-motion: no-preference`, e non è
   un dettaglio: senza questo guard sarebbe una regressione di accessibilità.
   Catena del difetto (trovato e corretto il 2026-07-30, prima del merge):
   un utente con movimento ridotto può trovarsi in Lite. Dal 2026-07-31 non ci
   finisce più per il solo `prefers-reduced-motion` — l'euristica di
   `theme_assets.php` lo conta solo in combinazione con hardware nella fascia
   incerta — ma ci arriva ancora per hardware debole o forzando il toggle a mano,
   quindi il guard qui sotto resta necessario esattamente come prima.
   Il guard WCAG 2.3.3 di `core.css:859`
   ferma tutto con `*, *::before, *::after { … !important }`, specificità (0,0,0).
   Le regole qui sotto sono `html.perf-lite .qualcosa`, specificità (0,2,1) (due
   classi + il tipo `html`): fra dichiarazioni `!important` della stessa origine
   decide la SPECIFICITÀ, non l'ordine — quindi vincerebbero sul guard e
   farebbero girare gli spinner proprio a chi ha chiesto di non vedere movimento.
   Con `no-preference` la allowlist semplicemente non esiste per quell'utente:
   chi è in Lite per hardware debole riavrà lo spinner, chi è in Lite per
   accessibilità resta con tutto fermo. Sono due popolazioni diverse che
   l'euristica mono-asse confonde — vedi il debito dichiarato nella spec. */
@media (prefers-reduced-motion: no-preference) {

    /* 2b. ALLOWLIST — movimento FUNZIONALE (2026-07-30).
       Il reset del punto 2 spegne ogni animazione, spinner inclusi. Ma chi è in Lite
       ha la macchina più lenta, quindi i fetch più lenti: è lì che togliere l'unico
       segnale di attività fa più danno — uno spinner immobile si legge come pagina
       bloccata. Questi selettori NON sono decorazione: la loro assenza rende ambiguo
       lo stato dell'interfaccia, quindi restano animati anche in Lite.
       Elenco esplicito e chiuso: non trasformarlo in un'euristica su nomi di classe.
       UNICA eccezione apparente, `[data-icon][class*="spin"] svg`: NON è
       un'euristica inventata qui, è il **mirror esatto** di una regola del tema
       che usa quel medesimo selettore — cercala in `ui.css` con
       `grep -n '\[data-icon\]\[class\*="spin"\]' app/css/theme/ui.css`.
       Il riferimento è dato per selettore e non per numero di riga di proposito:
       su questo branch un numero di riga è scaduto tre volte, ogni volta nel
       commit che stava correggendo la scadenza precedente. Per riattivare una regola
       serve un selettore che la copra: sostituirlo con classi esplicite
       mancherebbe proprio i casi che quella regola anima. Se un giorno il tema
       smette di usare il match su sottostringa, questa riga va aggiornata insieme.
       I valori sono RIDICHIARATI, non `revert`: `revert` ricadrebbe sull'user-agent
       (0s) invece che sul valore del tema. In Lite tutti gli elementi qui sopra
       animano a 1s: la velocità esatta non porta informazione, il movimento sì
       (per la maggior parte rotazione; `.spinner-grow` non ruota, pulsa in scala
       — `@keyframes spinner-grow` in bootstrap-bridge.css — ma il principio è lo
       stesso: un ciclo fermo si legge come blocco, uno che si ripete no). */
    html.perf-lite .spinner-ring,
    html.perf-lite .tab-loading svg,
    html.perf-lite .tab-loading .loader-spin,
    html.perf-lite .chart-state-loading .chart-state-icon,
    html.perf-lite .card-refresh-btn.spinning,
    html.perf-lite .icon-spin,
    html.perf-lite .lucide-spin svg,
    html.perf-lite [data-icon][class*="spin"] svg,
    html.perf-lite .mido-refresh-btn.is-spinning > svg,
    html.perf-lite .spinner-border,
    html.perf-lite .spinner-grow {
        animation-duration: 1s !important;
        animation-iteration-count: infinite !important;
    }

    /* Skeleton e shimmer: stessa logica, ritmo più lento perché è un'attesa di
       contenuto, non un'operazione in corso. */
    html.perf-lite .skeleton,
    html.perf-lite .skeleton-shimmer::after {
        animation-duration: 1.5s !important;
        animation-iteration-count: infinite !important;
    }

}

/* 3. Effetti GPU oltre blur/animazioni (audit perf-lite 2026-06-06). Su GPU
   integrata costano fill-rate/VRAM e ripaint: sotto perf-lite si neutralizzano.
   Sono TUTTI decorativi (aloni/glow/atmosfera/hover) → nessuna perdita funzionale,
   il contenuto (LED colorati, loghi, card) resta visibile e leggibile. */

/* (3a `filter` è confluito nel punto 1: stessi selettori, una passata di match
   in meno. Il razionale è documentato lì.) */

/* 3b. Aloni box-shadow sui LED di stato (ripetuti ~25-50 per tabella) e glyph hero:
   lo shadow-blur non è compositato -> ripaint. I dot restano colorati, senza alone. */
html.perf-lite .mido-statusdot,
html.perf-lite .mido-pill::before,
html.perf-lite .mido-hero-glyph,
html.perf-lite .live-dot,
html.perf-lite .status-dot,
/* 2026-07-31: l'accento del titolo in topbar (barra 3px + alone sfocato 14px,
   `mido_theme_helpers.css:894`) mancava dall'elenco. È il caso peggiore della
   categoria — un'ombra sfocata dentro una barra STICKY si ridipinge a ogni frame
   di scroll — e restava acceso anche in Lite. La barra colorata resta: sparisce
   solo l'alone. */
html.perf-lite .mido-topbar-head::before,
/* 2026-07-31: alone della voce di sidebar ATTIVA (`console-shell.css:325`). La barra
   colorata resta — è wayfinding, dice dove sei — ma il suo alone sfocato a 7px è
   decorazione, e stava dentro una sidebar sticky. Spegnere l'alone e non la barra è
   la distinzione che questo file deve sempre fare. */
html.perf-lite .sidebar-link.active::before,
/* 2026-07-31: stessa cosa per la famiglia SELEZIONATA (`console-shell.css:705`) — la
   barretta resta, sparisce l'alone a 7px. */
html.perf-lite .sidebar-fam.is-active::before {
    box-shadow: none !important;
}
/* Il pallino della famiglia attiva ha DUE layer: un anello netto a 3px (che è
   wayfinding — dice quale flotta stai guardando, e su 6px di pallino è l'unico
   segnale leggibile) e un alone sfocato a 7px, che è decorazione. Qui non si spegne
   la dichiarazione: si riscrive tenendo il solo anello. */
html.perf-lite .sidebar-fam.is-active .swatch {
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--fam, var(--primary)) 22%, transparent) !important;
}
html.perf-lite .mido-statusdot::after,
html.perf-lite .live-dot::after,
html.perf-lite .mido-hero-glyph::after {
    display: none !important;   /* onde/halo espandibili: pure decorazione */
}

/* 3c. Atmosfera/gradient grandi tracciati dal puntatore o in maschera: costo di
   ripaint su mousemove. Spenti -> superficie piatta. Il velo al puntatore è il
   layer reale `.mido-glow-layer` (components-mido.css C7): display:none, non solo
   opacity 0 — in Lite non deve nemmeno comporre. */
html.perf-lite .mido-glow-layer {
    display: none !important;
}
html.perf-lite .mido-surface-boost::before {
    opacity: 0 !important;
    background: none !important;
}
html.perf-lite .layout-mixed::before {
    mask-image: none !important;
    -webkit-mask-image: none !important;
    opacity: .18 !important;     /* resta un hint piatto della griglia */
}
html.perf-lite .app-main {
    background-image: none !important;   /* pattern radiale 24px ripetuto su viewport */
}

/* 3d. Empty-state: il radiale di famiglia (480px, ancorato sopra il bordo) è la
   firma decorativa del componente, non informazione — l'icona, il titolo e il testo
   restano. Sta qui e non in components-mido.css perché è l'unico pezzo dell'empty
   state che NON passa da un token: il resto (ombra, bordo) lo fa già. */
html.perf-lite .empty-state.mido-surface-boost,
html.perf-lite .empty-state-elevated.mido-surface-boost {
    background: var(--surface) !important;
}

/* 5. MODO DICHIARATO (2026-07-31) — Lite non è "Full meno qualcosa".
   Tolte ombra, filo d'accento e velo, una card resterebbe un rettangolo bianco su
   fondo quasi bianco separato da una hairline calibrata per essere letta INSIEME
   all'ombra: senza, il contenitore smette di leggersi e la pagina sembra con lo
   stile non caricato. Qui la separazione viene restituita dove costa zero — il
   bordo — così Lite si legge come una scelta ("modalità dati") e non come un
   guasto. `--border-strong` è già theme-aware (slate-300 in chiaro, slate-700 in
   scuro): niente hex, niente seconda regola per il dark.
   Le classi in coda NON ricevono `.mido-surface-boost` (non sono nella lista
   di `enhancements.js`) ma sono superfici a contratto identiche — leggono
   `--mido-elev`/`--mido-edge-tint` dal loro CSS di plugin. Senza questa riga in
   Lite resterebbero con la sola hairline: la stessa card che il punto esiste per
   salvare. Sono elencate a mano di proposito: la lista è chiusa, non un'euristica
   sui nomi di classe.
   2026-08-10: aggiunte le sei superfici tokenizzate nel round di audit
   (`.mido-admin-loading` skeleton delle liste admin, più i contenitori dei plugin
   timeline/gauge/map/activity-feed/pricing). NON sono qui, e la scelta è motivata:
   `.mido-launch-tile` ha l'ombra solo su `:hover` (a riposo era già piatta per
   progetto, in Lite non perde nulla) e `.mido-seg.is-active` resta distinta da
   fondo, colore e peso del testo — non è il caso "rettangolo indistinguibile" che
   questo punto esiste per risolvere.
   `.mido-pricing-tier` è filtrato con `:not(.is-featured)`: la variante in evidenza
   dichiara `border-color: var(--primary)` con specificità (0,2,0) e qui il selettore
   sarebbe (0,2,1), quindi vincerebbe cancellando proprio il bordo che distingue il
   tier consigliato. Il suo bordo primary è già forte, non ha bisogno del rinforzo. */
html.perf-lite .mido-surface-boost,
html.perf-lite .mido-progress,
html.perf-lite .mido-cal-heatmap,
html.perf-lite .mido-alerts,
html.perf-lite .mido-admin-loading,
html.perf-lite .mido-timeline,
html.perf-lite .mido-gauge,
html.perf-lite .mido-map-card,
html.perf-lite .mido-activityfeed,
html.perf-lite .mido-pricing-tier:not(.is-featured) {
    border-color: var(--border-strong);
}

/* 4. Toggle UI "modalità leggera" (#perfToggle nelle sidebar): evidenziato quando
   attivo. Regola NON scoped a html.perf-lite di proposito: il controllo è sempre
   presente e si colora in base allo stato (classe .is-active gestita dal boot). */
#perfToggle.is-active {
    color: var(--primary);
    background: color-mix(in srgb, var(--primary) 14%, transparent);
}
