/* CBWatch interface upgrade — layered on top of theme.css, not a
 * replacement for it. Every colour here is one of theme.css's existing
 * tokens (--bg/--panel/--accent/etc.) — this file adds richer motion,
 * depth, and data-viz/step-trail treatments inspired by three references
 * Connor asked for specifically:
 *
 *   - Motion (motion.dev)  — self-hosted at vendor/motion.js, drives the
 *     actual animation (hover spring-physics, entrance stagger, chart
 *     draw-in) from interface.js. This file only holds the CSS that
 *     Motion's inline styles compose with (base states, static shadows).
 *   - Kokonut UI            — the animated-card/button look this file's
 *     .k-card / .k-btn-primary / .k-badge rules borrow, hand-built in
 *     plain CSS since Kokonut's own components are React/shadcn (see the
 *     framework-approach decision — this is a vanilla-CSS translation of
 *     the look, not their code).
 *   - Bklit UI               — the animated-chart look .chart-* below
 *     borrows (gridless, gradient-fill, animated draw-in line/area
 *     charts), same "vanilla translation" approach as above.
 *
 * Every existing page keeps working if this file is never linked — it
 * only adds new classes/data-attributes, never redefines theme.css's
 * own selectors.
 */

/* --- Kokonut-inspired card: a slow-drifting conic-gradient ring sitting
   just behind the card, revealed through a 1px gap, instead of a flat
   border. Very subtle at rest (theme.css's normal .panel-border still
   does the heavy lifting) and brightens on hover. Opt-in via .k-card so
   it never silently changes every .panel on the site at once. --- */

.k-card {
  position: relative;
  isolation: isolate;
}
.k-card::before {
  content: "";
  position: absolute;
  inset: -1px;
  z-index: -1;
  border-radius: inherit;
  padding: 1px;
  background: conic-gradient(from var(--k-angle, 0deg), var(--accent-dim), transparent 30%, transparent 70%, var(--accent-dim));
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask-composite: exclude;
  opacity: 0.35;
  transition: opacity 0.3s ease;
}
.k-card:hover::before { opacity: 0.85; }

/* Continuous rotation (k-rotate, infinite) removed on request (25 Sept,
   laptop-lag fix) — the gradient ring stays, static, and still
   brightens on hover per .k-card:hover::before above. */

/* --- Kokonut-inspired primary button: gradient shimmer sweep on hover,
   layered on top of theme.css's existing .btn-primary (same gradient
   colours, same glow shadow — this only adds the sweep + spring-press
   feel that interface.js's hover()/press() wiring uses). --- */

.k-btn-primary { position: relative; overflow: hidden; }
.k-btn-primary::after {
  content: "";
  position: absolute;
  top: 0; left: -60%;
  width: 40%; height: 100%;
  background: linear-gradient(115deg, transparent, rgba(255, 255, 255, 0.35), transparent);
  transform: skewX(-18deg);
  transition: left 0.65s ease;
}
.k-btn-primary:hover::after { left: 130%; }

/* --- Animated stat badge (score/grade, big dashboard numbers) — a soft
   pulsing halo behind the number, on top of theme.css's .grade-badge. --- */

.k-pulse { position: relative; }
.k-pulse::before {
  content: "";
  position: absolute;
  inset: -6px;
  border-radius: inherit;
  background: radial-gradient(circle, var(--accent-dim), transparent 70%);
  opacity: 0;
  z-index: -1;
  animation: k-pulse-in 0.6s ease forwards;
}
@keyframes k-pulse-in { from { opacity: 0; transform: scale(0.8); } to { opacity: 0.55; transform: scale(1); } }

/* --- Manus-style step trail --------------------------------------------
   A vertical list of steps that move pending -> active -> done, driven by
   interface.js's StepTrail class. Labels are the scanner's REAL check
   names (see scanner/run.py's CHECKS dict) — this shows real work being
   named, paced against the real request's actual duration; it does not
   claim per-check backend confirmation (the checks genuinely run in
   parallel server-side — see run.py's module docstring), just an honest,
   readable "here's what's being checked" reveal instead of one flat
   "Scanning…" line. */

