/* ==========================================================================
 * Slerp demo · top-level stylesheet
 *
 * Scope: the things the page's <link rel="stylesheet"> pulls in that
 * aren't owned by a JS module. Most of the VDJ deck + the shader
 * editor ship as CSS-in-JS inside `src/shared/audio/panel/styles/*`
 * and inject themselves at panel-open time; this file carries the
 * out-of-panel styles — design tokens, body shell, the shader
 * backdrop layer, the legacy "dock" host the FPS pill falls back
 * to, and the demo page's own layout.
 *
 * Layout:
 *   1. Design tokens          (:root)
 *   2. Base reset + typography (*, html, body, a, headings)
 *   3. Shader backdrop         (.starnest-bg, body.has-starnest)
 *   4. Legacy dock host        (.starnest-dock, .starnest-fps)
 *   5. Demo page layout        (.slerp-demo-*, .media-player-mount)
 *   6. Mobile polish           (narrow-viewport affordances)
 *
 * Skinning notes: every surface colour + radius + shadow comes
 * from a CSS custom property declared in section 1. A future
 * "theme" surface can override any subset of those on a parent
 * selector (e.g. `body[data-theme="warm"]`) without touching a
 * single rule below. See the TODO block at the bottom of section
 * 1 for the full skinnable surface.
 * ========================================================================== */


/* -- 1. Design tokens ---------------------------------------------------- */

:root {
  color-scheme: dark;

  /* --- Surfaces -------------------------------------------------------- */
  /* Near-black canvas with subtle cool tint. The shader backdrop
   * renders behind `body.has-starnest` with the body's own
   * background flipped transparent (see section 3), so these
   * values only show through when a shader isn't active. */
  --bg:         #0a0b0d;
  --bg-soft:    #0e1014;
  --surface:    #121317;
  --surface-hi: #1a1c22;

  /* --- Borders — 1px outlines, never filled. -------------------------- */
  --border:     rgb(255, 255, 255, 0.08);
  --border-hi:  rgb(255, 255, 255, 0.14);
  --border-em:  rgb(255, 255, 255, 0.22);

  /* --- Ink — off-white with a trace of warmth so it doesn't feel
   *     clinical. `--muted` is tuned to stay >=6:1 against the
   *     lightest glass panels, not just against `--bg`. */
  --fg:         #f4f4f6;
  --muted:      #9395a0;
  --muted-hi:   #c0c2ca;

  /* --- Accent — violet / blue family the audio panel + shader
   *     editor extend with their own gradients. Kept at the root so
   *     a skin override can retint the whole product from one place. */
  --accent:     #7aa2f7;
  --accent-hi:  #a6c0f9;
  --accent-weak:#2a3a5e;

  /* --- Slerp "LED" accent — the product's signature violet. The
   *     hue, saturation, and three lightness stops are exposed as
   *     individual custom properties so the LED-hue knob (see
   *     `src/shared/ledKnob.ts`) can retint the whole product by
   *     writing a single --slerp-accent-h value at :root. The
   *     default (260°) resolves to roughly #a78bfa / #c4b5fd /
   *     #7c3aed — the historic hand-picked triad. */
  --slerp-accent-h: 260;
  --slerp-accent-s: 90%;
  --slerp-accent-l: 76%;
  --slerp-accent-l-bright: 85%;
  --slerp-accent-l-deep: 65%;
  --slerp-accent:
    hsl(var(--slerp-accent-h) var(--slerp-accent-s) var(--slerp-accent-l));
  --slerp-accent-bright:
    hsl(var(--slerp-accent-h) var(--slerp-accent-s) var(--slerp-accent-l-bright));
  --slerp-accent-deep:
    hsl(var(--slerp-accent-h) var(--slerp-accent-s) var(--slerp-accent-l-deep));

  /* Derived surfaces the panel + editor build recurring glass
   * materials from. Kept as tokens so a future theme can retint
   * these too without every call-site recomputing the color-mix. */
  --slerp-ink:    #0a0b0d;
  --slerp-ink-2:  #111217;

  /* --- Status — muted, not shouty. ------------------------------------ */
  --success:    #7ee787;
  --danger:     #ff7b7b;

  /* --- Radii + shadows ------------------------------------------------- */
  --radius-sm:  6px;
  --radius:     10px;
  --radius-lg:  14px;
  --radius-xl:  20px;
  --shadow-focus: 0 0 0 3px rgb(122, 162, 247, 0.25);

  /* --- Type scale (px). ----------------------------------------------- */
  --fs-xs:  12px;
  --fs-sm:  14px;
  --fs-md:  16px;
  --fs-lg:  18px;
  --fs-xl:  22px;
  --fs-2xl: 28px;
  --fs-3xl: 40px;
  --fs-4xl: 56px;

  /* --- Spacing scale (px). -------------------------------------------- */
  --sp-1:  4px;
  --sp-2:  8px;
  --sp-3:  12px;
  --sp-4:  16px;
  --sp-5:  24px;
  --sp-6:  32px;
  --sp-7:  48px;
  --sp-8:  64px;
  --sp-9:  96px;

  /* --- TODO: future skinnable surfaces --------------------------------
   * When we land theming (see docs/roadmap.md · "User skins"), the
   * following JS-injected panel palettes are also candidates for
   * promotion to CSS custom properties so a single stylesheet can
   * retint everything:
   *
   *   - audio/panel/styles/base.ts   → --slerp-accent /
   *                                    --slerp-accent-bright /
   *                                    --slerp-accent-deep /
   *                                    --slerp-ink / --slerp-glass*
   *   - audio/panel/styles/editor.ts → editor card palette
   *                                    (#a78bfa, #c4b5fd, #7c3aed)
   *
   * Today those values are hard-coded inside the JS strings. Moving
   * them to `:root` vars here + referencing `var(--slerp-*)` from
   * the panel CSS would let `body[data-theme="warm"] { --slerp-accent:
   * #ff9f5c; ... }` skin the whole product without touching JS.
   */
}


