@import url('https://fonts.googleapis.com/css2?family=Outfit:wght@400;500;600;700;800&family=JetBrains+Mono:wght@400;500;600&family=Figtree:wght@300;400;500;600&display=swap');
/* tokens.css — the WeYala / Ampera editorial design language, as ONE source.
 *
 * This is the single token set every surface should pull from — the dashboard,
 * the workspace, the front doors, marketing, and the Product Legibility export
 * (docs/46) — so nothing drifts toward generic SaaS ([[feedback_weyala_design_canonical]]).
 * Token-first, not library-first: pick the palette/type/motifs once here;
 * components (shadcn), charts (Tremor), diagrams (themed Mermaid) all inherit.
 *
 * See docs/48-design-system.md for the architecture + recommended tool stack.
 * Link it: <link rel="stylesheet" href="/tokens.css"> (before page styles).
 */
:root {
  /* ---- palette — Big Sky (coastal, sunny). The landing is the reference. ---- */
  --bg:            #F5F9FB;  /* luminous sky-white ground */
  --bg-deep:       #E9F1F5;  /* recessed / fills */
  --ink:           #10293A;  /* primary text — deep sky-slate */
  --ink-soft:      #37525F;  /* secondary text */
  --muted:         #6A8698;  /* labels, soft lines */
  --rule:          #D8E4EA;  /* hairline borders */
  --accent:        #2F8FCE;  /* sky-blue — the accent */
  --accent-soft:   #A9D0E6;
  /* --olive is now an ALIAS for --good, below (#2672). Both said #4E9C77. */
  --cobalt:        #3B7BA8;  /* links / the gig route */
  --ink-on-accent: #FBFEFF;
  --card:          #FFFFFF;  /* raised surfaces */
  --coral:         #E07A54;  /* warm accent — line symbols */

  /* ---- type ---- */
  --font-serif: 'Outfit', ui-sans-serif, system-ui, sans-serif; /* display / headings (geometric) */
  --font-mono:  'JetBrains Mono', ui-monospace, monospace;      /* state + labels */
  --font-sans:  'Figtree', ui-sans-serif, system-ui, sans-serif; /* prose + buttons */

  /* ---- radii / motion ---- */
  --radius:    16px;
  --radius-sm: 12px;
  --ease:      cubic-bezier(.2,.7,.2,1);

  /* ---- the grain overlay (tactile, not flat) — very subtle on the light ground ---- */
  --grain: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='200' height='200'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 0.1 0 0 0 0 0.12 0 0 0 0 0.15 0 0 0 0.015 0'/></filter><rect width='100%' height='100%' filter='url(%23n)'/></svg>");
}

/* ---- semantic names, so a page does not invent its own ---------------- */
/* These lived only in app.html's private :root, which is how they came to be
   defined once per page that wanted them. A name every surface needs belongs
   here (#1508). */
