/* egk-ui — the shared token layer for the Energetika estate.
 *
 * This file adds tokens. It changes nothing that already renders. Existing
 * modules keep using style.css; a module adopts egk-ui by opting in with the
 * `egk` class, and can then use these custom properties.
 *
 * Two ideas are load-bearing here and are worth stating before the values:
 *
 * 1. COLOUR CARRIES SEMANTIC FAMILY, NEVER STATUS. A body is cyan because it
 *    is evidence, not because it is good. Status lives in the epistemic
 *    treatment (below), which is a rendering, not a hue — so it survives
 *    greyscale, colour-blindness and a printed page.
 *
 * 2. EPISTEMIC CLASS IS A VISUAL PRIMITIVE. How we know a thing is as visible
 *    as the thing. A supplied value is solid; an absent one is a visible hole,
 *    never a zero and never a blank. This is the whole reason the estate gets
 *    a spatial layer at all: a table has nowhere to put this, and collapsing
 *    it into a value plus a green tick is what we are moving away from.
 *
 * ⚠️ Both themes are defined. The Living Instrument's first cut defined its
 * bodies with no fill at all, so they inherited `fill: black` and rendered at
 * 1.03:1 on the dark canvas — invisible, while every structural test passed.
 * Every family below is therefore specified per theme, and swept by
 * tests/js/instrument-contrast.test.mjs. Do not add a family without adding
 * it to both blocks.
 */

.egk {
  /* ---- Semantic families -------------------------------------------------
   * Five families, because five is what the estate actually has. Resist a
   * sixth: a family the eye cannot name is decoration.
   */
  --egk-evidence: #0f6b80;      /* observed in the world: usage, weather, fabric */
  --egk-evidence-soft: #a0c5cb;
  --egk-transformation: #5b3fb0; /* computation: a model run, a validation */
  --egk-transformation-soft: #c0bade;
  --egk-outcome: #8a5a08;        /* what the transformation produced */
  --egk-outcome-soft: #ccbd9d;
  --egk-candidate: #10705a;      /* an option, not yet a decision */
  --egk-candidate-soft: #a1c6bd;
  --egk-constraint: #a3231b;     /* a limit, a refusal, a gate */
  --egk-constraint-soft: #dab5b1;

  /* ---- Instrument surface ---- */
  --egk-field: #f2f7f5;          /* the field the bodies move in */
  --egk-field-edge: #cedbd5;
  --egk-current: #6c8a80;        /* a real relationship between two bodies */
  --egk-current-strong: #123f35;
  --egk-ink: #1c2924;
  --egk-ink-quiet: #53635c;

  /* ---- Epistemic rendering -----------------------------------------------
   * Consumed by instrument-render.js via [data-epistemic]. Kept as tokens so
   * a module can render an epistemic state without importing the instrument.
   */
  --egk-absent-dash: 3 4;        /* a hole you can see through */
  /* ⚠️ DERIVED, NOT CHOSEN. An absent body is filled with the field, so its
   * entire visibility is this dashed edge — and a stroke-opacity composites
   * the family colour ONTO the field before the eye ever sees it. At the
   * original 0.55 the worst case measured 2.31:1 (light/outcome) and 2.84:1
   * (dark/transformation): below the 3:1 floor for a graphical object, i.e.
   * a body that is present in the DOM and not on the screen. At 0.8 the worst
   * case is 3.68:1. The "hole" is carried by the field fill and the dash, not
   * by the dimness, so raising this costs the meaning nothing.
   *
   * Composited by tests/js/instrument-contrast.test.mjs — change this and the
   * sweep re-derives it. Do not raise the threshold to fit a value. */
  --egk-absent-alpha: 0.8;
  --egk-derived-ring: 0.55;      /* inner ring radius, as a fraction of r */
  --egk-refused-hatch: 2 3;

  /* ---- Motion ------------------------------------------------------------
   * At rest the amplitude is deliberately below the threshold at which a
   * body could be read as having moved somewhere. It says "alive", never
   * "changed". Anything that means "changed" must be an explicit transition.
   */
  --egk-drift-amplitude: 1.5px;
  --egk-drift-a: 17s;
  --egk-drift-b: 21s;
  --egk-drift-c: 26s;
  --egk-trace-duration: 1.6s;
  --egk-settle: 220ms;
  --egk-settle-ease: cubic-bezier(0.22, 0.61, 0.36, 1);

  /* ---- Frame ---- */
  --egk-focus: #0b6b4b;
  --egk-focus-ring: 3px;
  --egk-touch-min: 44px;         /* iPad-oriented surfaces; not negotiable */
  --egk-radius: 10px;
  --egk-gap: 12px;
  --egk-gap-wide: 20px;
}

/* The estate ships `data-theme="auto"` and resolves by media query, so the
 * dark values must be reachable both ways. */
@media (prefers-color-scheme: dark) {
  .egk[data-theme="auto"], [data-theme="auto"] .egk, html[data-theme="auto"] .egk {
    --egk-evidence: #4fc3d9;
    --egk-evidence-soft: #1d4649;
    --egk-transformation: #a98cf0;
    --egk-transformation-soft: #3d3d5a;
    --egk-outcome: #e8a33d;
    --egk-outcome-soft: #473f21;
    --egk-candidate: #70d6a4;
    --egk-candidate-soft: #244739;
    --egk-constraint: #f08a8a;
    --egk-constraint-soft: #503c3a;

    --egk-field: #0c1a17;
    --egk-field-edge: #38574c;
    --egk-current: #5d8577;
    --egk-current-strong: #c3eadb;
    --egk-ink: #edf6f2;
    --egk-ink-quiet: #b7c8c1;
    --egk-focus: #64d9ac;
  }
}

[data-theme="dark"] .egk, .egk[data-theme="dark"] {
  --egk-evidence: #4fc3d9;
  --egk-evidence-soft: #1d4649;
  --egk-transformation: #a98cf0;
  --egk-transformation-soft: #3d3d5a;
  --egk-outcome: #e8a33d;
  --egk-outcome-soft: #473f21;
  --egk-candidate: #70d6a4;
  --egk-candidate-soft: #244739;
  --egk-constraint: #f08a8a;
  --egk-constraint-soft: #503c3a;

  --egk-field: #0c1a17;
  --egk-field-edge: #38574c;
  --egk-current: #5d8577;
  --egk-current-strong: #c3eadb;
  --egk-ink: #edf6f2;
  --egk-ink-quiet: #b7c8c1;
  --egk-focus: #64d9ac;
}