/* -- 2. Base reset + typography ------------------------------------------ */

@font-face {
  font-family: Inter;
  src: url("/fonts/Inter.woff2") format("woff2-variations");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}

*,
*::before,
*::after {
  box-sizing: border-box;
}

/* The `hidden` HTML attribute maps to `display: none` via UA
 * styles but an explicit `display: flex/grid` on a class overrides
 * it. Make it authoritative. */
[hidden] {
  display: none !important;
}

html {
  text-size-adjust: 100%;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

body {
  margin: 0;
  padding: 0;
  background: var(--bg);
  color: var(--fg);
  font-family: Inter, ui-sans-serif, system-ui, -apple-system,
    "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  font-size: var(--fs-md);
  line-height: 1.55;
  font-feature-settings: "cv11", "ss03";
  letter-spacing: -0.005em;
}

a {
  color: var(--accent);
  text-decoration: none;
  transition: color 120ms ease;
}
a:hover { color: var(--accent-hi); }
a:focus-visible {
  outline: none;
  box-shadow: var(--shadow-focus);
  border-radius: var(--radius-sm);
}

::selection {
  background: rgb(122, 162, 247, 0.35);
  color: var(--fg);
}


/* -- 3. Shader backdrop -------------------------------------------------- */

/* Fixed-position WebGL canvas inserted at the top of <body> by
 * `src/shared/starNest.ts`. Purely decorative; the page remains
 * fully readable and interactive regardless of whether this
 * element exists. */
.starnest-bg {
  position: fixed;
  inset: 0;
  width: 100vw;
  height: 100vh;
  z-index: -1;
  pointer-events: none;
  display: block;
  background: transparent;
}

/* When the backdrop shader is active we hand the page's background
 * over to the shader. Every other style on the page stays identical
 * — only the body's own background flips transparent so the canvas
 * underneath is visible. */
body.has-starnest {
  background: transparent !important;
}


/* -- 4. Legacy dock host ------------------------------------------------- */

/* The right-side dock is legacy: starNest.ts used to mount a
 * picker + tune panel + slider rows there. The demo page now
 * replaces all of that with the in-deck Scene section, so the
 * dock's main purpose here is to be a positioned container for
 * the FPS pill when `tune.showFps` is on.
 *
 * `body.slerp-media-page` is set on every page of this app (see
 * index.html). The rules below hide the dock's children except
 * the FPS pill — the pill gets a special standalone-mode
 * fallback below that re-mounts it directly to the body when
 * the dock isn't present at all. */

body.slerp-media-page .starnest-dock {
  pointer-events: none;
}
body.slerp-media-page .starnest-dock > *:not(.starnest-fps) {
  display: none !important;
}

.starnest-dock {
  position: fixed;
  right: 12px;
  bottom: 12px;
  z-index: 40;
  display: flex;
  flex-direction: column;
  gap: 8px;
  align-items: flex-end;
}
.starnest-dock > * {
  pointer-events: auto;
}

/* --- Diagnostic FPS pill. Lives inside the starnest-dock as its
 *     only visible child on demo pages; falls back to
 *     body-mounted when there is no dock at all. Tier colours
 *     mirror the deck's own inline FPS readout for consistency.
 */
.starnest-fps {
  padding: 4px 10px;
  min-width: 62px;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 11px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.04em;
  line-height: 1;
  text-align: center;
  color: var(--muted);
  background: color-mix(in srgb, var(--bg) 70%, transparent);
  border: 1px solid var(--border);
  border-radius: 999px;
  backdrop-filter: blur(10px) saturate(140%);
  user-select: none;
  box-shadow: 0 4px 14px -4px color-mix(in srgb, black 60%, transparent);
}
.starnest-fps[data-tier="ok"] {
  color: var(--success);
  border-color: color-mix(in srgb, var(--success) 45%, transparent);
}
.starnest-fps[data-tier="warn"] {
  color: #ffc978;
  border-color: color-mix(in srgb, #f5a524 45%, transparent);
}
.starnest-fps[data-tier="bad"] {
  color: #ff9f9f;
  border-color: color-mix(in srgb, var(--danger) 50%, transparent);
}
.starnest-fps[data-tier="measuring"] {
  color: var(--muted);
}

/* Standalone mode: mounted directly on <body> when no dock is
 * present (e.g. after the dock-mount skip on immersive pages).
 * Pinned to the same bottom-right anchor the dock would have
 * used. */
.starnest-fps--standalone {
  position: fixed;
  right: 12px;
  bottom: 12px;
  z-index: 40;
}


/* -- 5. Demo page layout ------------------------------------------------- */

/* The demo is a single page: a full-viewport dark canvas with the
 * VDJ deck centred over the shader backdrop. The deck owns its own
 * max-width (560px) via the panel's CSS-in-JS; this section just
 * makes sure the mount element gives it room to breathe at any
 * viewport. */

body.slerp-demo-page {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: stretch;
}

body.slerp-demo-page .slerp-demo-main {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--sp-5);
}

body.slerp-demo-page .slerp-demo-mount {
  /* Stretch to the viewport width minus the panel's own max-width
   * cap; the panel centres itself inside this mount via
   * `margin: 0 auto` in its own CSS. */
  width: auto;
  max-width: min(96vw, 1100px);
}

.media-player-mount {
  /* Shared container class the demo main uses to host the panel.
   * The panel creates its own glass slab inside via
   * `slerp-audio-panel`; this wrapper is layout-only. */
  display: block;
  width: 100%;
}


/* -- 5b. Standalone legal pages (privacy.html, terms.html) ------------ */

body.slerp-legal-page {
  margin: 0;
  min-height: 100vh;
  background: var(--bg);
  color: var(--fg);
  font-family: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  line-height: 1.55;
}

.slerp-legal {
  max-width: 40rem;
  margin: 0 auto;
  padding: 2rem 1.25rem 3rem;
}

.slerp-legal-back {
  margin: 0 0 1.5rem;
  font-size: 0.9rem;
}

.slerp-legal-back a {
  color: var(--slerp-accent-bright);
  text-decoration: none;
}

.slerp-legal-back a:hover {
  text-decoration: underline;
}

.slerp-legal h1 {
  margin: 0 0 0.5rem;
  font-size: 1.5rem;
  font-weight: 600;
  letter-spacing: -0.02em;
}

.slerp-legal-updated {
  margin: 0 0 1.25rem;
  font-size: 0.85rem;
  color: var(--muted);
}

.slerp-legal p {
  margin: 0 0 1rem;
  font-size: 0.95rem;
  color: color-mix(in srgb, var(--fg) 90%, transparent);
}

.slerp-legal a[href^="mailto:"] {
  color: var(--slerp-accent-bright);
}

/* -- 6. Mobile polish ---------------------------------------------------- */

/* Narrow-viewport affordances. The deck + editor CSS-in-JS modules
 * carry their own @media rules for their internal elements; these
 * are the page-level affordances that belong to the stylesheet the
 * HTML loads directly. */

@media (max-width: 520px) {
  body.slerp-demo-page .slerp-demo-main {
    padding: var(--sp-2);
    align-items: flex-start;
  }
  body.slerp-demo-page .slerp-demo-mount {
    max-width: 100vw;
  }
}

/* Safe-area insets so iPhone notch + home-indicator don't clip
 * the FPS pill. */
@supports (padding: env(safe-area-inset-bottom)) {
  .starnest-dock,
  .starnest-fps--standalone {
    right: max(12px, env(safe-area-inset-right));
    bottom: max(12px, env(safe-area-inset-bottom));
  }
}

/* Respect the user's motion preference — the shader backdrop's
 * own rAF loop already feature-detects this via JS
 * (`reducedMotion()` in starNest.ts); this rule just makes sure
 * any subtle CSS transitions on the dock / FPS pill don't fire
 * either. */
@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;
  }
}
