/* ═══════════════════════════════════════════════════════════════════════════
   CARICAMENTI — NON MODIFICARE
   Fa parte di uicore/core: al prossimo riallineamento questo file viene
   sovrascritto.
   ═══════════════════════════════════════════════════════════════════════════

   Tre modi di dire "sto lavorando", e non sono intercambiabili:

   1. SCHELETRO   la pagina si sta riempiendo la prima volta. Mostra la forma
                  di ciò che arriverà: l'attesa sembra più breve perché
                  l'occhio ha già capito il layout.
   2. PULSANTE    l'utente ha chiesto qualcosa di specifico. Il riscontro sta
                  sul comando che ha premuto, non altrove.
   3. VELO        operazione che blocca davvero tutto. Da usare con parsimonia:
                  è l'unico che impedisce di fare altro.

   L'errore comune è usare il velo per tutto. Un salvataggio da 200 ms che
   oscura la pagina è più fastidioso di nessun riscontro.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── 1. Scheletri ─────────────────────────────────────────────────────────
   Il riflesso che scorre non è decorazione: distingue "sta arrivando" da
   "è vuoto". Un blocco grigio fermo si legge come un errore. */
.ui-skeleton {
    position: relative;
    overflow: hidden;
    border-radius: var(--ui-radius-sm);
    background: rgba(var(--ui-brand-rgb), .065);
}
.ui-skeleton::after {
    content: "";
    position: absolute;
    inset: 0;
    background: linear-gradient(100deg,
        transparent 18%,
        rgba(255, 255, 255, .5) 48%,
        transparent 78%);
    transform: translateX(-120%);
    animation: uiShimmer 1.4s ease-in-out infinite;
}
[data-bs-theme="dark"] .ui-skeleton {
    background: rgba(255, 255, 255, .05);
}
[data-bs-theme="dark"] .ui-skeleton::after {
    /* Al buio un riflesso bianco al 50% acceca: qui basta un velo. */
    background: linear-gradient(100deg,
        transparent 18%,
        rgba(255, 255, 255, .07) 48%,
        transparent 78%);
}

@keyframes uiShimmer {
    to { transform: translateX(120%); }
}

@media (prefers-reduced-motion: reduce) {
    /* Il blocco resta, il riflesso no: il movimento ripetuto a ciclo è
       proprio quello che dà fastidio a chi ha chiesto di ridurlo. */
    .ui-skeleton::after { animation: none; }
}

/* Righe di testo. L'ultima più corta, come in un paragrafo vero: è il
   dettaglio che fa sembrare uno scheletro invece di barre a caso. */
.ui-skeleton-line { height: 12px; margin-bottom: 8px; border-radius: var(--ui-radius-xs); }
.ui-skeleton-line:last-child { width: 62%; margin-bottom: 0; }
.ui-skeleton-title { height: 20px; width: 45%; margin-bottom: 14px; }
.ui-skeleton-circle { border-radius: 50%; }

/* Forme composte: rispecchiano i componenti veri, così il passaggio
   scheletro → contenuto non sposta niente. */
.ui-skeleton-kpi { height: 88px; border-radius: var(--ui-radius-lg); }
.ui-skeleton-row { height: 68px; border-radius: var(--ui-radius-md); }
.ui-skeleton-chart { height: 260px; border-radius: var(--ui-radius-lg); }

.ui-skeleton-list { display: grid; gap: 10px; }

/* ── 2. Pulsante in attesa ────────────────────────────────────────────────
   L'etichetta resta al suo posto ma diventa trasparente: sostituirla con
   "Attendere…" cambia la larghezza del pulsante e fa saltare la riga. */
.ui-btn-loading {
    position: relative;
    color: transparent !important;
    pointer-events: none;
}
.ui-btn-loading > * { opacity: 0; }
.ui-btn-loading::after {
    content: "";
    position: absolute;
    top: 50%;
    left: 50%;
    width: 16px;
    height: 16px;
    margin: -8px 0 0 -8px;
    border: 2px solid currentColor;
    border-right-color: transparent;
    border-radius: 50%;
    /* `currentColor` è trasparente per la regola sopra: il colore va ripreso
       dal testo del pulsante, che Bootstrap tiene in --bs-btn-color. */
    color: var(--bs-btn-color, var(--ui-ink));
    animation: uiSpin .6s linear infinite;
}

@keyframes uiSpin {
    to { transform: rotate(360deg); }
}

/* ── 3. Velo globale ─────────────────────────────────────────────────────── */
.ui-loader {
    position: fixed;
    inset: 0;
    z-index: var(--ui-z-loader);
    display: grid;
    place-items: center;
    opacity: 0;
    transition: opacity var(--ui-duration-fast) var(--ui-ease);
}
.ui-loader.is-visible { opacity: 1; }

.ui-loader-panel {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--ui-space-3);
    padding: var(--ui-space-6) var(--ui-space-8);
    border-radius: var(--ui-radius-lg);
    min-width: 180px;
}

.ui-loader-spin {
    width: 34px;
    height: 34px;
    border: 3px solid color-mix(in oklab, var(--ui-brand) 25%, transparent);
    border-top-color: var(--ui-brand);
    border-radius: 50%;
    animation: uiSpin .7s linear infinite;
}

.ui-loader-logo {
    width: 44px;
    height: 44px;
    object-fit: contain;
    border-radius: var(--ui-radius-sm);
}

.ui-loader-msg {
    font-size: var(--ui-text-sm);
    font-weight: var(--ui-weight-semibold);
    opacity: .8;
    text-align: center;
}

@media (prefers-reduced-motion: reduce) {
    /* Rotazione più lenta invece che ferma: un indicatore immobile sembra
       bloccato, ed è l'informazione opposta a quella che deve dare. */
    .ui-loader-spin, .ui-btn-loading::after { animation-duration: 2s; }
}
