/* =====================================================================
 * Open Brain · UI states (v2 redesign W0, Jul 2026)
 *
 * The SIX BINDING PATTERNS every v2 surface must implement, per the
 * "Web UI states spec" screen in Web Redesign.dc.html:
 *
 *   1. Loading   — shimmer skeleton (1.4s), card-shaped placeholders in
 *                  final positions, NO layout shift on resolve. Never a
 *                  spinner-on-blank.
 *   2. Empty     — earned/celebratory when meaningful (inbox zero);
 *                  first-run empties explain + point at the primary action.
 *   3. Error     — recoverable, never a dead end: banner with Retry +
 *                  a request-detail line; last-good data stays visible
 *                  BEHIND the banner (errors overlay, they don't replace).
 *   4. Offline   — banner + queued-write count; the PWA keeps working.
 *   5. Toast     — confirm + Undo, 5s. Reversibility-first.
 *   6. Confirm   — destructive dialog ONLY when irreversible; everything
 *                  else acts immediately with toast+undo.
 *
 * Companion JS: /dashboard/ui-states.js (obsSkeleton, obsEmpty,
 * obsErrorBanner, obsOfflineBanner, obsToastUndo, obsConfirmDestructive).
 * Load AFTER design-system.css — colours come from the --v2-* tokens.
 * ===================================================================== */

/* ── 1. Loading — shimmer skeleton ─────────────────────────────────── */
@keyframes obs-shimmer {
  0%   { background-position: -200% 0; }
  100% { background-position: 200% 0; }
}
.obs-skeleton {
  position: relative;
  border-radius: 7px;
  background: linear-gradient(90deg,
    hsl(var(--v2-s2)) 25%, hsl(var(--v2-s3)) 50%, hsl(var(--v2-s2)) 75%);
  background-size: 200% 100%;
  animation: obs-shimmer 1.4s linear infinite;
  color: transparent !important;
  pointer-events: none;
  user-select: none;
}
/* Size presets — card-shaped placeholders in final positions. */
.obs-skeleton-line   { height: 11px; width: 90%; }
.obs-skeleton-title  { height: 14px; width: 60%; }
.obs-skeleton-short  { height: 11px; width: 74%; }
.obs-skeleton-card   {
  height: 96px; width: 100%;
  border-radius: 16px;
}
.obs-skeleton-stack { display: flex; flex-direction: column; gap: 8px; }
@media (prefers-reduced-motion: reduce) {
  .obs-skeleton { animation: none; background: hsl(var(--v2-s2)); }
}

/* ── 2. Empty — earned / first-run ─────────────────────────────────── */
.obs-empty {
  border-radius: 13px;
  padding: 18px;
  text-align: center;
  background: hsl(var(--v2-s2));
  color: hsl(var(--v2-fg));
}
.obs-empty.is-earned {
  background: var(--v2-grad-bull);
  color: white;
}
.obs-empty-icon  { font-size: 22px; line-height: 1; }
.obs-empty-title { font-size: 14px; font-weight: 700; margin-top: 3px; }
.obs-empty-body  { font-size: 11px; opacity: 0.85; margin-top: 2px; }
.obs-empty-action {
  display: inline-flex; align-items: center;
  margin-top: 10px; padding: 7px 14px;
  border: none; cursor: pointer; font-family: inherit;
  font-size: 12px; font-weight: 700;
  color: hsl(var(--v2-onprimary));
  background: hsl(var(--v2-primary));
  border-radius: 999px;
}
.obs-empty.is-earned .obs-empty-action {
  background: rgba(255, 255, 255, 0.2); color: white;
}