.step-trail {
  display: flex;
  flex-direction: column;
  gap: 2px;
  width: 100%;
  max-width: 420px;
  margin: 0 auto;
}

.step-trail-item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 7px 10px;
  border-radius: var(--radius-sm);
  font-family: var(--mono);
  font-size: var(--fs-sm);
  color: var(--ink-dim);
  opacity: 0.45;
  transition: opacity 0.25s ease, color 0.25s ease, background 0.25s ease;
}
.step-trail-item.is-active { opacity: 1; color: var(--ink); background: rgba(79, 209, 197, 0.06); }
.step-trail-item.is-done { opacity: 0.85; color: var(--ink-dim); }

.step-dot {
  width: 14px; height: 14px;
  flex-shrink: 0;
  border-radius: 50%;
  border: 1.5px solid var(--panel-border);
  position: relative;
  display: grid;
  place-items: center;
}
.step-trail-item.is-active .step-dot {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(79, 209, 197, 0.15);
}
.step-trail-item.is-active .step-dot::after {
  content: "";
  width: 5px; height: 5px;
  border-radius: 50%;
  background: var(--accent);
  animation: step-blink 0.9s ease-in-out infinite;
}
@keyframes step-blink { 0%, 100% { opacity: 1; } 50% { opacity: 0.25; } }

.step-trail-item.is-done .step-dot {
  border-color: var(--low);
  background: var(--low);
}
.step-trail-item.is-done .step-dot::after {
  content: "✓";
  font-size: 9px;
  font-family: var(--sans);
  color: var(--panel);
  font-weight: 700;
}

/* --- Bklit-inspired animated charts -------------------------------------
   Gridless, minimal, gradient-fill line/area charts. The path itself is
   drawn in via interface.js animating stroke-dashoffset (Motion's
   animate()) rather than just appearing — see drawChartLine(). */

.chart-wrap { width: 100%; }
.chart-svg { width: 100%; display: block; overflow: visible; }
.chart-line { fill: none; stroke: var(--accent); stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.chart-area { opacity: 0.16; }
.chart-dot { fill: var(--accent); }
.chart-axis-label { font-family: var(--mono); font-size: 10px; fill: var(--ink-dim); }

.chart-tooltip {
  position: absolute;
  pointer-events: none;
  background: var(--panel-raised);
  border: 1px solid var(--panel-border);
  border-radius: var(--radius-sm);
  padding: 5px 9px;
  font-family: var(--mono);
  font-size: var(--fs-xs);
  color: var(--ink);
  box-shadow: var(--shadow-panel);
  opacity: 0;
  transition: opacity 0.15s ease;
  white-space: nowrap;
  transform: translate(-50%, -130%);
  z-index: 5;
}
.chart-tooltip.visible { opacity: 1; }

/* --- Entrance animation base state ---------------------------------------
   Elements with data-animate start hidden/offset via CSS so there's no
   flash-of-unanimated-content before interface.js's Motion-driven reveal
   runs; if JS fails to load for any reason, a tiny no-JS fallback timeout
   below still brings everything to full opacity so the page is never
   stuck invisible. */

[data-animate] { opacity: 0; }
[data-animate="fade-up"] { transform: translateY(14px); }
[data-animate="fade-in"] { transform: none; }
[data-animate="scale-in"] { transform: scale(0.96); }

/* No-JS fallback: each page that links this file also includes
     <noscript><style>[data-animate]{opacity:1!important;transform:none!important}</style></noscript>
   right after it, so a visitor with JS disabled never sees permanently
   invisible content. Separately, interface.js has its own timeout-based
   fallback for "JS ran but Motion failed to load" (network hiccup, etc.). */

@media (prefers-reduced-motion: reduce) {
  .k-card::before { animation: none !important; }
  .step-dot::after { animation: none !important; }
  [data-animate] { opacity: 1 !important; transform: none !important; }
}