:root {
  --accent-deep:  #2578B0;  /* pressed / emphasis on the accent */
  --on-accent:    #FBFEFF;  /* text ON an accent fill */
  /* ---- THE STATUS COLOURS, RE-MEASURED (#2672) -------------------------
   *
   * Four of these were picked by eye and three could not be told apart. Run
   * through the dataviz palette validator against this ground:
   *
   *   --alert #C4553F vs --caution #A8761C   ΔE  2.8 deuteranopia · 10.3 normal
   *   --good  #4E9C77 vs --accent  #2F8FCE   ΔE 14.9 normal (floor is 15)
   *   --good  #4E9C77 vs --caution #A8761C   ΔE 14.8 normal
   *   --info  #6B5CB8 vs --accent  #2F8FCE   ΔE 13.9 normal
   *
   * The alert/caution pair is the bad one: "something needs a person" and
   * "needs a look" were the same colour to a deuteranope, and those are the two
   * a reader most needs to separate.
   *
   * HUE COULD NOT FIX IT AND THAT IS THE FINDING. Deuteranopia collapses the
   * red-green axis, so no amount of moving red toward orange separates it from
   * amber — the separation has to come from LIGHTNESS. Each replacement below
   * keeps its hue and moves its L, which is why they still read as the same
   * four meanings. Every pair now clears ΔE 15 for normal vision and ΔE 8 for
   * protan/deutan/tritan, and shared/status_palette_test.ts re-measures it from
   * THIS FILE on every CI run. */
  --good:         #005F38;  /* done. was #4E9C77 — ΔE 14.9 from --accent, under the floor */
  /* A LIFTED CORAL, for FILLS ONLY (#1847, #1849). The phase strip's progress
     band. --coral is the warm accent used for LINE SYMBOLS and, on the route
     view, for "not yet" — so a solid fill of it would borrow a meaning it
     already carries. This is the same warmth, lighter, and it must never be
     used for text: it does not carry --coral's contrast.
     Orange rather than green on purpose. Green on this page means done, and
     --good also means "can start now" on the rows below; a green bar under a
     phase name would have made one colour say two things on one screen. */
  --coral-lift:   #F0925F;
  --alert:        #AB2101;  /* something needs a person. was #C4553F — ΔE 2.8 from --caution under deuteranopia */

  /* ---- THE FOUR ROLES BIG SKY COULD NOT SAY (#2667, step 1) -------------
   *
   * Additive. Nothing above changes, and no surface moves yet.
   *
   * The operator console is not a recolour of Big Sky — it speaks a different
   * vocabulary. Unifying on Big Sky means Big Sky must first be able to say
   * everything the console says, or those states lose their colour on the way
   * across:
   *
   *   console --gold   "needs a look"     Big Sky had nothing
   *   console --cyan   "informational"    Big Sky had nothing
   *   console --dim    the faintest ink   Big Sky had nothing
   *   console --bg-2/3 layered grounds    Big Sky had --bg-deep only
   *
   * Values are VALIDATED, not chosen by eye, against this ground and against
   * the existing --accent: caution/info/accent separate at ΔE 24.5 normal and
   * 23.4 protan, well clear of the 15 floor. The console's own gold and cyan
   * were too light to use here unchanged.
   *
   * `--olive`, `--rose`, `--cyan` and `--gold` ARE aliased now — step 2 did it,
   * in the block below. This sentence used to say they were not, which was true
   * for exactly one change and would have read as the standing arrangement
   * afterwards. A declaration that contradicts the system is worse than a
   * missing one, because the next reader takes it as permission. */
  --caution:      #A8761C;  /* needs a look — not yet wrong, not yet fine */
  --info:         #3A2977;  /* informational — never a state, never a warning. was #6B5CB8 — ΔE 13.9 from --accent */
  --dim:          #9FB3C0;  /* fainter than --muted: present, deliberately quiet */
  --bg-2:         #DEEAF0;  /* a panel stacked on --bg-deep */
  --bg-3:         #D3E2EA;  /* and one stacked on that */
  --rule-soft:    #E4EDF2;  /* a division inside a panel, not between panels */
  /* THE ACCENT AT WASH STRENGTH — a selected or hovered surface, not a filled
     one. Added 2026-09-03 because it was USED IN THREE PLACES AND DEFINED IN
     NONE: plan-next's selected phase chip, its drop control on hover, and its
     sign-in button on hover all said `background-color: var(--accent-wash)`,
     which is invalid at computed-value time and falls back to transparent.
     Measured in the browser: a pressed chip and an unpressed chip were both
     rgba(0,0,0,0), so "blue says which one" never rendered — while a source
     test asserting the RULE EXISTS passed the whole time. A missing token does
     not fail; it silently paints nothing. */
  --accent-wash:  #E3F0FA;

  /* ---- THE CONSOLE'S SPELLINGS, POINTED AT BIG SKY'S ROLES (#2672, step 2) --
   *
   * Four names the operator pages say and Big Sky did not answer. Each one is
   * the SAME JOB as a role step 1 added or Big Sky already had, under a
   * different word — so this is a rename, not a new colour:
   *
   *   --cyan   informational              = --info
   *   --rose   something needs a person   = --alert
   *   --gold   needs a look               = --caution
   *   --olive  done / passing             = --good   (identical hex in both themes)
   *
   * THEY POINT AT THE ROLE, NOT A HEX, and that is the whole point. `--info` is
   * themed — #6B5CB8 here, #9E8FD8 on the dark ground — so one alias follows
   * every theme and a page that flips carries its meanings across. Writing the
   * hex twice is what made the palette need unifying in the first place.
   *
   * These lines are what made a page SAFE to flip off the console theme, and
   * then every page did. While that theme still existed this paragraph said
   * nothing operator-facing moves today, because its 0,2,0 selector outranked
   * this block's 0,1,0 — true for one afternoon, and it is rewritten rather
   * than left, because a comment describing an arrangement the file has since
   * left is read by the next person as permission to rebuild it. These four
   * aliases are now the ONLY definitions of those names. */
  --olive: var(--good);
  --cyan:  var(--info);
  --rose:  var(--alert);
  --gold:  var(--caution);

  /* ---- THE WASHES, DEFINED ONCE (#2672) ---------------------------------
   *
   * A wash is a tint of the colour it names and an edge is a stronger tint of
   * the same, so neither can be a value of its own: `color-mix` means changing
   * --rose moves every rose surface with it and they cannot disagree.
   *
   * These eight lived only inside the console block, which is why a page could
   * not use them on any other ground. `var(--rose)` here resolves against
   * whichever --rose wins the cascade on :root — the console's #D67A82 under
   * that theme, --alert everywhere else — so one definition serves all three
   * themes and the console copies were deleted rather than kept in step. That
   * is the #1508 fork this file exists to close: the same eight values stated
   * in two places with nothing keeping them agreed. */
  --rose-wash:  color-mix(in srgb, var(--rose)  10%, transparent);
  --rose-edge:  color-mix(in srgb, var(--rose)  40%, transparent);
  --olive-wash: color-mix(in srgb, var(--olive) 10%, transparent);
  --olive-edge: color-mix(in srgb, var(--olive) 40%, transparent);
  --gold-wash:  color-mix(in srgb, var(--gold)  10%, transparent);
  --gold-edge:  color-mix(in srgb, var(--gold)  40%, transparent);
  --cyan-wash:  color-mix(in srgb, var(--cyan)  10%, transparent);
  --cyan-edge:  color-mix(in srgb, var(--cyan)  40%, transparent);

  /* THE ACCENT AT GLOW STRENGTH (#2672). Four pages say var(--accent-glow) —
     build, dashboard, admin and build-sketch — and it was defined ONLY inside
     the console block, as a literal rgba() of the amber. So the token worked on
     exactly the theme its pages were pinned to and silently painted nothing
     anywhere else. Derived from --accent, so it follows the theme rather than
     naming one theme's colour. */
  --accent-glow: color-mix(in srgb, var(--accent) 18%, transparent);

  /* THE COLOUR A SHADOW IS MADE OF (#2672). admin.html had nine rgba(0,0,0,.)
     shadows — right on its near-black ground and a hole punched in the page on
     a light one, because a shadow is a colour and a literal one cannot follow a
     theme. On Big Sky light a shadow is the ink, not pure black: sky-slate
     reads as depth where black reads as dirt. */
  --shadow-ink:  #10293A;
}

