/* ============================================================================
   QCI UI · qci-states.css — loading / empty / degraded states. v1 (frozen).
   Generalized from flare-lite's skeleton + empty-state patterns so every app
   ships DESIGNED non-happy paths, never a browser-default spinner or a blank
   div. Requires qci-tokens.css. No raw hex here.

   Classes:
     .qci-sk (+ .qci-sk--line/--num/--pill)   shimmer skeleton blocks
     .qci-loading                              container for first paint
     .qci-empty (+ -mark/-title/-sub/-action)  respectful empty state
     .qci-degraded (+ -dot/-note)              "feed paused · last good HH:MM"
   ========================================================================== */

/* ---- skeleton shimmer (first paint) ---- */
.qci-sk {
  display: block; background: var(--bg-3); border-radius: 3px;
  position: relative; overflow: hidden;
}
.qci-sk::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(90deg, transparent, color-mix(in srgb, var(--ink-4) 20%, transparent), transparent);
  animation: qci-sk-shimmer 1.3s infinite;
}
@keyframes qci-sk-shimmer { from { transform: translateX(-100%); } to { transform: translateX(100%); } }
.qci-sk--line { height: 10px; width: 100%; }
.qci-sk--line.w80 { width: 80%; } .qci-sk--line.w50 { width: 50%; } .qci-sk--line.w30 { width: 30%; }
.qci-sk--num  { height: 24px; width: 72px; }
.qci-sk--pill { height: 15px; width: 42px; border-radius: 2px; }
.qci-loading { pointer-events: none; display: flex; flex-direction: column; gap: var(--space-2); }

/* ---- empty state (respectful: explains, never blames) ---- */
.qci-empty {
  flex: 1 1 auto; display: flex; align-items: center; justify-content: center;
  padding: var(--space-8) var(--space-6);
}
.qci-empty[hidden] { display: none; }
.qci-empty-inner {
  text-align: center; max-width: 300px;
  display: flex; flex-direction: column; align-items: center; gap: var(--space-2);
}
.qci-empty-mark {
  width: 40px; height: 40px; border-radius: 50%; margin-bottom: var(--space-1);
  border: 1px solid var(--line-strong);
  background: radial-gradient(circle at 50% 50%, var(--calm-bg), transparent 70%);
  position: relative;
}
.qci-empty-mark::after {
  content: ""; position: absolute; inset: 0; margin: auto; width: 14px; height: 14px;
  background: var(--calm); border-radius: 50%;
  box-shadow: 0 0 0 4px var(--calm-bg);
}
.qci-empty-title { margin: 0; font-size: var(--fs-h2); font-weight: 600; color: var(--ink); }
.qci-empty-sub { margin: 0; font-size: var(--fs-sm); color: var(--ink-3); line-height: 1.5; }
.qci-empty-action {
  margin-top: var(--space-2); height: 32px; padding: 0 var(--space-4);
  background: var(--bg-3); border: 1px solid var(--line-strong);
  border-radius: var(--r-pill); color: var(--ink); font-size: var(--fs-sm); font-weight: 600;
}
.qci-empty-action:hover { background: var(--bg-hover); }

/* ---- degraded state (upstream down; we are serving last-good/fixtures) ----
   Usage: <div class="qci-degraded"><span class="qci-degraded-dot"></span>
            feed paused <span class="qci-degraded-note">last good 04:12 UTC</span>
          </div> */
.qci-degraded {
  display: inline-flex; align-items: center; gap: var(--space-2);
  padding: var(--space-1) var(--space-3);
  border: 1px solid color-mix(in srgb, var(--med) 30%, transparent);
  background: var(--med-bg); border-radius: var(--r);
  color: var(--ink-2); font-size: var(--fs-xs);
  text-transform: uppercase; letter-spacing: .07em; font-weight: 600;
}
.qci-degraded[hidden] { display: none; }
.qci-degraded-dot {
  width: 6px; height: 6px; border-radius: 50%; flex: none;
  background: var(--med);
  animation: qci-degraded-pulse 2.4s var(--ease) infinite;
}
@keyframes qci-degraded-pulse { 0%, 100% { opacity: 1; } 50% { opacity: .35; } }
.qci-degraded-note { color: var(--ink-3); font-family: var(--mono); font-variant-numeric: tabular-nums; text-transform: none; letter-spacing: 0; }

/* Whole-pane degraded variant: dims the pane content behind the notice */
.qci-pane-degraded { position: relative; }
.qci-pane-degraded > :not(.qci-degraded) { opacity: .45; filter: saturate(.6); }
.qci-pane-degraded > .qci-degraded { position: absolute; top: var(--space-3); right: var(--space-3); z-index: 2; }
