/* states.css — owned by WP2 (UI primitives: loading / skeleton / error /
 * empty). Ported from eudr-x's scattered spinner/skeleton/overlay inventory
 * (spec-theme §6) — one @keyframes ct-spin for every rotator, one ct-shimmer
 * for the skeleton — navy-mapped and ct- prefixed. Dark variants for the
 * literal-rgba surfaces (skeleton, card veil) live here; token-driven surfaces
 * (error panel, empty state) flip for free via dark.css's token block. */

/* ═══════════════════════════ Spinners ═══════════════════════════ */

/* The single rotation keyframe every spinner shares (eudr-x declared it 5×
   under different names — spin, spin-small, auth-spin, sc-spin, ra-spin).
   prefers-reduced-motion is globally neutralized in tokens.css, so this
   degrades to a static ring for free. */
@keyframes ct-spin {
  to {
    transform: rotate(360deg);
  }
}

/* Standard 32px border spinner (spec-theme §6.1). */
.ct-spinner {
  display: inline-block;
  width: 32px;
  height: 32px;
  border: 3px solid color-mix(in srgb, var(--accent) 22%, transparent);
  border-top-color: var(--accent);
  border-radius: 50%;
  animation: ct-spin 0.8s linear infinite;
  flex-shrink: 0;
  vertical-align: middle;
}

/* 14px in-button spinner on a solid/colored button (spec-theme §6.2): white
   ring so it reads on the primary/secondary fill. */
.ct-spinner-sm {
  width: 14px;
  height: 14px;
  border-width: 2px;
  border-color: rgba(255, 255, 255, 0.35);
  border-top-color: #fff;
  animation-duration: 0.6s;
}

/* 12px tiny spinner for inline / destructive ops (spec-theme §6.4): inherits
   the accent ring from the base class, just smaller and faster. */
.ct-spinner-xs {
  width: 12px;
  height: 12px;
  border-width: 2px;
  animation-duration: 0.6s;
}

/* ═══════════════════════════ Full-screen loading overlay ═══════════════════════════ */

/* Blocking veil with a pulsing 3-dot loader + message, for long async ops
   (spec-theme §6.5). Self-colored dark navy veil — reads correctly in both
   themes, no dark override needed. */
.ct-loading-overlay {
  position: fixed;
  inset: 0;
  z-index: 600;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(8, 17, 32, 0.42);
  backdrop-filter: blur(3px);
  -webkit-backdrop-filter: blur(3px);
  animation: ct-fade-in 0.2s ease;
}
.ct-loading-overlay-content {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 16px;
}
.ct-loading-dots {
  display: flex;
  gap: 8px;
}
.ct-loading-dot {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--accent-light);
  animation: ct-loading-pulse 1.4s ease-in-out infinite;
}
.ct-loading-dot:nth-child(2) {
  animation-delay: 0.2s;
}
.ct-loading-dot:nth-child(3) {
  animation-delay: 0.4s;
}
.ct-loading-message {
  font-size: var(--text-sm);
  font-weight: 500;
  letter-spacing: 0.02em;
  color: #fff;
}
@keyframes ct-loading-pulse {
  0%,
  80%,
  100% {
    opacity: 0.25;
    transform: scale(0.8);
  }
  40% {
    opacity: 1;
    transform: scale(1.1);
  }
}
@keyframes ct-fade-in {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

/* ═══════════════════════════ In-card loading veil ═══════════════════════════ */

/* Absolute veil inside a position:relative card/panel (spec-theme §6.6). Navy
   veil values per §6 note: light rgba(228,234,240,0.82) / dark rgba(6,12,22,0.82).
   Put a spinner() + optional text node inside. */
.ct-card-loading {
  position: absolute;
  inset: 0;
  z-index: 15;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 10px;
  border-radius: inherit;
  background: rgba(228, 234, 240, 0.82);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
}
.ct-card-loading .ct-spinner {
  border-color: rgba(82, 104, 120, 0.18);
  border-top-color: #3f5469;
  animation-duration: 0.75s;
}
.ct-card-loading-text {
  font-size: var(--text-sm);
  font-weight: 600;
  letter-spacing: 0.3px;
  color: var(--text-muted);
}
body.dark-mode .ct-card-loading {
  background: rgba(6, 12, 22, 0.82);
}
body.dark-mode .ct-card-loading .ct-spinner {
  border-color: rgba(255, 255, 255, 0.1);
  border-top-color: var(--accent-light);
}

/* ═══════════════════════════ Shimmer skeleton ═══════════════════════════ */

/* The house skeleton (spec-theme §6.7): one shimmer keyframe, neutral navy-tint
   gradient. Bare rows get a width from JS (skeletonRows); default height 14px so
   a standalone .ct-skeleton is still visible. */
@keyframes ct-shimmer {
  0% {
    background-position: -200px 0;
  }
  100% {
    background-position: 200px 0;
  }
}
.ct-skeleton {
  height: 14px;
  border-radius: 6px;
  background: linear-gradient(
    90deg,
    rgba(12, 25, 37, 0.06) 25%,
    rgba(12, 25, 37, 0.1) 50%,
    rgba(12, 25, 37, 0.06) 75%
  );
  background-size: 400px 100%;
  animation: ct-shimmer 1.5s infinite;
}
.ct-skeleton-stat {
  height: 90px;
  border-radius: var(--radius);
}
.ct-skeleton-rows {
  display: flex;
  flex-direction: column;
  gap: 10px;
}
body.dark-mode .ct-skeleton {
  background: linear-gradient(
    90deg,
    rgba(255, 255, 255, 0.04) 25%,
    rgba(255, 255, 255, 0.08) 50%,
    rgba(255, 255, 255, 0.04) 75%
  );
  background-size: 400px 100%;
}

/* ═══════════════════════════ Error panel ═══════════════════════════ */

/* Distinct from an empty state: a failed fetch renders THIS (hazard-red, with a
   retry), never the empty CTA (spec-chemtrust §7.2). Reuses the
   .ct-extraction-error grammar (ui.css) with an icon + message + retry slot. All
   colors are tokens, so dark.css flips them automatically. */
.ct-error-panel {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: var(--space-3);
  padding: var(--space-5);
  border-radius: var(--radius);
  background: var(--confirmed-tint);
  color: var(--confirmed);
  border: 1px solid var(--confirmed-edge);
}
.ct-error-panel-icon {
  flex: 0 0 auto;
  margin-top: 1px;
}
.ct-error-panel-body {
  flex: 1 1 200px;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.ct-error-panel-msg {
  margin: 0;
  font-weight: 700;
}
.ct-error-panel-reqid {
  margin: 0;
  font-size: var(--text-xs);
  font-weight: 600;
  opacity: 0.85;
}
.ct-error-panel-reqid code {
  color: inherit;
}
.ct-error-panel .ct-btn-secondary {
  flex: 0 0 auto;
  align-self: center;
}

/* ═══════════════════════════ Rich empty state ═══════════════════════════ */

/* Richer than the bare .ct-empty (ui.css): stacked icon + title + hint + CTA
   slot, so a genuinely-empty list can point the user at their next action. */
.ct-empty-rich {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-7) var(--space-5);
  text-align: center;
}
.ct-empty-icon {
  color: var(--text-subtle);
  opacity: 0.7;
}
.ct-empty-title {
  margin: 0;
  font-size: var(--text-lg);
  font-weight: 800;
  color: var(--text);
}
.ct-empty-hint {
  margin: 0;
  max-width: 46ch;
  color: var(--text-muted);
  font-size: var(--text-md);
}
.ct-empty-action {
  margin-top: var(--space-2);
}