/* ---- THE SKY ITSELF (#1531) --------------------------------------------
 *
 * David: "we lose the original blue — not the dark blue but the sky blue no?"
 *
 * He was right, and the reason is a contrast floor. On #F5F9FB the sky
 * #86CBF3 scores 1.67:1 — it CANNOT carry text, so as an accent it was never
 * an option and /app settled for #2F8FCE, a steel blue. The page kept its
 * numbers and lost its colour.
 *
 * index.html and datadive.html already solved it: THE SKY IS THE GROUND, NOT
 * THE INK. A gradient behind everything, ink stays #10293A at 14:1, and the
 * page reads unmistakably blue without a single character becoming unreadable.
 *
 * Both pages held a private copy, and datadive.html's own comment says
 * "Moving --sky-* into tokens is the follow-up". This is that follow-up — a
 * third copy on /app is exactly the fork that put a warm-cream top bar on
 * Pivot and a cool-blue one on the planner (#1508).
 *
 * BOTH DARK SELECTORS ARE LISTED. tokens.css says data-theme="dark";
 * datadive.html says "night". Two names for one state, which is its own debt —
 * covering both here means neither page breaks and datadive can drop its local
 * block whenever somebody reconciles the naming.
 */
:root {
  --sky-top:  #7CC6F2;   /* the landing's #86CBF3, deepened so white cards pop */
  --sky-mid:  #A6DCF8;
  --sky-low:  #CFEDFC;
  --sky-out:  #F5FBFE;   /* where the sky stops and the page begins */
  --sky-glow: radial-gradient(58% 52% at 78% 4%, rgba(255,250,224,.95), rgba(255,250,224,0) 58%);
}
:root[data-theme="dark"], :root[data-theme="night"] {
  --sky-top:  #071320;
  --sky-mid:  #0B2032;
  --sky-low:  #0C2231;
  --sky-out:  #0F1B26;
  --sky-glow: radial-gradient(50% 45% at 78% 6%, rgba(120,180,225,.22), rgba(120,180,225,0) 62%);
}

/* Drop one of these into a page and it has a sky. Fixed, behind everything,
   and pointer-transparent so it can never eat a click.
   --sky-depth is how far down the sky reaches: a page sets it, and that is the
   whole dial between a generous wash and a restrained band. */
