/* ============================================================================
   SceneDeck — design tokens
   ============================================================================

   The site is the link between two machines, seen from inside it. That is not
   a decorative conceit: SceneDeck runs on one machine and OBS runs on another,
   and everything between them crosses a WebSocket.

   Two things define it:

   - THE OBS PALETTE supplies the colour, measured from obsproject.com's own
     stylesheet: the #280f83 -> #065dac hero gradient, the #256eff accent, and
     the navy surface ramp #080f22 .. #162458. Dark mode is the palette in its
     native habitat; light mode is the same hues printed on cool paper.
   - MATERIAL 3 EXPRESSIVE supplies the structure and the motion: the tonal
     surface-container ramp, elevation-as-tone, state layers, and spring
     physics instead of duration-and-curve (see scripts/spring.js).

   The rule that keeps it coherent: one M3 tonal step is one physical panel
   depth. surface-container-low is a recessed panel; surface-container-highest
   is a fader cap. If it does not do something, it does not get a bevel.

   Every hex traces back to obsproject.com, to a Material tonal step derived
   from the OBS accent, or to a status colour OBS itself uses.

   --src-h / --src-c are registered so they can be *interpolated*. That is what
   lets the whole page retint as one motion when a scene accent is picked,
   rather than snapping between two palettes.
   ========================================================================== */

@property --src-h {
  syntax: "<number>";
  inherits: true;
  initial-value: 262;
}

@property --src-c {
  syntax: "<number>";
  inherits: true;
  initial-value: 0.2;
}

