/*
 * MemQL's design tokens -- the one place the product's palette, type scale and
 * radius rhythm are written down.
 *
 * WHO IMPORTS THIS, AND WHY IT LIVES AT THE REPO ROOT
 *
 * Two builds consume this file and neither may carry a copy:
 *
 *   clients/os       Vite, bundling the imported CSS.
 *   component/identity/web   Tailwind v4 via the standalone CLI, output
 *                            embedded into the Go binary.
 *
 * They are a TypeScript app and a Go binary; they share no package manager and
 * no config format. Plain CSS custom properties are the one format both
 * consume, which is why the shared layer is CSS rather than a Tailwind config,
 * and why it sits at the repo root rather than inside either surface --
 * neither owns it. brand_shared_source_test.go asserts both builds import
 * these files instead of copying them, because two copies of a palette is
 * two palettes.
 *
 * WHAT LIVES HERE: the semantic roles (surface / fg / muted / border / accent /
 * danger), the type scale, the radius rhythm, and the control metrics -- the
 * one height a form control is built on, which is shared for the same reason
 * the palette is: two surfaces that disagree about it are two products. Semantic names, never colour
 * names: "mint-300" is a value that cannot survive a theme flip, "--memql-fg"
 * is a role that can. View-kit's --vk-* contract is NOT here -- view-kit is a
 * CONSUMER concern, and its bridge lives with whatever consumes it (the
 * portal's copy went with epic memql#4984; the VS Code extension carries its
 * own).
 *
 * THE PALETTE IS memql.io's, exactly (memql#4177). The neutrals are
 * green-tinted -- the dark ground is a near-black with a moss cast, the light
 * ground a warm paper -- and the one accent is the brand green the site's
 * graph mark wears. Warn and danger are re-derived warm hues muted toward the
 * same olive cast so the three status families read as one system.
 *
 * THEME RESOLUTION -- one definition per token via light-dark():
 *
 *   :root { color-scheme: light dark }        -> no data-theme attribute means
 *                                                "follow the OS", which is the
 *                                                correct default for a viewer
 *                                                who has never chosen.
 *   :root[data-theme="light"] { color-scheme: light }
 *   :root[data-theme="dark"]  { color-scheme: dark }
 *
 * Every colour token is written ONCE as light-dark(<light>, <dark>) and the
 * three color-scheme declarations are the entire switch. The portal writes the
 * attribute from src/app/theme.ts; the identity pages never write it, because
 * a sign-in page cannot read the portal's localStorage across origins -- they
 * follow the OS, which is the honest default there.
 *
 * DAYLIGHT -- THE LIGHT HALF, RE-GROUND (memql#4650)
 *
 * The light neutrals were green-tinted paper; they are near-neutral paper now.
 * The accent family, the status families, the data tints and EVERY dark-mode
 * value are byte-identical -- what moved is the six neutrals plus the two
 * lines, so the console reads as paper with a green accent rather than as a
 * green screen. Rationale and the owner's table:
 * docs/superpowers/specs/2026-08-26-portal-declutter-identity-design.md (C).
 *
 * TWO VALUES DEVIATE FROM THAT TABLE, and both are the table's own escape
 * clause ("exact hex may shift to hit the targets"):
 *
 *   --memql-fg-subtle  #7e837b, not #82877f. The spec value measures 3.67 on
 *                      white where today's #7c847b measures 3.86, and subtle
 *                      is PLACEHOLDER TEXT -- moving to a neutral is not a
 *                      licence to make the palette's weakest text weaker. This
 *                      value holds today's ratio (3.87) on the new ground.
 *   scrollbar thumb    follows --memql-border-strong, as its own note below
 *                      has always said it does. Leaving it at the OLD
 *                      border-strong would have made that sentence quietly
 *                      false; the HOVER step is picked to preserve today's
 *                      2.30 ratio, because the hover is the affordance.
 *
 * CONTRAST (measured, WCAG relative luminance -- keep this table honest when
 * a value moves):
 *   dark  fg/bg 15.96 . muted/bg 7.68 . subtle/bg 4.04 . accent/bg 10.21
 *         accent-fg on accent 10.21 . warn/bg 8.95 . danger/bg 6.32
 *         data-number/surface 16.08 . data-string/surface 9.15
 *   light fg/bg 15.89 . fg/surface 17.05 . fg/raised 14.80
 *         muted/bg 5.92 . muted/surface 6.35 . muted/raised 5.51
 *         subtle/bg 3.61 . subtle/surface 3.87 . subtle/raised 3.36
 *         accent/bg 4.79 . accent/surface 5.14 . accent-fg on accent 5.14
 *         warn/bg 5.10 . danger/surface 6.04 . danger/bg 5.63
 *         data-number/surface 5.47 . data-string/surface 5.02
 *         scrollbar thumb/surface 1.49 . thumb-hover/surface 2.30
 * The binding floors: body text is AA on all three light grounds (bg, surface
 * and surface-raised) and muted text clears 4.5:1 on bg and on surface, which
 * are this epic's two stated targets. warn is a border and a dot (non-text UI,
 * >= 3:1 against the ground it sits on -- both themes clear it with room);
 * accent and the data tints carry small text (>= 4.5:1 -- both themes clear
 * it). subtle is the one family below 4.5 and always has been: it is reserved
 * for placeholders and the literal "null", never for a sentence a reader has
 * to get through.
 */