.wy-sky {
  position: fixed; inset: 0; z-index: -2; pointer-events: none;
  background:
    var(--sky-glow),
    linear-gradient(180deg,
      var(--sky-top) 0%,
      var(--sky-mid) calc(var(--sky-depth, 100%) * .34),
      var(--sky-low) calc(var(--sky-depth, 100%) * .62),
      var(--sky-out) var(--sky-depth, 100%));
  transition: background .6s var(--ease);
}
@media (prefers-reduced-motion: reduce) { .wy-sky { transition: none; } }

/* Clouds drift across the sky. index.html had these too and kept them private,
   same as the gradient — a surface that wants weather should not have to
   redraw it (#1533). Pure decoration: fixed, behind, pointer-transparent. */
.wy-clouds { position: fixed; inset: 0; z-index: -1; pointer-events: none; overflow: hidden; }
.wy-cloud {
  position: absolute; border-radius: 50%; filter: blur(6px);
  background: radial-gradient(circle, rgba(255,255,255,.85), rgba(255,255,255,0) 70%);
}
.wy-cloud.a { width: 340px; height: 120px; top: 11%; left: -12%; animation: wy-drift 60s linear infinite; }
.wy-cloud.b { width: 240px; height:  90px; top: 26%; left:  40%; animation: wy-drift 90s linear infinite; opacity: .7; }
.wy-cloud.c { width: 300px; height: 100px; top:  6%; left:  68%; animation: wy-drift 75s linear infinite; opacity: .6; }
@keyframes wy-drift { from { transform: translateX(0); } to { transform: translateX(120vw); } }
@media (prefers-reduced-motion: reduce) { .wy-cloud { animation: none; } }

/* ---- Big Sky · NIGHT — the studio palette ------------------------------ */
/*
 * NO FLOOR IS DECLARED DARK HERE ANY MORE (#1597).
 *
 * The line that opened this block used to name the Tools floor and hand it this
 * palette by decision — which made /app the one dark surface in a product whose
 * landing, home and planner are all airy, and made it so for everybody rather
 * than for anyone who chose it. #1533/#1534 re-pointed --st-* on that page and
 * the shop came into the light; this comment stayed behind describing the
 * arrangement it had just left. A declaration nobody reads is debt. A
 * declaration that CONTRADICTS the system is worse, because the next person who
 * wants a dark surface reads it as permission and rebuilds what was removed.
 * shared/a_peek_is_a_reading_test.ts fails if the sentence comes back.
 *
 * What this palette IS: the studio look, available to any surface that wants
 * it, kept here so nobody has to redraw it (it was a private copy inside
 * app.html — the same fork that put a warm-cream .wy-topbar on Pivot and a
 * cool-blue one on the planner, #1508).
 *
 * NOT a prefers-color-scheme block: a deliberate surface treatment, not a
 * response to the reader's OS setting. Nothing wears it by default, and no page
 * may impose it — the ◐ control is the only thing that changes a reader's
 * theme (#1515 · #1524).
 */
:root {
  --st-bg:     #0F1B26;  /* the room */
  --st-board:  #0B1620;  /* recessed — the board behind the work */
  --st-card:   #17242F;
  --st-card-2: #1E2C38;
  --st-rule:   #2A3A47;
  --st-ink:    #EAF1F6;
  --st-soft:   #AEBFCB;
  --st-mut:    #7E92A0;
  --st-olive:  #78C29A;
  --st-acc:    #63A9D6;
  --st-alert:  #E0685C;
}

/* ---- Big Sky · DARK ----------------------------------------------------- */
/*
 * The customer-facing palette after dark. It lived inside app.html, twice, so
 * any other surface wanting it had to copy it — the same fork as the top bar
 * and the console palette (#1508).
 *
 * EXPLICIT ONLY. There is deliberately NO prefers-color-scheme block here.
 * A media query in this file would hand dark mode to every page that links it,
 * and eight of them carry hardcoded white backgrounds (budget alone has 12,
 * plus 2 black text rules) that would render as white slabs on a dark ground.
 * A page opts in by loading theme.js, which sets data-theme only where the page
 * says it is ready.
 */
