/* Structural tokens.
 *
 * These are the parts of the system that do not carry visual identity: the
 * spacing rhythm, the type scale, and transition timings. They are declared
 * once, here. A skin may override any of them, but is not required to -- so
 * they are the only tokens allowed to have a value outside skins/.
 *
 * Identity tokens (colour, edge, chrome, type families, motion character) are
 * deliberately NOT defaulted here. If they were, a skin that forgot to declare
 * one would silently inherit a neutral value and look almost-right, which is
 * exactly the failure mode the token contract exists to prevent. Instead they
 * are declared only in skins/, and test/design_system/token_contract_test.rb
 * fails the build when a skin is missing one.
 *
 * The full contract, with prose for every token, is config/design_tokens.yml.
 */

:root {
  /* Spacing rhythm */
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 24px;
  --space-6: 32px;
  --space-7: 44px;

  --panel-pad: var(--space-4);
  --row-height: 60px;
  --row-gap: var(--space-2);

  /* Type scale */
  --text-xs: 11px;
  --text-sm: 13px;
  --text-md: 15px;
  --text-lg: 17px;
  --text-xl: 22px;
  --text-2xl: 30px;
  --text-3xl: 40px;

  /* Transition timings. Character (easing, loop periods) is a skin decision. */
  --motion-fast: 120ms;
  --motion-base: 220ms;
}

/* Keyframes are shared; the values they interpolate towards are tokens, so the
   same animation reads differently under each skin. */
@keyframes rk-eq {
  0%, 100% { transform: scaleY(var(--viz-floor)); }
  50%      { transform: scaleY(1); }
}

@keyframes rk-marquee {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); }
}

@keyframes rk-spin {
  from { transform: rotate(0deg); }
  to   { transform: rotate(360deg); }
}

@keyframes rk-pulse {
  0%, 100% { opacity: 1; }
  50%      { opacity: 0.35; }
}

/* The page's light, wandering behind whatever the skin has hung in front of it.
   Only `transform` is interpolated -- translate, rotate and scale compose into a
   single matrix the compositor can run without touching layout, paint, or the
   main thread. Animating background-position or filter here would look the same
   and cost a full repaint of a viewport-sized layer every frame.

   The rotation is what decorrelates the individual lights in --bg-page-lights: a
   pure translation slides them in lockstep and reads as wallpaper being dragged,
   while turning the whole layer around its centre sends each one along its own
   arc, at its own apparent speed.

   The travel is large because the brightness cannot be. The lights are held to
   around a tenth of an alpha by the ink floors the page has to keep, and a soft
   wash that quiet is only legible as a light if it visibly goes somewhere: the
   first draft moved a twelfth as far over twice as long and read as a static
   gradient. */
@keyframes rk-drift {
  from { transform: translate3d(-14%, -10%, 0) rotate(-10deg) scale(1); }
  to   { transform: translate3d(15%, 11%, 0) rotate(10deg) scale(1.16); }
}
