Skeleton

Locul unui conținut care încă nu a sosit. Spinner-ul spune „așteaptă"; skeleton-ul arată ce vine și unde, ca pagina să nu sară când sosește.

Markup canonic · components/skeleton.json

sursa = JSON · generat de scripts/build-catalog.py

În KPI · .kpi[aria-busy="true"]

încărcat ↔ se încarcă · aceeași înălțime
Venituri facturate
387.420Lei
Încasat 310.000 · Rest 77.420
Venituri facturate

Starea completă e în KPI card.

Anatomie

înălțime        0.75em — cât cifrele, la mărimea textului din rând
așezare         inline-block pe linia de bază — acoperă locul numărului
lățime          100% implicit · o setezi pe lățimea conținutului care vine
culoare         --c-bej-1 · pe .kpi.dark alb 12%
colțuri         --r-xs
puls            opacitate 1 → 0.5 → 1, 2s, infinit

Bara e un inline-block gol, deci rândul care o ține își păstrează înălțimea și textul o înlocuiește fără să miște nimic. Are nevoie de un rând de text în jur: pusă direct într-un părinte flex devine element flex, pierde linia de bază, iar părintele se strânge. .kpi .delta e inline-flex — de aceea trece pe inline-block cât ține o bară.

Accesibilitate

aria-busy="true"         pe regiunea care se încarcă (cardul, lista)
.skeleton                fără text, fără rol — cititorul de ecran n-are ce citi
prefers-reduced-motion   pulsul se oprește — bara rămâne, pe loc

Spre deosebire de spinner, skeleton-ul se oprește sub reduced motion: o bară care nu pulsează se citește tot ca „se încarcă", un inel oprit se citește ca pagină înghețată.