:root[data-theme="dark"] {
  --bg:           #0F1B26;
  --bg-deep:      #17242F;
  --card:         #17242F;
  --ink:          #EAF1F6;
  --ink-soft:     #AEBFCB;
  --muted:        #7E92A0;
  --rule:         #2A3A47;
  --accent:       #63A9D6;
  --accent-deep:  #7FB6E0;
  --accent-soft:  #345267;
  /* --olive: aliased to --good in the base :root (#2672) — both were #78C29A. */
  --cobalt:       #7FB6E0;
  --on-accent:    #0F1820;
  --good:         #309C6B;  /* was #78C29A — ΔE 13.1 from --accent, recorded in step 1 and fixed here */
  --coral-lift:   #F0A07A;   /* the same lift, on the dark ground */
  --accent-wash:  #12314A;   /* the wash, on the dark ground */
  --alert:        #E0685C;

  /* The same four roles on the dark ground (#2667, step 1). Validated against
   * this surface and the dark --accent: caution/info/accent separate at ΔE 22.0
   * normal, 19.2 protan, 14.0 tritan.
   *
   * MEASURED AND LEFT ALONE: the EXISTING --good #78C29A and --accent #63A9D6
   * sit at ΔE 13.1 under NORMAL vision, below the 15 floor — a green and a blue
   * that are hard to tell apart with full colour vision, on the dark theme
   * today. That predates this change and moving either is a brand decision, not
   * an additive one, so it is recorded rather than quietly fixed. */
  --caution:      #D9B45C;
  /* was #9E8FD8, which step 1 shipped and step 2 measured properly: ΔE 1.7 from
     --accent under DEUTERANOPIA. Step 1's note quoted normal/protan/tritan and
     never deutan, which is the one that collapses this exact pair. Separated by
     lightness, because violet and blue cannot be separated by hue for a
     deuteranope. */
  --info:         #CEBAFF;
  --dim:          #5A6B78;
  --bg-2:         #1E2C38;
  --bg-3:         #24343F;
  --rule-soft:    #22323F;
  --coral:        #E0685C;
  /* the studio, deeper still, when the room itself is dark */
  --st-bg:        #0A1017;
  --st-board:     #070C12;
  --st-card:      #141F29;
  --st-card-2:    #1A2734;
  --st-rule:      #26333F;

  /* THE GRAIN, INVERTED FOR A DARK ROOM (#2672). The base --grain is a dark
     speckle for a light ground; over #0F1B26 it is invisible. build.html and
     dashboard.html each held a private copy of a LIGHT grain — byte-identical,
     warm-tinted for the console's amber — which is the #1508 fork again, twice.
     One definition, cooled to the sky palette rather than the console's. */
  --grain: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='180' height='180'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 0.92 0 0 0 0 0.96 0 0 0 0 1 0 0 0 0.035 0'/></filter><rect width='100%25' height='100%25' filter='url(%23n)'/></svg>");

  /* In a dark room a shadow IS black — there is nothing darker than the ground
     to tint it with. */
  --shadow-ink:   #000000;
}

/* ---- THE OPERATOR CONSOLE — RETIRED 2026-09-28 (#2667 step 5) ----------
 *
 * There was a fourth palette here: a dark amber-and-olive treatment that
 * admin, build, dashboard, plan and roadmap opted into with
 * data-theme="console". It was not stale paint — it was the four-view taxonomy
 * showing up in CSS, and it was right that operator tools looked different from
 * the customer's product.
 *
 * It is gone because the owner asked for one WeYala, and because keeping it
 * cost more than it said. A page on that theme could not use a Big Sky token
 * and a Big Sky page could not use a console one, so 165 colours — measured
 * properly, 1,090 — were written as literals on both sides of the line rather
 * than crossing it. The console did not have a vocabulary Big Sky lacked; Big
 * Sky simply had not been asked to say "needs a look" yet.
 *
 * WHAT HAPPENED TO ITS WORDS. --olive, --cyan, --rose and --gold are aliases in
 * the base :root now, pointing at --good, --info, --alert and --caution, so
 * every page that still says var(--rose) gets the right colour on whatever
 * ground it stands. The washes and --accent-glow went with them. Nothing was
 * deleted without somewhere to go.
 *
 * THE ORDER WAS THE WHOLE JOB. Retiring this block first would have left five
 * surfaces inheriting the LIGHT palette on a #0E0D0A ground, and a test in
 * shared/one_palette_test.ts failed on exactly that until the last page moved.
 * Operator surfaces now wear data-theme="dark" — still visibly not the
 * customer's product, and the same palette underneath.
 */

/* Font face loading — surfaces that link tokens.css get the brand fonts. */

/* The Mermaid house-theme init directive (for diagram-as-code surfaces) lives
   in code: shared/legibility/core.ts THEME + tools/legibility/editorial.css.
   It mirrors these tokens — keep them in sync (one palette, every output). */
