/* ============================================================================
   Spotsheet — SKELETON PRIMITIVES  ·  boot-shell-inline-loading v1
   ----------------------------------------------------------------------------
   The one reusable loading-state module. Every content surface composes its
   skeleton from these classes. Built ONLY on tokens.css vars (no new colors).

   Rules this file encodes:
     · Shimmer is NEUTRAL graphite — never teal. Teal stays reserved for the
       boot splash + live/active state, so a skeleton never reads as "ready".
     · One calm sweep tempo (1500ms) shared with the boot splash, so the whole
       app loads at one rhythm.
     · prefers-reduced-motion → static placeholders, no sweep.
     · Skeleton geometry MUST mirror real content (these primitives are sized
       to the real rows/zones) so data arrival causes zero layout shift.

   A11y: put role="status" aria-busy="true" aria-live="polite" on the region
   that holds skeletons; drop aria-busy (and swap children) when data arrives.
   ========================================================================== */

/* ---- Base shimmer block --------------------------------------------------- */
/* Everything visible is a .sk. Region-wide sliding gradient keeps one tempo
   regardless of element size (small chips don't sweep faster than big blocks). */
.sk {
  --sk-base: #1f2228;          /* between --bg-sub and --bg-row */
  --sk-hi:   #282d34;          /* one step toward --line-strong */
  display: block;
  border-radius: var(--r-2);
  background: linear-gradient(
    100deg,
    var(--sk-base) 0%,
    var(--sk-base) 36%,
    var(--sk-hi)   50%,
    var(--sk-base) 64%,
    var(--sk-base) 100%
  );
  background-size: 220% 100%;
  background-position: 180% 0;
  animation: sk-shimmer 1500ms linear infinite;
}
@keyframes sk-shimmer {
  to { background-position: -180% 0; }
}

/* Deep variant — sits on recessed --bg-deep wells (media wells, the waveform
   strip). A hair darker so the placeholder still reads as inset. */
.sk.deep { --sk-base: #14171b; --sk-hi: #1d2127; }

/* ---- Text lines ----------------------------------------------------------- */
.sk-line  { height: 9px;  border-radius: var(--r-1); }
.sk-line.sm { height: 7px; }
.sk-line.lg { height: 13px; border-radius: var(--r-2); }   /* titles */
.sk-line.xl { height: 18px; border-radius: var(--r-2); }   /* page headings */

/* width helpers (compose with .sk-line) */
.sk-w-15 { width: 15%; } .sk-w-25 { width: 25%; } .sk-w-30 { width: 30%; }
.sk-w-40 { width: 40%; } .sk-w-50 { width: 50%; } .sk-w-60 { width: 60%; }
.sk-w-70 { width: 70%; } .sk-w-80 { width: 80%; } .sk-w-90 { width: 90%; }
.sk-full { width: 100%; }

/* a stack of text lines with realistic rhythm */
.sk-lines { display: flex; flex-direction: column; gap: 8px; }

/* ---- Shapes --------------------------------------------------------------- */
.sk-circle { border-radius: 50%; flex-shrink: 0; }   /* avatars / status dots */
.sk-chip   { height: 18px; border-radius: var(--r-1); }   /* TC / category chips */
.sk-chip.tag { height: 22px; }
.sk-block  { border-radius: var(--r-3); }            /* video frames, thumbs */
.sk-pill   { height: 18px; width: 52px; border-radius: var(--r-1); }

/* ---- Card scaffold -------------------------------------------------------- */
/* A skeleton wearing .nt-panel chrome — real border/shadow, shimmer inside.
   The frame is "ready" (paints with the shell); only its contents are pending. */
.sk-card {
  background: var(--bg-panel);
  border: 1px solid var(--line);
  border-radius: var(--r-3);
  box-shadow: var(--inset-panel);
}

/* ---- A skeleton list row (the Notes / Versions / cue workhorse) ----------- */
/* Mirrors a real list row's height + padding so swapping in data never shifts. */
.sk-row {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 0 16px;
  position: relative;
}
.sk-row + .sk-row { border-top: 1px solid var(--line-soft); }

/* ---- Region helpers ------------------------------------------------------- */
/* Optional: a region-level fade so a freshly-painted skeleton doesn't pop.
   Kept very subtle — it must still feel instant, not animated-in.
   NOTE: the resting state (and the keyframe `from`) is VISIBLE (no opacity:0,
   no `both` fill) — content must never be stranded transparent if the
   animation doesn't run (print, capture, reduced-motion). */
.sk-region { animation: sk-region-in 200ms ease-out; }
@keyframes sk-region-in { from { opacity: 0.45; } to { opacity: 1; } }

/* When data replaces the skeleton, the real content gets this for an equally
   subtle settle. Pair so the handoff reads as one beat. */
.sk-settle { animation: sk-settle-in 220ms cubic-bezier(0.215,0.61,0.355,1); }
@keyframes sk-settle-in { from { opacity: 0.5; } to { opacity: 1; } }

/* ---- Reduced motion ------------------------------------------------------- */
/* Static placeholders. No sweep, no region/settle transitions — the geometry
   is the message; motion is decoration we drop. */
@media (prefers-reduced-motion: reduce) {
  .sk {
    animation: none;
    background: var(--sk-base);
    background-image: none;
  }
  .sk-region, .sk-settle { animation: none; }
}
/* Preview-harness force toggle — mirrors the reduce query for the demo switch. */
.force-rm .sk {
  animation: none !important;
  background: var(--sk-base) !important;
  background-image: none !important;
}
.force-rm .sk-region, .force-rm .sk-settle { animation: none !important; }