:root {
  color-scheme: light;

  /* The source colour: the OBS accent #256eff in OKLCH. Chroma is clamped at
     0.20 — #256eff is 0.227, saturated enough that the light tones lose
     contrast if it is carried up the ramp unmodified. */
  --src-h: 262;
  --src-c: 0.2;

  /* ---- Primary: the OBS accent (key #256eff) ----------------------------- */
  /* #256eff itself is only 4.31:1 on the darkest OBS navy, so it is a fill
     colour here and never body text; the text-safe tones sit either side. */
  --md-primary: #1b52d6;
  --md-on-primary: #ffffff;
  --md-primary-container: #d9e2ff;
  --md-on-primary-container: #001845;

  /* ---- Secondary: the violet end of the OBS hero gradient (#280f83) ------ */
  --md-secondary: #4b3f9e;
  --md-on-secondary: #ffffff;
  --md-secondary-container: #e3dfff;
  --md-on-secondary-container: #180066;

  /* ---- Tertiary: the OBS amber ------------------------------------------- */
  --md-tertiary: #7a5300;
  --md-on-tertiary: #ffffff;
  --md-tertiary-container: #f39c12;
  --md-on-tertiary-container: #261a00;

  --md-error: #ba1a1a;
  --md-on-error: #ffffff;
  --md-error-container: #ffdad6;
  --md-on-error-container: #410002;

  /* ---- Neutrals: cool, blue-leaning paper to match the OBS navies -------- */
  --md-surface: #f4f6fb;
  --md-on-surface: #0c1633;
  --md-surface-bright: #ffffff;
  --md-surface-container-lowest: #ffffff;
  --md-surface-container-low: #eef1f8;
  --md-surface-container: #e8ecf6;
  --md-surface-container-high: #e1e7f3;
  --md-surface-container-highest: #d8e0ef;
  --md-on-surface-variant: #333f5e;
  --md-outline: #57647f;
  --md-outline-variant: #c4cde2;
  --md-inverse-surface: #101b41;
  --md-inverse-on-surface: #eceff7;
  --md-scrim: #000000;

  /* ---- Instrument roles -------------------------------------------------- */
  /* The slab is theme-invariant: #0a1129, straight off obsproject.com. */
  --inst-slab: #0a1129;
  --inst-on-slab: #eceff7;
  --inst-rail: #1b52d6; /* structural rails and the focus ring */
  --inst-signal: #f39c12; /* the OBS amber: one word per section, max */
  --inst-live: #e74c3c; /* tally / on-air, OBS's own red */
  --inst-armed: #ffbe6f;
  --inst-ok: #2ec27e;
  --inst-warn: #f39c12;

  /* ---- The feed ---------------------------------------------------------- */
  /* The OBS hero gradient, linear-gradient(45deg, #280f83, #065dac), spans the
     depth of the source wall: the far plane violet, the near plane blue. */
  --mesh-edge: #8ab4f8; /* Google blue: the network's own line colour */
  --mesh-node: #6f8fd0;
  --feed-far: #280f83;
  --feed-near: #065dac;
  --feed-line: #256eff;
  --feed-packet: #93aede; /* pale on paper: multiply darkens, it must not print solid */
  --feed-live: #e74c3c; /* tally on the source that is on air */

  /* ---- Scene accents ----------------------------------------------------- */
  /* The app's real per-scene accent colours. These drive the retint. */
  --acc-indigo: #6f78ff;
  --acc-purple: #9141ac;
  --acc-blue: #3584e4;
  --acc-teal: #00b0a8;
  --acc-green: #2ec27e;
  --acc-orange: #ff7800;
  --acc-red: #e01b24;

  /* ---- State layers (M3) ------------------------------------------------- */
  --state-hover: 0.08;
  --state-focus: 0.1;
  --state-press: 0.1;

  /* ---- Canvas ------------------------------------------------------------ */
  /* In light the packets are ink printed on paper; in dark they are emissive. */
  --bg-canvas-blend: multiply;
  --bg-canvas-opacity: 0.3;
  --three-opacity: 0.5;
  --feed-ceiling: 0.12; /* bounds how dark a source may print on paper */
  --scrim-floor: 52%;
  --fallback-grid: 7%;
  --fallback-near: 12%;
  --fallback-far: 9%;
  --packet-alpha: 0.12;

  /* ---- Shape ------------------------------------------------------------- */
  /* Radius encodes scale, never decoration: two elements sharing a radius
     must share a hierarchy level. */
  --r-none: 0px;
  --r-xs: 4px;
  --r-s: 8px;
  --r-m: 12px;
  --r-l: 16px;
  --r-xl: 28px;
  --r-xxl: clamp(24px, 5vw, 40px); /* the full-bleed slab */
  --r-full: 9999px;

  /* ---- Spacing ----------------------------------------------------------- */
  --s-1: 4px;
  --s-2: 8px;
  --s-3: 12px;
  --s-4: 16px;
  --s-5: 24px;
  --s-6: 32px;
  --s-7: 48px;
  --s-8: 64px;
  --s-9: 96px;
  --s-10: 128px;

  --section-pad: clamp(88px, 10.5vw, 176px);
  --slab-pad: clamp(104px, 12vw, 208px);
  --showpiece-pad: clamp(128px, 14vw, 256px);

  --w-content: 1320px;
  --w-slab: 1560px;
  --w-prose: 640px; /* 68ch, never wider */

  --page-margin: 20px;
  --gutter: 16px;
  --cols: 4;

  /* ---- Typography -------------------------------------------------------- */
  --font-display: "Unbounded", "Arial Black", system-ui, sans-serif;
  --font-text: "Onest", -apple-system, "Segoe UI", Roboto, Cantarell, sans-serif;
  --font-mono: "JetBrains Mono", ui-monospace, "Cascadia Mono", "Source Code Pro", monospace;

  /* ---- Motion ------------------------------------------------------------ */
  --ease-emphasized: cubic-bezier(0.2, 0, 0, 1);
  --ease-emphasized-decel: cubic-bezier(0.05, 0.7, 0.1, 1);
  --ease-emphasized-accel: cubic-bezier(0.3, 0, 0.8, 0.15);
  --ease-standard: cubic-bezier(0.2, 0, 0, 1);

  /* Slight overshoot: a fader cap hitting a detent, a needle settling. Used
     only where something mechanical comes to rest. */
  --ease-detent: cubic-bezier(0.34, 1.32, 0.36, 1);

  /* Telemetry is strictly linear. Instruments do not ease; easing a meter is
     a lie. Eased chrome against linear data is the whole motion idea here. */
  --ease-mechanical: linear;

  --d-short2: 100ms;
  --d-short3: 150ms;
  --d-short4: 200ms;
  --d-medium2: 300ms;
  --d-medium3: 350ms;
  --d-medium4: 400ms;
  --d-long2: 500ms;
  --d-long3: 550ms;
  --d-xlong1: 700ms;

  /* ---- Bevel ------------------------------------------------------------- */
  --bevel: inset 0 1px 0 #ffffff, inset 0 -1px 0 rgba(0, 0, 0, 0.07);
  --bevel-recessed: inset 0 2px 4px rgba(0, 0, 0, 0.14), inset 0 -1px 0 rgba(255, 255, 255, 0.5);

  --shadow-1: 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 3px 1px rgba(0, 0, 0, 0.06);
  --shadow-2: 0 1px 2px rgba(0, 0, 0, 0.1), 0 2px 6px 2px rgba(0, 0, 0, 0.07);
  --shadow-3: 0 1px 3px rgba(0, 0, 0, 0.1), 0 4px 8px 3px rgba(0, 0, 0, 0.07);
  --shadow-4: 0 2px 3px rgba(0, 0, 0, 0.1), 0 6px 10px 4px rgba(0, 0, 0, 0.07);

  /* ---- Z-index ladder ---------------------------------------------------- */
  /* Locked. Nothing may invent a value outside this list. */
  --z-three: -4;
  --z-pixi: -3;
  --z-grain: -2;
  --z-vignette: -1;
  --z-content: 0;
  --z-spine: 5;
  --z-nav: 50;
  --z-toast: 80;
  --z-skip: 100;
}

