/* ==========================================================================
   CHASSIS motion
   --------------------------------------------------------------------------
   Rule: motion carries information. Every animation here is bound to a state
   the user needs to perceive — arrival, change, direction, load, risk — and
   none of it runs for decoration. All transforms are GPU-composited.
   ========================================================================== */

/* ---- arrival: strata enter at different depths ------------------------- */

@keyframes rise {
  from { opacity: 0; transform: translate3d(0, 14px, 0); }
  to   { opacity: 1; transform: none; }
}

@keyframes riseFar {
  from { opacity: 0; transform: translate3d(0, 26px, 0) scale(0.985); }
  to   { opacity: 1; transform: none; }
}

@keyframes wipeIn {
  from { clip-path: inset(0 100% 0 0); }
  to   { clip-path: inset(0 0 0 0); }
}

.enter { animation: rise var(--m-settle) var(--ease-out) both; }
.enter-far { animation: riseFar 620ms var(--ease-out) both; }
.enter-1 { animation-delay: 60ms; }
.enter-2 { animation-delay: 130ms; }
.enter-3 { animation-delay: 205ms; }
.enter-4 { animation-delay: 290ms; }
.enter-5 { animation-delay: 380ms; }
.enter-6 { animation-delay: 480ms; }

/* ---- value change: a directional tick, the colour says which way -------- */

@keyframes tickUp {
  0%   { box-shadow: inset 0 -2px 0 var(--sig-gain); background-color: color-mix(in oklab, var(--sig-gain) 14%, transparent); }
  100% { box-shadow: inset 0 -2px 0 transparent; background-color: transparent; }
}

@keyframes tickDown {
  0%   { box-shadow: inset 0 2px 0 var(--sig-loss); background-color: color-mix(in oklab, var(--sig-loss) 14%, transparent); }
  100% { box-shadow: inset 0 2px 0 transparent; background-color: transparent; }
}

.tick-up { animation: tickUp 900ms var(--ease-out); }
.tick-down { animation: tickDown 900ms var(--ease-out); }

/* ---- live: a pulse whose period is bound to a real rate ---------------- */

@keyframes livePulse {
  0%, 100% { opacity: 0.35; transform: scale(0.86); }
  50%      { opacity: 1; transform: scale(1); }
}

.live-dot {
  width: 6px;
  height: 6px;
  flex: none;
  background: var(--sig-gain);
  clip-path: polygon(50% 0, 100% 50%, 50% 100%, 0 50%);
  animation: livePulse var(--pulse, 1600ms) var(--ease-in-out) infinite;
}

.live-dot--warn { background: var(--sig-warn); }
.live-dot--loss { background: var(--sig-loss); }
.live-dot--mind { background: var(--sig-mind); }

/* ---- scanning: the engine ring turns at the rate it is working --------- */

@keyframes ringSpin { to { transform: rotate(360deg); } }

.ring {
  position: relative;
  width: var(--ring-size, 34px);
  height: var(--ring-size, 34px);
  flex: none;
}

.ring::before,
.ring::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 50%;
}

.ring::before {
  border: 1px solid color-mix(in oklab, var(--ink-500) 55%, transparent);
}

.ring::after {
  border: 1px solid transparent;
  border-top-color: var(--ring-ink, var(--sig-brand));
  border-right-color: color-mix(in oklab, var(--ring-ink, var(--sig-brand)) 40%, transparent);
  animation: ringSpin var(--ring-period, 2.4s) linear infinite;
}

.ring[data-idle="true"]::after { animation-duration: 9s; opacity: 0.3; }

/* ---- risk tremor: sub-pixel instability on structurally unsound rows ---- */

@keyframes tremor {
  0%, 100% { transform: translate3d(0, 0, 0); }
  25%      { transform: translate3d(0.4px, -0.3px, 0); }
  50%      { transform: translate3d(-0.3px, 0.35px, 0); }
  75%      { transform: translate3d(0.25px, 0.2px, 0); }
}

[data-tremor="true"] { animation: tremor 260ms linear infinite; }

/* ---- stream: prints arriving on the tape ------------------------------- */

@keyframes printIn {
  from { opacity: 0; transform: translate3d(-10px, 0, 0); clip-path: inset(0 100% 0 0); }
  to   { opacity: 1; transform: none; clip-path: inset(0 0 0 0); }
}

.print-in { animation: printIn 340ms var(--ease-out) both; }

/* ---- ambient drift for floating elements ------------------------------- */

@keyframes drift {
  0%, 100% { transform: translate3d(0, 0, 0); }
  50%      { transform: translate3d(0, -7px, 0); }
}

.drift { animation: drift var(--drift-period, 9s) var(--ease-in-out) infinite; }
.drift-2 { animation-delay: -3s; }
.drift-3 { animation-delay: -6s; }

/* ---- parallax: strata respond to the pointer at different depths ------- */

.parallax {
  transform: translate3d(
    calc(var(--px) * var(--depth, 6px)),
    calc(var(--py) * var(--depth, 6px)),
    0
  );
  transition: transform 420ms var(--ease-out);
  will-change: transform;
}

.parallax--tight { transition: transform 140ms linear; }

/* Cards that tilt toward the pointer when hovered — a physical read, small
   enough to feel like weight rather than a gimmick. */
.tilt {
  transform-style: preserve-3d;
  transition: transform var(--m-move) var(--ease-out);
}

.tilt:hover {
  transform: perspective(900px)
    rotateX(calc(var(--ty, 0) * -3deg))
    rotateY(calc(var(--tx, 0) * 3deg))
    translate3d(0, -2px, 0);
}

/* ---- overlays ---------------------------------------------------------- */

@keyframes veilIn { from { opacity: 0; } to { opacity: 1; } }

@keyframes sheetIn {
  from { opacity: 0; transform: translate3d(0, 22px, 0) scale(0.985); }
  to   { opacity: 1; transform: none; }
}

.veil { animation: veilIn var(--m-move) var(--ease-out) both; }
.sheet-in { animation: sheetIn 340ms var(--ease-spring) both; }

/* ---- loading: a machined shuttle, not a spinner ------------------------ */

@keyframes shuttle {
  0%   { transform: translateX(-100%); }
  100% { transform: translateX(400%); }
}

.loading-rail {
  position: relative;
  height: 1px;
  overflow: hidden;
  background: color-mix(in oklab, var(--ink-400) 40%, transparent);
}

.loading-rail::after {
  content: "";
  position: absolute;
  inset: 0 auto 0 0;
  width: 25%;
  background: linear-gradient(90deg, transparent, var(--sig-brand), transparent);
  animation: shuttle 1.15s var(--ease-in-out) infinite;
}

/* ---- reduced motion: keep meaning, drop movement ----------------------- */

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
  .parallax { transform: none !important; }
  .live-dot { opacity: 1; }
}
