/*
 * Base chrome — THE WALL AND THE RECORD.
 * Owns: reset, body/canvas, the lattice ambient layer, typography
 * primitives, focus law, scrollbars, the motion keyframe library every
 * surface drives, and the global reduced-motion kill switch.
 * Tokens live in tokens.css; shared widgets in components.css.
 */

/* -- reset + canvas ---------------------------------------------------- */
*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  background: var(--s-void);
  color-scheme: dark;
}

body {
  margin: 0;
  min-height: 100vh;
  background: transparent;
  color: var(--text-body);
  font-family: var(--font-sans);
  font-size: var(--t-body);
  line-height: var(--t-body-lh);
  -webkit-font-smoothing: antialiased;
}

/* Machine voice is mono and tabular by default; prose opts back to sans. */
code,
pre,
kbd,
samp,
.mono,
[data-counter],
.claim-timer {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
}

h1, h2, h3, h4 {
  margin: 0 0 var(--sp-3);
  color: var(--text-max);
  font-weight: 600;
  letter-spacing: -0.01em;
  line-height: 1.2;
}

h1 { font-size: var(--t-display-2); line-height: var(--t-display-2-lh); }
h2 { font-size: var(--t-title-lg); line-height: var(--t-title-lg-lh); }
h3 { font-size: var(--t-title); line-height: var(--t-title-lh); }

p { margin: 0 0 var(--sp-3); }

a {
  color: var(--sig);
  text-decoration: none;
  transition: color var(--t-fast) var(--ease-snap);
}
a:hover { color: var(--sig-bright); text-decoration: underline; }

::selection {
  background: var(--sig-dim);
  color: var(--text-max);
}

/* Focus law: the double-line survey ring — a shape cue, not just color. */
:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
  border-radius: var(--r-chamfer);
}

/* Scrollbars: thin instruments. */
* {
  scrollbar-width: thin;
  scrollbar-color: var(--line-tick) transparent;
}
*::-webkit-scrollbar { width: 8px; height: 8px; }
*::-webkit-scrollbar-thumb {
  background: var(--line-tick);
  border-radius: var(--r-lamp);
}
*::-webkit-scrollbar-track { background: transparent; }

/* -- the lattice (ambient, stable, body-level) ------------------------- */
.lattice {
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  overflow: hidden;
}

.lattice-ticks {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  opacity: 0.5; /* tick strokes carry the rest; net ceiling stays ambient */
}

/* The long arcs live in their own svg: path data takes NUMBERS only, so the
   arcs draw in a 0-100 viewBox stretched to the surface (the first cut put
   percentages straight into d= — Chrome drops those paths with a console
   error and the arcs silently never render). */
.lattice-arcs {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
}

.lattice-arc {
  stroke: var(--line-tick);
  stroke-width: 1;
  opacity: 0.22;
  fill: none;
}

.lattice-sweep {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  width: 2px;
  background: linear-gradient(
    to bottom,
    transparent,
    var(--sig) 30%,
    var(--sig) 70%,
    transparent
  );
  opacity: 0.35;
  animation: sweep-x var(--c-sweep) linear infinite;
}

.lattice-scan {
  position: absolute;
  inset: 0;
  background: radial-gradient(
    ellipse 80% 60% at 50% 0%,
    rgba(34, 211, 238, 0.05),
    transparent 60%
  );
  animation: scan var(--c-scan) var(--ease-drift) infinite;
}

/* Wall heartbeat (f2): a real swarm event brightens the sweep for one pass.
   Transition (not keyframes) so the reduced-motion kill switch collapses it
   to an instant step — the signal stays, only the movement stops. */
.lattice-sweep {
  transition: opacity var(--dur-4) var(--ease-snap);
}

.lattice-sweep.hot {
  opacity: 0.85;
}

/* Page content rides above the lattice. */
body > header,
body > main,
body > nav,
body > .app-header,
body > .page {
  position: relative;
  z-index: 1;
}

/* -- demo banner ------------------------------------------------------- */
.demo-banner {
  position: relative;
  z-index: 2;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  flex-wrap: wrap;
  padding: var(--sp-2) var(--sp-4);
  background: var(--s-panel);
  border-bottom: 1px solid var(--line);
  color: var(--text-label);
  font-size: var(--t-ui);
}

.demo-banner code { color: var(--text-max); }
.demo-banner-actions { display: flex; align-items: center; gap: var(--sp-2); }
.demo-banner-actions a { color: var(--sig); }

/* -- matrix rain container (opt-in; engine in matrix.js) ---------------- */
.matrix-bg-container {
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
}

#matrix-rain-canvas {
  width: 100%;
  height: 100%;
  display: block;
  opacity: 0.14;
}