:root {
  color-scheme: light dark;

  /* --- surfaces, back to front ------------------------------------- */
  --memql-bg: light-dark(#f7f7f5, #07090a);          /* the page itself */
  --memql-surface: light-dark(#ffffff, #0b1110);     /* cards, panels, the rail */
  --memql-surface-raised: light-dark(#efefec, #0e1311); /* hover, selected rows */

  /* --- foreground ---------------------------------------------------- */
  --memql-fg: light-dark(#191d1a, #e8e6dd);          /* body text */
  --memql-fg-muted: light-dark(#5b615c, #9ca395);    /* labels, secondary slots */
  --memql-fg-subtle: light-dark(#7e837b, #6c726a);   /* placeholders, "null" */

  /* --- lines --------------------------------------------------------- */
  --memql-border: light-dark(#e5e6e2, #18231e);
  --memql-border-strong: light-dark(#d2d4cf, #213029);

  /* --- accents -------------------------------------------------------- */
  --memql-accent: light-dark(#047d5a, #5ccda7);
  --memql-accent-fg: light-dark(#ffffff, #07090a);
  --memql-accent-subtle: light-dark(#dcefe6, #0f2a20);
  /* The deep brand green, for the rare filled moment that wants the site's
     darker pole (memql.io's accent-deep #026842 family). Not a status. */
  --memql-accent-deep: light-dark(#026842, #026842);

  /* --- status ---------------------------------------------------------
   * ok IS the brand green: on a console whose brand is green, "healthy"
   * wearing the accent is the point, not a collision. warn/danger are warm
   * hues pulled toward the olive-tinted neutrals so the three families sit
   * in one palette; ratios in the header table.
   */
  --memql-ok: light-dark(#047d5a, #5ccda7);
  --memql-ok-subtle: light-dark(#dcefe6, #0f2a20);
  --memql-warn: light-dark(#8a6210, #d2a75a);
  --memql-warn-subtle: light-dark(#f5ead2, #2a2113);
  --memql-danger: light-dark(#b3362a, #e0705f);
  --memql-danger-subtle: light-dark(#f8e3df, #2b1512);

  /* --- the two-voice data tints ---------------------------------------
   * Graph data (ids, counts, timestamps, field values) renders in the mono
   * voice with these tints -- numbers mint, strings amber -- mirroring the
   * site's code samples. Chrome never wears them.
   */
  --memql-data-number: light-dark(#0f766e, #98ffe0);
  --memql-data-string: light-dark(#b45309, #cbb083);

  /* --- type scale ----------------------------------------------------
   * A fifth-based ramp, deliberately short. Five sizes is enough for an
   * operations console and a short ramp is what keeps two screens built by
   * two different issues looking like one product. `display` is the one
   * exception -- the Squada One big-number/wordmark size -- and it is a
   * moment, not a step pages may reach for casually.
   */
  --memql-text-xs: 0.75rem;
  --memql-text-sm: 0.8125rem;
  --memql-text-base: 0.9375rem;
  --memql-text-lg: 1.125rem;
  --memql-text-xl: 1.5rem;
  --memql-text-display: 2.25rem;

  /* Inter carries the chrome; JetBrains Mono carries the data voice -- rows,
     ids and payload values are read character by character, not word by
     word. Squada One is the display face: the wordmark and big-number
     moments only. All three are self-hosted (fontsource) because the edge
     CSP allows no external font host; the stacks keep real fallbacks. */
  --memql-font-sans: "InterVariable", "Inter", ui-sans-serif, system-ui,
    -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --memql-font-mono: "JetBrains Mono", ui-monospace, SFMono-Regular, "SF Mono",
    Menlo, Consolas, "Liberation Mono", monospace;
  --memql-font-display: "Squada One", "InterVariable", "Inter", ui-sans-serif,
    sans-serif;

  --memql-radius: 0.375rem;
  --memql-radius-lg: 0.625rem;

  /* --- motion ----------------------------------------------------------
   * ONE DURATION AND ONE CURVE, because a console with three of each has
   * none. Every state change a person can cause -- a hover wash, a tab
   * underline sliding, a dialog settling, a row rising into place -- runs at
   * this duration on this curve, so the whole surface moves as one object
   * instead of as a collection of components that each guessed.
   *
   * 160ms is chosen to be BELOW the threshold where a transition reads as an
   * animation rather than as responsiveness. The curve is fast-out, hard-in:
   * it leaves immediately (so the interface never feels like it is deciding)
   * and arrives without overshoot (so nothing bounces -- this is an
   * operations console, not a toy).
   *
   * These are metrics, not colours, so they carry no light-dark() pair: the
   * theme flip must never change how fast anything moves.
   *
   * WHAT DOES NOT USE THEM: the breathing pulses in the portal's own
   * stylesheet (the connection mark, streaming states). Those are not
   * responses to a gesture -- they are a running thing saying it is running,
   * and they are deliberately slow enough to read as a heartbeat.
   */
  --memql-motion-dur: 160ms;
  --memql-motion-ease: cubic-bezier(0.2, 0, 0, 1);

  /* --- control metrics -------------------------------------------------
   * THE HEIGHT OF A CONTROL IS A TOKEN, not an emergent property of padding.
   *
   * Before memql#4503 nothing in either surface stated a control height, so
   * every kind of control arrived at its own by accident: text inputs and
   * selects ~38px from `px-3 py-2 text-sm`, the portal's Button sm ~34px, its
   * Button xs ~26px, the identity pages' `.btn` ~38px again. Put any two of
   * them in the same row and they disagree -- which is exactly what a form
   * row is. And a native <select> is worse than merely different: it adds
   * per-platform chrome on top of whatever padding it was given, so the same
   * class string measures differently on Linux and macOS.
   *
   * Two steps, because an operations console needs exactly two: the line a
   * form is built on, and a compact line for table cells and band headers.
   * A control anywhere near a form field wears `control`; `control-sm` is for
   * controls that sit inside dense data, where a 36px row would be the loudest
   * thing on the screen.
   *
   * These are METRICS, not colours, so they carry no light-dark() pair -- the
   * theme flip must never move a box.
   */
  --memql-control-h: 2.25rem;    /* 36px -- inputs, selects, buttons in a form row */
  --memql-control-h-sm: 1.75rem; /* 28px -- table cells, band headers, chips */

  /* --- scrollbars ------------------------------------------------------
   * The thumb is the border family, one step stronger than a resting line:
   * a scrollbar is chrome that should be findable when looked for and silent
   * otherwise. The track stays transparent (declared at the rule, not here --
   * there is no value to name) so a bar inside the rail does not paint a
   * second surface colour over `--memql-surface`.
   *
   * Hover is one step stronger again, which is the whole affordance: the bar
   * is draggable and nothing else on the page darkens under the pointer.
   */
  --memql-scrollbar-thumb: light-dark(#d2d4cf, #213029);
  --memql-scrollbar-thumb-hover: light-dark(#a9aca5, #33473c);
}

/* The explicit choice, written by src/app/theme.ts. Pinning color-scheme is
 * the entire override: every light-dark() token above re-resolves. */
:root[data-theme="light"] {
  color-scheme: light;
}

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

/* Reduced motion, in ONE place.
 *
 * Zeroing the duration token is the whole opt-out for everything that
 * transitions: a rule written as `transition-duration: var(--memql-motion-dur)`
 * becomes 0ms here and the state change lands instantly, with no per-component
 * media query and nothing to forget. The CURVE is left alone -- a curve over
 * zero time is not motion.
 *
 * It is not the whole story, and it is not meant to be. Keyframe animations
 * (the mark's breathing, a staggered first paint, the token float) name a
 * duration of their own, so each still needs its own reduced-motion rule
 * beside it -- which is why the portal's stylesheet keeps its own opt-out
 * block. What this removes is the LARGEST category: every hover, focus,
 * selection and open/close transition in both surfaces, at once. */
@media (prefers-reduced-motion: reduce) {
  :root {
    --memql-motion-dur: 0ms;
  }
}