/* ---- Dark ---------------------------------------------------------------- */
/* Neutrals are the OBS navy ramp. #080f22 through #162458 are obsproject.com's
   own surface colours, so dark mode is the palette in its native habitat. */

:root[data-theme="dark"] {
  color-scheme: dark;

  --md-secondary: #c4c0ff;
  --md-on-secondary: #2c1b78;
  --md-secondary-container: #423490;
  --md-on-secondary-container: #e3dfff;

  --md-tertiary: #f39c12;
  --md-on-tertiary: #422c00;
  --md-tertiary-container: #5e4100;
  --md-on-tertiary-container: #ffddab;

  --md-error: #ffb4ab;
  --md-on-error: #690005;
  --md-error-container: #93000a;
  --md-on-error-container: #ffdad6;

  /* The OBS navy ramp, straight off obsproject.com. */
  --md-surface: #080f22;
  --md-on-surface: #eceff7;
  --md-surface-bright: #2d3243;
  --md-surface-container-lowest: #060b1a;
  --md-surface-container-low: #0a1129;
  --md-surface-container: #0c1633;
  --md-surface-container-high: #101b41;
  --md-surface-container-highest: #162458;
  --md-on-surface-variant: #c6cfe6;
  --md-outline: #96a3c7;
  --md-outline-variant: #2b3765;
  --md-inverse-surface: #eceff7;
  --md-inverse-on-surface: #0c1633;

  /* The OBS accent lifted until it clears AA on the navy: #72a2ff is 7.56:1
     where #256eff is only 4.31:1. */
  --md-primary: #a8c4ff;
  --md-on-primary: #002a6b;
  --md-primary-container: #16285c;
  --md-on-primary-container: #d9e2ff;

  --inst-slab: #0a1129;
  --inst-on-slab: #eceff7;
  --mesh-edge: #8ab4f8;
  --mesh-node: #c2d7ff;
  --inst-rail: #72a2ff;
  --inst-live: #ff6f63;
  --inst-ok: #57e19c;
  --inst-warn: #f39c12;

  --bg-canvas-blend: plus-lighter;
  --bg-canvas-opacity: 0.5;
  --three-opacity: 0.72;
  --feed-ceiling: 0.08;
  --scrim-floor: 38%;
  --fallback-grid: 12%;
  --fallback-near: 24%;
  --fallback-far: 18%;
  --feed-packet: #72a2ff;
  --packet-alpha: 0.34;

  --bevel: inset 0 1px 0 rgba(255, 255, 255, 0.1), inset 0 -1px 0 rgba(0, 0, 0, 0.4);
  --bevel-recessed: inset 0 2px 4px rgba(0, 0, 0, 0.35), inset 0 -1px 0 rgba(255, 255, 255, 0.06);

  --shadow-1: 0 1px 2px rgba(0, 0, 0, 0.45);
  --shadow-2: 0 1px 2px rgba(0, 0, 0, 0.5), 0 2px 6px 2px rgba(0, 0, 0, 0.3);
  --shadow-3: 0 1px 3px rgba(0, 0, 0, 0.55), 0 4px 8px 3px rgba(0, 0, 0, 0.35);
  --shadow-4: 0 2px 3px rgba(0, 0, 0, 0.6), 0 6px 10px 4px rgba(0, 0, 0, 0.4);
}

@supports not (mix-blend-mode: plus-lighter) {
  :root[data-theme="dark"] {
    --bg-canvas-blend: screen;
  }
}

/* ---- Grid ---------------------------------------------------------------- */

@media (min-width: 600px) {
  :root {
    --cols: 8;
    --gutter: 20px;
    --page-margin: 32px;
  }
}

@media (min-width: 905px) {
  :root {
    --cols: 12;
    --gutter: 24px;
    --page-margin: 48px;
  }
}

@media (min-width: 1240px) {
  :root {
    --gutter: 32px;
  }
}

@media (min-width: 1920px) {
  :root {
    --gutter: 40px;
  }
}