.matrix-viper-watermark {
  position: absolute;
  inset: 0;
  display: none;
  background: center / min(480px, 70vw) no-repeat
    url("/static/img/viper-watermark.png");
}

body.matrix-on .matrix-viper-watermark {
  display: block;
  animation: watermark-breathe var(--c-breathe) var(--ease-drift) infinite;
}

#matrix-toggle {
  position: fixed;
  right: var(--sp-3);
  bottom: var(--sp-3);
  z-index: 3;
  padding: 2px var(--sp-2);
  background: transparent;
  border: 1px solid var(--line);
  border-radius: var(--r-lamp);
  color: var(--text-faint);
  font-family: var(--font-mono);
  font-size: var(--t-meta);
  cursor: pointer;
}

#matrix-toggle:hover { color: var(--text-label); border-color: var(--line-tick); }

/* =========================================================================
 * MOTION LIBRARY — every surface drives these; nothing defines its own
 * keyframes for the shared vocabulary. Physics: snap, overshoot, rest.
 * ========================================================================= */

/* Card settles into its socket (SSE swap heartbeat). */
@keyframes seat-in {
  0% { transform: translateY(4px) scale(0.985); opacity: 0.4; }
  70% { transform: translateY(-1px) scale(1.004); opacity: 1; }
  100% { transform: translateY(0) scale(1); opacity: 1; }
}

.seat-in {
  animation: seat-in var(--t-settle) var(--ease-needle) both;
}

/* Lamp latches: three blinks, then lit. */
@keyframes relatch {
  0%, 100% { opacity: 1; }
  15%, 45%, 75% { opacity: 0.15; }
  30%, 60%, 90% { opacity: 1; }
}

.relatch { animation: relatch var(--t-sweep) steps(1, end) both; }

/* Unread badge pops. */
@keyframes badge-pop {
  0% { transform: scale(0.6); }
  70% { transform: scale(1.15); }
  100% { transform: scale(1); }
}

.badge-pop { animation: badge-pop var(--t-settle) var(--ease-needle) both; }

/* Count odometer bump. */
@keyframes count-bump {
  0% { transform: translateY(4px); opacity: 0.2; }
  100% { transform: translateY(0); opacity: 1; }
}

.count-bump { animation: count-bump var(--t-fast) var(--ease-snap) both; }

/* The flag flare: the gate closing, captured -> solved. */
@keyframes flare {
  0% { transform: scale(0.2); opacity: 0.5; }
  100% { transform: scale(2.4); opacity: 0; }
}

.flare {
  position: fixed;
  z-index: 60;
  width: 80px;
  height: 80px;
  margin: -40px 0 0 -40px;
  border-radius: var(--r-lamp);
  background: radial-gradient(circle, var(--ch-solved-dim) 0%, transparent 70%);
  box-shadow: var(--lamp-glow) var(--ch-solved);
  pointer-events: none;
  animation: flare 600ms var(--ease-snap) forwards;
}

/* Ambient cycles (stable wrappers only — never inside polled fragments). */
@keyframes sweep-x {
  0% { transform: translateX(0); }
  100% { transform: translateX(100vw); }
}

@keyframes scan {
  0%, 100% { opacity: 0.4; }
  50% { opacity: 1; }
}

@keyframes watermark-breathe {
  0%, 100% { opacity: 0.04; }
  50% { opacity: 0.09; }
}

@keyframes dot-breathe {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.45; }
}

@keyframes fresh-pulse {
  0%, 100% { box-shadow: 0 0 0 0 var(--sig-dim); }
  50% { box-shadow: 0 0 0 4px var(--sig-dim); }
}

.breathe { animation: dot-breathe var(--c-breathe) var(--ease-drift) infinite; }

/* Poll discipline: content swapped by the 5s polls carries no entrance. */
.is-poll,
.is-poll .seat-in,
.is-poll .badge-pop,
.is-poll .count-bump {
  animation: none !important;
}

/* -- phone guarantees (chrome level; surface sheets add their own) -------- */
@media (max-width: 640px) {
  .app-header {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--sp-2);
    padding: var(--sp-2) var(--sp-3);
    min-height: 36px;
  }

  h1 { font-size: var(--t-title-lg); }
  h2 { font-size: var(--t-title); }
  .lattice-sweep { display: none; } /* keep the phone cheap */
}

/* -- the kill switch: the signal stays, only the movement stops --------- */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }

  .lattice-sweep,
  .lattice-scan,
  .lattice-arc {
    animation: none !important;
    opacity: 0.12; /* parked, still present: the wall is never blank */
  }

  .flare { display: none; }
}