/* ── 3. Error — recoverable overlay banner ─────────────────────────── */
.obs-error-banner {
  display: flex; align-items: center; gap: 11px;
  border-radius: 13px;
  padding: 13px 14px;
  background: hsl(var(--v2-pinkbg));
  border: 1px solid hsl(var(--v2-pink)/0.35);
  color: hsl(var(--v2-fg));
  margin-bottom: 10px;
}
.obs-error-icon  { font-size: 15px; flex: 0 0 auto; }
.obs-error-body  { flex: 1; min-width: 0; }
.obs-error-title { font-size: 13px; font-weight: 700; }
.obs-error-detail {
  font-size: 11px; color: hsl(var(--v2-muted)); margin-top: 1px;
  font-family: var(--v2-font-mono, ui-monospace, monospace);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.obs-error-retry {
  flex: 0 0 auto;
  border: none; cursor: pointer; font-family: inherit;
  font-size: 11.5px; font-weight: 700;
  color: white; background: hsl(var(--v2-pink));
  border-radius: 999px; padding: 7px 13px;
}

/* ── 4. Offline — fixed banner + queue count ───────────────────────── */
.obs-offline-banner {
  position: fixed; top: 10px; left: 50%; transform: translateX(-50%);
  z-index: 99998;
  display: flex; align-items: center; gap: 10px;
  border-radius: 13px;
  padding: 11px 14px;
  max-width: min(560px, 92vw);
  background: hsl(var(--v2-marigoldbg));
  border: 1px solid hsl(var(--v2-marigold)/0.35);
  color: hsl(var(--v2-fg));
  box-shadow: 0 18px 44px -14px rgba(0, 0, 0, 0.4);
}
.obs-offline-dot {
  width: 8px; height: 8px; border-radius: 50%; flex: 0 0 auto;
  background: hsl(var(--v2-neutral));
}
.obs-offline-msg  { font-size: 12.5px; font-weight: 600; }
.obs-offline-note { margin-left: auto; font-size: 11px; color: hsl(var(--v2-muted)); }

/* ── 5. Toast — confirm + undo (5s) ────────────────────────────────── */
@keyframes obs-toast-in {
  from { opacity: 0; transform: translate(-50%, 16px); }
  to   { opacity: 1; transform: translate(-50%, 0); }
}
.obs-toast {
  position: fixed; bottom: 26px; left: 50%; transform: translateX(-50%);
  z-index: 99998;
  display: flex; align-items: center; gap: 10px;
  background: hsl(var(--v2-card));
  border: 1px solid hsl(var(--v2-bull)/0.4);
  border-radius: 999px;
  padding: 11px 18px;
  max-width: min(560px, 92vw);
  box-shadow: 0 18px 44px -14px rgba(0, 0, 0, 0.7);
  animation: obs-toast-in 0.3s ease-out both;
  color: hsl(var(--v2-fg));
}
.obs-toast-check {
  width: 20px; height: 20px; border-radius: 50%; flex: 0 0 auto;
  background: hsl(var(--v2-mintbg));
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 11px;
}
.obs-toast-msg { font-size: 13px; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.obs-toast-undo {
  border: none; background: transparent; cursor: pointer; font-family: inherit;
  font-size: 12px; font-weight: 700; padding: 0;
  color: hsl(var(--v2-primary));
  flex: 0 0 auto;
}
@media (prefers-reduced-motion: reduce) { .obs-toast { animation: none; } }

/* ── 6. Destructive confirm — only when irreversible ───────────────── */
.obs-confirm-overlay {
  position: fixed; inset: 0; z-index: 99999;
  display: flex; align-items: center; justify-content: center;
  background: rgba(0, 0, 0, 0.5);
  padding: 16px;
}
.obs-confirm-panel {
  width: min(400px, 92vw);
  border-radius: 16px;
  padding: 16px;
  background: hsl(var(--v2-card));
  border: 1px solid hsl(var(--v2-border));
  box-shadow: 0 40px 90px -20px rgba(0, 0, 0, 0.8);
  color: hsl(var(--v2-fg));
}
.obs-confirm-title { font-size: 13px; font-weight: 700; }
.obs-confirm-body  { font-size: 11.5px; color: hsl(var(--v2-muted)); margin-top: 3px; line-height: 1.5; }
.obs-confirm-actions { display: flex; gap: 8px; margin-top: 12px; }
.obs-confirm-go {
  border: none; cursor: pointer; font-family: inherit;
  font-size: 11.5px; font-weight: 700;
  color: white; background: hsl(var(--v2-bear));
  border-radius: 9px; padding: 7px 14px;
}
.obs-confirm-keep {
  border: 1px solid hsl(var(--v2-border)); cursor: pointer; font-family: inherit;
  font-size: 11.5px; font-weight: 600;
  color: hsl(var(--v2-fg)); background: transparent;
  border-radius: 9px; padding: 7px 14px;
}
