/* =============================================================================
   Skeleton di caricamento — usato da LoaderManager.showSkeleton()
   (sm/lib_scripts/custom_loader.js)

   Serve al PRIMO caricamento, quando a video non c'e' ancora niente: mostra la
   forma del contenuto invece di coprirlo con uno spinner. Sui ricaricamenti di
   dati gia' visibili resta l'overlay classico, che non fa sparire il contenuto
   sotto gli occhi.

   Palette volutamente NEUTRA (grigi derivati dalla superficie #f5f7fb del design
   system), non a tinta brand: lo skeleton e' un'assenza di dato, non un elemento
   d'identita', e il tema colore dell'app varia per installazione.
   ========================================================================== */

:root {
  --sk-skel-base: #e7ebf2;      /* barra a riposo */
  --sk-skel-shine: #f4f7fb;     /* cresta dello shimmer */
  --sk-skel-bg: #ffffff;        /* fondo del pannello che copre il contenuto */
  --sk-skel-radius: 6px;        /* raggio piccolo del design system */
  --sk-skel-speed: 1.4s;
}

/* Pannello che copre l'elemento ospite. Opaco di proposito: al primo caricamento
   sotto non c'e' nulla da vedere, e la trasparenza darebbe solo sporco visivo. */
.sk-skel-panel {
  position: absolute;
  inset: 0;
  z-index: 999;
  background: var(--sk-skel-bg);
  overflow: hidden;
  padding: 1rem 1.25rem;
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

/* La barra: il gradiente e' largo il triplo del contenitore e viene traslato,
   cosi' la luce attraversa l'elemento invece di lampeggiare sul posto. */
.sk-skel-bar {
  position: relative;
  border-radius: var(--sk-skel-radius);
  background-color: var(--sk-skel-base);
  background-image: linear-gradient(
    90deg,
    var(--sk-skel-base) 0%,
    var(--sk-skel-shine) 50%,
    var(--sk-skel-base) 100%
  );
  background-size: 300% 100%;
  background-repeat: no-repeat;
  animation: sk-skel-sweep var(--sk-skel-speed) ease-in-out infinite;
}

@keyframes sk-skel-sweep {
  0%   { background-position: 150% 0; }
  100% { background-position: -50% 0; }
}

/* --- Variante TABELLA ------------------------------------------------------
   Griglia: una colonna larga per l'etichetta di riga + N colonne di valori.
   --sk-cols e' scritto da JS in base alle colonne reali della tabella. */
.sk-skel-table {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.sk-skel-row {
  display: grid;
  grid-template-columns: minmax(140px, 2.4fr) repeat(var(--sk-cols, 6), minmax(48px, 1fr));
  gap: 0.5rem;
  align-items: center;
}

.sk-skel-row .sk-skel-bar { height: 15px; }

/* L'intestazione e' leggermente piu alta e piu marcata: da' subito il senso
   della struttura, non solo di "qualcosa sta arrivando". */
.sk-skel-row-head { margin-bottom: 0.35rem; }
.sk-skel-row-head .sk-skel-bar {
  height: 19px;
  --sk-skel-base: #dde3ec;
}

/* Righe di gruppo: barra etichetta piu corta e leggermente piu scura, per
   restituire la gerarchia ad albero della tabella vera. */
.sk-skel-row-group .sk-skel-cell-label .sk-skel-bar {
  --sk-skel-base: #dde3ec;
  width: 62%;
}
.sk-skel-row-leaf .sk-skel-cell-label .sk-skel-bar { width: 84%; margin-left: 1.25rem; }

/* Sfasamento progressivo: le righe non pulsano all'unisono, l'onda scende.
   Nove passi bastano, poi si ricicla. */
.sk-skel-row:nth-child(9n+2) .sk-skel-bar { animation-delay: .05s; }
.sk-skel-row:nth-child(9n+3) .sk-skel-bar { animation-delay: .10s; }
.sk-skel-row:nth-child(9n+4) .sk-skel-bar { animation-delay: .15s; }
.sk-skel-row:nth-child(9n+5) .sk-skel-bar { animation-delay: .20s; }
.sk-skel-row:nth-child(9n+6) .sk-skel-bar { animation-delay: .25s; }
.sk-skel-row:nth-child(9n+7) .sk-skel-bar { animation-delay: .30s; }
.sk-skel-row:nth-child(9n+8) .sk-skel-bar { animation-delay: .35s; }
.sk-skel-row:nth-child(9n+9) .sk-skel-bar { animation-delay: .40s; }

/* --- Varianti GRAFICO ------------------------------------------------------
   Una forma per tipo di grafico, non una sola generica: uno skeleton che
   promette colonne e poi consegna una torta e' peggio che non metterne affatto,
   perche' l'occhio ha gia' cominciato a leggere una struttura sbagliata.
   Le misure variabili (altezze, larghezze, intensita') le scrive JS pescando da
   cicli FISSI, mai da Math.random: con valori casuali lo skeleton cambierebbe
   faccia a ogni caricamento della stessa pagina e sembrerebbe un dato che varia.

   Guscio comune a tutte: riempie l'ospite in verticale. */
.sk-skel-graph {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  min-height: 0;
}

/* L'asse non e' una barra: e' fermo e piu scuro, cosi' il grafico sembra
   appoggiato a qualcosa invece che sospeso. */
.sk-skel-graph-base {
  height: 2px;
  margin-top: 0.5rem;
  border-radius: 1px;
  background: #dde3ec;
}

/* -- BARRE VERTICALI (variante 'bar') -- */
.sk-skel-bar-v {
  flex: 1 1 auto;
  display: flex;
  align-items: flex-end;
  gap: 0.5rem;
  min-height: 80px;   /* se l'ospite e' basso si vedono comunque le colonne */
}
.sk-skel-bar-v .sk-skel-bar { flex: 1 1 0; }

/* -- BARRE ORIZZONTALI (variante 'bar-h') --
   Con l'etichetta di categoria a sinistra, come l'asse Y dei grafici "Top N".
   Le larghezze le scrive JS in ordine decrescente: quei grafici sono classifiche
   ordinate, e una scaletta calante si legge subito come tale. */
.sk-skel-bar-h {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 0.75rem;
}
.sk-skel-bar-h-row {
  display: grid;
  grid-template-columns: 84px minmax(0, 1fr);
  gap: 0.6rem;
  align-items: center;
}
.sk-skel-bar-h-row .sk-skel-bar { height: 14px; }
.sk-skel-bar-h-row .sk-skel-bar-h-label { height: 10px; width: 82%; }

/* -- TORTA (variante 'donut') --
   Anello + legenda. Il buco e' un ::after riempito col fondo del pannello:
   cosi' l'anello resta una sola barra e si porta dietro lo shimmer, che con un
   border non funzionerebbe (l'animazione lavora sul background). */
.sk-skel-donut {
  flex: 1 1 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 1.75rem;
  flex-wrap: wrap;
}
.sk-skel-donut-ring {
  position: relative;
  width: 148px;
  height: 148px;
  border-radius: 50%;
  flex-shrink: 0;
}
.sk-skel-donut-ring::after {
  content: "";
  position: absolute;
  inset: 27%;
  border-radius: 50%;
  background: var(--sk-skel-bg);
}
.sk-skel-donut-legend { display: flex; flex-direction: column; gap: 0.65rem; }
.sk-skel-donut-legend-row { display: flex; align-items: center; gap: 0.5rem; }
.sk-skel-donut-legend-row .sk-skel-donut-dot { width: 10px; height: 10px; border-radius: 50%; }
.sk-skel-donut-legend-row .sk-skel-donut-voce { height: 10px; width: 78px; }

/* -- AREA / LINEA (variante 'area') --
   Una sagoma sola con il bordo superiore spezzato: la silhouette la fa il
   clip-path, il riempimento e lo shimmer restano quelli della barra. */
.sk-skel-area { flex: 1 1 auto; display: flex; flex-direction: column; min-height: 0; }
.sk-skel-area-shape {
  flex: 1 1 auto;
  min-height: 80px;
  border-radius: 0;
  clip-path: polygon(
    0% 76%, 8% 60%, 17% 68%, 25% 42%, 34% 50%, 42% 28%, 50% 38%,
    59% 20%, 67% 32%, 75% 16%, 84% 28%, 92% 10%, 100% 22%,
    100% 100%, 0% 100%
  );
}

/* -- HEATMAP (variante 'heatmap') --
   Griglia di celle con l'etichetta di riga a sinistra. --sk-hm-cols lo scrive
   JS, come --sk-cols per la tabella. L'opacita' per cella (anch'essa da JS, da
   un ciclo fisso) e' cio' che distingue una heatmap da una scacchiera: senza,
   sarebbe una griglia uniforme, e l'intensita' variabile e' il suo dato. */
.sk-skel-heatmap {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 0.3rem;
}
.sk-skel-heatmap-row {
  display: grid;
  grid-template-columns: 34px repeat(var(--sk-hm-cols, 24), minmax(0, 1fr));
  gap: 0.25rem;
  align-items: center;
}
.sk-skel-heatmap-row .sk-skel-bar { height: 14px; }
.sk-skel-heatmap-row .sk-skel-heatmap-label { height: 9px; width: 80%; }
.sk-skel-heatmap-cell { border-radius: 2px; }

/* Sfasamento: la luce attraversa il grafico invece di far pulsare tutto
   all'unisono. Otto passi bastano, poi si ricicla. */
.sk-skel-bar-v .sk-skel-bar:nth-child(8n+2),
.sk-skel-bar-h-row:nth-child(8n+2) .sk-skel-bar,
.sk-skel-heatmap-row:nth-child(8n+2) .sk-skel-bar,
.sk-skel-donut-legend-row:nth-child(8n+2) .sk-skel-bar { animation-delay: .05s; }
.sk-skel-bar-v .sk-skel-bar:nth-child(8n+3),
.sk-skel-bar-h-row:nth-child(8n+3) .sk-skel-bar,
.sk-skel-heatmap-row:nth-child(8n+3) .sk-skel-bar,
.sk-skel-donut-legend-row:nth-child(8n+3) .sk-skel-bar { animation-delay: .10s; }
.sk-skel-bar-v .sk-skel-bar:nth-child(8n+4),
.sk-skel-bar-h-row:nth-child(8n+4) .sk-skel-bar,
.sk-skel-heatmap-row:nth-child(8n+4) .sk-skel-bar,
.sk-skel-donut-legend-row:nth-child(8n+4) .sk-skel-bar { animation-delay: .15s; }
.sk-skel-bar-v .sk-skel-bar:nth-child(8n+5),
.sk-skel-bar-h-row:nth-child(8n+5) .sk-skel-bar,
.sk-skel-heatmap-row:nth-child(8n+5) .sk-skel-bar,
.sk-skel-donut-legend-row:nth-child(8n+5) .sk-skel-bar { animation-delay: .20s; }
.sk-skel-bar-v .sk-skel-bar:nth-child(8n+6),
.sk-skel-bar-h-row:nth-child(8n+6) .sk-skel-bar,
.sk-skel-heatmap-row:nth-child(8n+6) .sk-skel-bar { animation-delay: .25s; }
.sk-skel-bar-v .sk-skel-bar:nth-child(8n+7),
.sk-skel-bar-h-row:nth-child(8n+7) .sk-skel-bar,
.sk-skel-heatmap-row:nth-child(8n+7) .sk-skel-bar { animation-delay: .30s; }
.sk-skel-bar-v .sk-skel-bar:nth-child(8n+8),
.sk-skel-heatmap-row:nth-child(8n+8) .sk-skel-bar { animation-delay: .35s; }

/* --- Variante LISTA --------------------------------------------------------
   Riga "pallino + nome + valore", la forma dei riquadri a elenco (ultimi
   accessi, utenti dormienti, scadenze). Il blocco di barre piatte qui non
   basterebbe: perderebbe il rientro fra titolo e sottotitolo e il valore in
   colonna a destra, che sono proprio cio' che rende leggibile l'elenco. */
.sk-skel-list { display: flex; flex-direction: column; gap: 0.9rem; }

.sk-skel-list-row {
  display: grid;
  grid-template-columns: 34px minmax(0, 1fr) auto;
  gap: 0.75rem;
  align-items: center;
}

.sk-skel-list-avatar { width: 34px; height: 34px; border-radius: 50%; }

.sk-skel-list-text { display: flex; flex-direction: column; gap: 0.35rem; }
.sk-skel-list-text .sk-skel-bar:first-child { height: 13px; width: 70%; }
.sk-skel-list-text .sk-skel-bar:last-child  { height: 10px; width: 45%; }

.sk-skel-list-value { height: 15px; width: 46px; }

.sk-skel-list-row:nth-child(6n+2) .sk-skel-bar { animation-delay: .06s; }
.sk-skel-list-row:nth-child(6n+3) .sk-skel-bar { animation-delay: .12s; }
.sk-skel-list-row:nth-child(6n+4) .sk-skel-bar { animation-delay: .18s; }
.sk-skel-list-row:nth-child(6n+5) .sk-skel-bar { animation-delay: .24s; }
.sk-skel-list-row:nth-child(6n+6) .sk-skel-bar { animation-delay: .30s; }

/* --- Variante BLOCCO (riuso generico: card, form, riquadri) --------------- */
.sk-skel-block { display: flex; flex-direction: column; gap: 0.6rem; }
.sk-skel-block .sk-skel-bar { height: 14px; }
.sk-skel-block .sk-skel-bar:nth-child(3n+1) { width: 92%; }
.sk-skel-block .sk-skel-bar:nth-child(3n+2) { width: 78%; }
.sk-skel-block .sk-skel-bar:nth-child(3n+3) { width: 85%; }
.sk-skel-block .sk-skel-bar:last-child { width: 45%; }

/* --- Comparsa e uscita ----------------------------------------------------
   Entra subito (non deve sembrare un ritardo in piu), esce in dissolvenza cosi'
   il passaggio allo skeleton -> dati non e' uno scatto. */
.sk-skel-panel { animation: sk-skel-in 120ms ease-out; }
.sk-skel-panel.is-leaving {
  animation: sk-skel-out 180ms ease-in forwards;
  pointer-events: none;
}
@keyframes sk-skel-in  { from { opacity: 0; } to { opacity: 1; } }
@keyframes sk-skel-out { from { opacity: 1; } to { opacity: 0; } }

/* --- Accessibilita --------------------------------------------------------
   Con reduced-motion niente shimmer ne dissolvenze: restano le barre statiche,
   che comunicano la stessa cosa senza movimento. */
@media (prefers-reduced-motion: reduce) {
  .sk-skel-bar {
    animation: none;
    background-image: none;
  }
  .sk-skel-panel,
  .sk-skel-panel.is-leaving {
    animation: none;
  }
}
