/* melange project site — one stylesheet, no framework, no build step.
 *
 * The colours are theme.md's, copied rather than imported. melange has no design-token
 * pipeline and no build step; theme.md says a new surface copies the :root block, so this
 * one does.
 *
 * Two rules from there are easy to undo by accident:
 *   - --accent is clay, not sun. Sun (--accent-hot) is 3.96:1 against white and cannot
 *     hold text; clay is 5.72:1. Fills-with-labels use --accent, bare marks use
 *     --accent-hot.
 *   - --bad is a red from outside the icon. Using the icon's rust would make a failed
 *     badge and a running badge differ by about 6% lightness.
 *
 * Where this parts company with the web UI is the *picture*, not the palette. The icon is
 * a landscape — cream sky, low sun, overlapping hills, a dark ridge — and the app takes
 * only its colours. This page takes its shape: you descend a horizon, the ridges divide
 * the sections, and the sun tracks your scroll. Same blood, different surface, so the two
 * are recognisably one product without the site looking like a screenshot of the app.
 *
 * THEMING IS THREE-STATE here, unlike the web UI's prefers-color-scheme-only. A visitor
 * should be able to see both themes on a page whose whole job is showing the thing off.
 * So every token is defined on bare :root, redefined under the media query guarded by
 * :root:not([data-theme=light]), and redefined again under :root[data-theme=dark] so an
 * explicit choice wins in both directions. A colour whose only definition sits inside a
 * media block renders as light-mode ink on a dark ground.
 */

:root {
  color-scheme: light dark;

  /* the icon, sampled — the only place a hex literal is allowed */
  --cream:    #fef5e9;
  --sand:     #d3aa7b;
  --ochre:    #be6d2f;
  --sun:      #d25c1b;
  --clay:     #ac4817;
  --espresso: #3a2d20;
  --ink:      #1c1e1b;

  --bg:         #f8ecdb;
  --panel:      var(--cream);
  --panel-2:    #f0dfc8;
  --line:       #e3cdae;
  --text:       #2a2119;
  --muted:      #7a6a57;
  --accent:     var(--clay);
  --accent-hot: var(--sun);
  --accent-fg:  var(--cream);

  --ok:    #4c7a3f;
  --warn:  #8f6111;
  --bad:   #9c1f16;
  --dead:  #7a5486;
  --idle:  #7a6a57;

  /* espresso, not black: a neutral shadow goes grey-blue over cream */
  --shadow-1: 0 8px 24px rgb(58 45 32 / 0.16);
  --shadow-2: 0 18px 56px rgb(58 45 32 / 0.30);

  --mono: ui-monospace, "SF Mono", SFMono-Regular, Menlo, Consolas, "Cascadia Mono", monospace;
  --sans: system-ui, -apple-system, "Segoe UI", sans-serif;

  --radius:    10px;
  --radius-lg: 16px;
  --dur:       .5s;
  --dur-fast:  .18s;
  --ease:      cubic-bezier(.22, .61, .36, 1);
  --heat:      linear-gradient(90deg, var(--sand), var(--sun) 62%, var(--clay));
  --glow:      0 0 14px rgb(210 92 27 / 0.30);
  --ring:      rgb(210 92 27 / 0.55);

  /* The hills, back to front. Named rather than used inline so a divider is one class. */
  --hill-1: var(--sand);
  --hill-2: var(--ochre);
  --hill-3: var(--clay);
  --ridge:  var(--espresso);

  /* Syntax, for the quick-start code blocks. The same colours as the web UI editor,
     picked for contrast against --panel-2. Every one MUST be redefined in both dark
     blocks below. */
  --tok-comment: #7a6a57;
  --tok-str:     #4c7a3f;
  --tok-kw:      #9c1f16;
  --tok-var:     #ac4817;
  --tok-cmd:     #2a2119;
  --tok-fn:      #ac4817;
  --tok-num:     #7a5486;
  --tok-punct:   #7a6a57;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg:         #1a1712;
    --panel:      #24201a;
    --panel-2:    #2e281f;
    --line:       #3e362a;
    --text:       #f5e9d8;
    --muted:      #a5947c;
    /* the accents lift, and a filled button flips to dark-on-bright */
    --accent:     #e8814a;
    --accent-hot: #f2955f;
    --accent-fg:  #24180f;

    --ok:   #86c46b;
    --warn: #d9a441;
    --bad:  #f0705f;
    --dead: #b98fc9;
    --idle: #a5947c;

    --shadow-1: 0 8px 24px rgb(0 0 0 / 0.45);
    --shadow-2: 0 18px 56px rgb(0 0 0 / 0.6);
    --heat:  linear-gradient(90deg, var(--ochre), var(--sun) 55%, #f2955f);
    --glow:  0 0 18px rgb(242 149 95 / 0.45);
    --ring:  rgb(242 149 95 / 0.6);

    --hill-1: #6b4f34;
    --hill-2: #7d4622;
    --hill-3: #5e2c14;
    --ridge:  #2a2119;

    --tok-comment: #a5947c;
    --tok-str:     #86c46b;
    --tok-kw:      #f0705f;
    --tok-var:     #e8814a;
    --tok-cmd:     #f5e9d8;
    --tok-fn:      #e8814a;
    --tok-num:     #b98fc9;
    --tok-punct:   #a5947c;
  }
}

:root[data-theme="dark"] {
  --bg:         #1a1712;
  --panel:      #24201a;
  --panel-2:    #2e281f;
  --line:       #3e362a;
  --text:       #f5e9d8;
  --muted:      #a5947c;
  --accent:     #e8814a;
  --accent-hot: #f2955f;
  --accent-fg:  #24180f;

  --ok:   #86c46b;
  --warn: #d9a441;
  --bad:  #f0705f;
  --dead: #b98fc9;
  --idle: #a5947c;

  --shadow-1: 0 8px 24px rgb(0 0 0 / 0.45);
  --shadow-2: 0 18px 56px rgb(0 0 0 / 0.6);
  --heat:  linear-gradient(90deg, var(--ochre), var(--sun) 55%, #f2955f);
  --glow:  0 0 18px rgb(242 149 95 / 0.45);
  --ring:  rgb(242 149 95 / 0.6);

  --hill-1: #6b4f34;
  --hill-2: #7d4622;
  --hill-3: #5e2c14;
  --ridge:  #2a2119;

  --tok-comment: #a5947c;
  --tok-str:     #86c46b;
  --tok-kw:      #f0705f;
  --tok-var:     #e8814a;
  --tok-cmd:     #f5e9d8;
  --tok-fn:      #e8814a;
  --tok-num:     #b98fc9;
  --tok-punct:   #a5947c;
}

/* === END TOKENS ===
 * No hex literal may appear below this line. Everything from here on refers to the
 * semantic tokens above, which is what keeps the two themes honest — a colour written
 * inline is one that only ever gets checked in whichever theme its author had open.
 * `no_hex_literals_outside_the_token_blocks` enforces it. */

* { box-sizing: border-box; }

html { scroll-behavior: smooth; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font: 16px/1.65 var(--sans);
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
  border-radius: 3px;
}

a { color: var(--accent); text-decoration-thickness: 1px; text-underline-offset: 3px; }
a:hover { color: var(--accent-hot); }

h1, h2, h3 { line-height: 1.12; letter-spacing: -0.02em; margin: 0; font-weight: 650; }

code, kbd, pre { font-family: var(--mono); }

/* Skip link — the page is long and its nav is repetitive. */
.skip {
  position: absolute; left: -9999px; top: 0; z-index: 100;
  background: var(--accent); color: var(--accent-fg);
  padding: .6rem 1rem; border-radius: 0 0 var(--radius) 0;
}
.skip:focus { left: 0; }

/* --- The sun ----------------------------------------------------------------------
 * A single fixed radial wash behind everything, whose vertical position is driven by
 * scroll depth (--sun-y, set in app.js). It is the one thing that makes the page feel
 * like a descent rather than a stack of cards, and it costs one custom property.
 * Behind `prefers-reduced-motion` it simply sits still. */
.sun {
  position: fixed; inset: 0; z-index: -1; pointer-events: none;
  background:
    radial-gradient(60rem 40rem at 50% calc(var(--sun-y, 0) * 100%),
      rgb(from var(--accent-hot) r g b / 0.16), transparent 70%);
}

/* --- Top bar ---------------------------------------------------------------------- */
.top {
  position: sticky; top: 0; z-index: 50;
  display: flex; align-items: center; gap: 1rem;
  padding: .7rem clamp(1rem, 4vw, 2.5rem);
  /* Without relative-colour support the declaration below is dropped whole, and a
     transparent sticky bar puts the page under itself. */
  background: var(--panel);
  background: rgb(from var(--panel) r g b / 0.82);
  backdrop-filter: blur(12px);
  border-bottom: 1px solid var(--line);
}
.brand { display: flex; align-items: center; gap: .6rem; text-decoration: none; color: inherit; }
.brand img { width: 26px; height: 26px; display: block; }
.wordmark { font-family: var(--mono); font-size: 1.05rem; font-weight: 600; letter-spacing: -.02em; }
.top nav { margin-left: auto; display: flex; align-items: center; gap: .25rem; }
.top nav a {
  font-size: .87rem; color: var(--muted); text-decoration: none;
  padding: .4rem .7rem; border-radius: var(--radius);
}
.top nav a:hover { color: var(--text); background: var(--panel-2); }
@media (max-width: 860px) { .top nav a.opt { display: none; } }

/* The theme control: three states, because "system" is a real answer and a two-way
   toggle silently overrides it the first time anybody touches the button. */
.theme { display: flex; gap: 2px; padding: 2px; background: var(--panel-2); border-radius: var(--radius); }
.theme button {
  font: inherit; font-size: .8rem; line-height: 1;
  padding: .35rem .5rem; border: 0; border-radius: calc(var(--radius) - 3px);
  background: transparent; color: var(--muted); cursor: pointer;
}
.theme button[aria-pressed="true"] { background: var(--panel); color: var(--text); box-shadow: var(--shadow-1); }

/* --- Layout ----------------------------------------------------------------------- */
.wrap { width: min(1120px, 100% - clamp(2rem, 8vw, 5rem)); margin-inline: auto; }
section { position: relative; padding: clamp(4rem, 9vw, 7.5rem) 0; }

.eyebrow {
  font-family: var(--mono); font-size: .8rem; letter-spacing: .12em; text-transform: uppercase;
  color: var(--muted); display: flex; align-items: center; gap: .7rem; margin-bottom: 1rem;
}
.eyebrow::before {
  content: ""; width: 2.5rem; height: 2px; border-radius: 2px; background: var(--heat);
}
h2 { font-size: clamp(1.8rem, 4vw, 2.7rem); max-width: 22ch; }
.lede { color: var(--muted); font-size: clamp(1rem, 1.6vw, 1.15rem); max-width: 62ch; margin: 1rem 0 0; }

/* --- The ridge dividers -----------------------------------------------------------
 * Layered hills between sections. They are decorative and marked aria-hidden; the SVG
 * carries no meaning the text does not already have. */
.ridge {
  display: block; width: 100%; height: clamp(60px, 9vw, 130px);
  /* The two edges are the whole difficulty. A ridge is drawn from the light side into
     the dark one, so the *solid* path has to meet .on-ridge's fill exactly and across
     the whole width — which is why its wave stays clear of y=120 rather than dipping to
     touch it, and why the 1px overlap is here: `preserveAspectRatio="none"` scales the
     viewBox to a fractional height, and the rounding leaves a hairline of the wrong
     colour along the join. */
  margin-block: -1px;
}
.ridge path:nth-child(1) { fill: var(--hill-1); opacity: .5; }
.ridge path:nth-child(2) { fill: var(--hill-2); opacity: .55; }
.ridge path:nth-child(3) { fill: var(--hill-3); opacity: .6; }
.ridge path:nth-child(4) { fill: var(--ridge); }
/* Coming back *out* of the dark band, the same drawing is simply turned over — so the
   solid ridge stays against the dark side and the hills still fade towards the light
   one. Reversing the fills instead (which is what the flipped duplicate paths used to
   do) put the darkest band against the light section and left a hard edge above it. */
.ridge.up { transform: scaleY(-1); }
.on-ridge { background: var(--ridge); color: var(--cream); }
.on-ridge .lede, .on-ridge .eyebrow { color: var(--sand); color: rgb(from var(--cream) r g b / 0.68); }

/* --- Hero -------------------------------------------------------------------------- */
.hero { padding-top: clamp(3rem, 8vw, 6rem); padding-bottom: clamp(2rem, 5vw, 4rem); }
.hero-grid { display: grid; grid-template-columns: 1.05fr .95fr; gap: clamp(2rem, 5vw, 4rem); align-items: center; }
@media (max-width: 900px) { .hero-grid { grid-template-columns: 1fr; } }

.hero h1 { font-size: clamp(2.4rem, 6.2vw, 4.2rem); letter-spacing: -.035em; }
.hero h1 em { font-style: normal; color: var(--accent); }
.hero p.tag { font-size: clamp(1.05rem, 2vw, 1.3rem); color: var(--muted); max-width: 46ch; margin: 1.4rem 0 0; }
.hero-mark { width: 68px; height: 68px; margin-bottom: 1.5rem; display: block; }

.cta { display: flex; flex-wrap: wrap; gap: .8rem; margin-top: 2.2rem; }
.btn {
  display: inline-flex; align-items: center; gap: .5rem;
  font: inherit; font-size: .95rem; font-weight: 550;
  padding: .7rem 1.2rem; border-radius: var(--radius);
  border: 1px solid transparent; text-decoration: none; cursor: pointer;
  transition: transform var(--dur-fast) var(--ease), background var(--dur-fast) var(--ease);
}
.btn:active { transform: translateY(1px); }
/* Clay, never sun: this fill holds a label. */
.btn-primary { background: var(--accent); color: var(--accent-fg); }
.btn-primary:hover { background: var(--accent-hot); color: var(--accent-fg); }
.btn-ghost { background: var(--panel); color: var(--text); border-color: var(--line); }
.btn-ghost:hover { background: var(--panel-2); color: var(--text); }

/* --- Numbers ----------------------------------------------------------------------- */
.numbers { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: 1px; background: var(--line); border: 1px solid var(--line); border-radius: var(--radius-lg); overflow: hidden; }
.num { background: var(--panel); padding: 1.6rem 1.2rem; }
.num b { display: block; font-family: var(--mono); font-size: clamp(1.5rem, 3vw, 2.1rem); font-weight: 600; letter-spacing: -.03em; }
.num span { display: block; color: var(--muted); font-size: .85rem; margin-top: .35rem; }

/* --- Cards ------------------------------------------------------------------------- */
.cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 1.2rem; margin-top: 2.5rem; }
.card {
  background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius-lg);
  padding: 1.5rem; box-shadow: var(--shadow-1);
}
.card h3 { font-size: 1.08rem; margin-bottom: .6rem; }
.card p { margin: 0; color: var(--muted); font-size: .95rem; }
.card p + p { margin-top: .7rem; }
.on-ridge .card { background: transparent; border-color: var(--hill-1); background: rgb(from var(--cream) r g b / 0.06); border-color: rgb(from var(--cream) r g b / 0.14); box-shadow: none; }
.on-ridge .card p { color: var(--sand); color: rgb(from var(--cream) r g b / 0.66); }

/* Features are denser than cards: a title and one line, twelve of them. */
.features { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 1px; background: var(--line); border: 1px solid var(--line); border-radius: var(--radius-lg); overflow: hidden; margin-top: 2.5rem; }
.feat { background: var(--panel); padding: 1.3rem; }
.feat h3 { font-size: .98rem; margin-bottom: .35rem; }
.feat p { margin: 0; color: var(--muted); font-size: .88rem; line-height: 1.55; }
.feat b { font-family: var(--mono); font-size: .82rem; color: var(--accent); font-weight: 500; }

/* --- The job-flow diagram -----------------------------------------------------------
 * Section 02's stage is full width and its own aspect ratio is wide, so on a narrow
 * screen it scrolls sideways inside the card rather than shrinking to a smudge — a
 * diagram with node cards in it has a floor below which it says nothing at all. */
.flow { margin-top: 2.5rem; display: grid; gap: 1.6rem; }
.flow-wide { overflow-x: auto; overscroll-behavior-x: contain; }
.flow-wide svg { min-width: 720px; }
.flow-read { display: grid; grid-template-columns: 1fr auto; gap: 1.5rem 2rem; align-items: start; }
@media (max-width: 780px) { .flow-read { grid-template-columns: 1fr; } }
/* Seven short steps in one column is a very tall list under a very wide picture. */
@media (min-width: 700px) { .flow-steps { columns: 2; column-gap: 2.5rem; } }
.flow-steps li { break-inside: avoid; }

.flow-stage {
  /* A low wash from the top edge, so the stage reads as a lit surface rather than a
     flat swatch. The plain --panel underneath is the fallback wherever the relative
     colour is unsupported and the layer is dropped whole. */
  background: var(--panel);
  background:
    radial-gradient(120% 80% at 50% -10%, rgb(from var(--accent-hot) r g b / 0.09), transparent 65%),
    var(--panel);
  border: 1px solid var(--line); border-radius: var(--radius-lg);
  padding: 1.2rem; box-shadow: var(--shadow-1);
}
.flow-stage svg { width: 100%; height: auto; display: block; overflow: visible; }

/* The dotted ground. It is one <pattern>, shared by both diagrams — an id resolves
   document-wide, so only the hero carries the <defs>. */
#fl-dots circle { fill: var(--line); }
.fl-grid { opacity: .8; }

/* --- Boxes -------------------------------------------------------------------------
 * Everything is dim until the current step names it. The whole group carries `.on`, so
 * a card, its label and its badges brighten together. */
/* Only the box itself, never `.fl-node rect` — a descendant selector is (0,1,1) and
   would quietly outrank every (0,1,0) class on the pips, badges, ticks and bars inside
   it, which is a fill that looks *almost* right and is impossible to spot. */
.fl-card {
  fill: var(--panel-2); stroke: var(--line); stroke-width: 1.5;
  transition: fill var(--dur) var(--ease), stroke var(--dur) var(--ease),
              stroke-width var(--dur) var(--ease);
}
.fl-node text { font-family: var(--mono); }
.fl-id   { fill: var(--muted); font-size: 11.5px; font-weight: 600; }
.fl-big  { font-size: 14px; }
.fl-sub  { fill: var(--muted); font-size: 9.5px; letter-spacing: .04em; }
.fl-node.on > .fl-card { stroke: var(--accent); stroke-width: 2; fill: rgb(from var(--accent-hot) r g b / 0.1); }
.fl-node.on { filter: drop-shadow(0 1px 8px rgb(from var(--accent-hot) r g b / 0.32)); }
.fl-node.on .fl-id { fill: var(--text); }

/* --- Node internals ---------------------------------------------------------------- */
.fl-badge { fill: var(--panel); stroke: var(--line); stroke-width: 1; }
.fl-badge-t { fill: var(--muted); font-family: var(--mono); font-size: 9px; letter-spacing: .04em; }

/* One pip per process slot the node will actually run at once — its own semaphore,
   which is a different number from the `slots` the scheduler weighs it by. Both are on
   the card because conflating them is the mistake `NodeLoad { jobs, units }` exists to
   prevent. */
.fl-pip { fill: var(--panel); stroke: var(--line); stroke-width: 1; transition: fill var(--dur-fast) var(--ease); }
.fl-pip.on { fill: var(--accent-hot); stroke: var(--accent-hot); }
.fl-node.full .fl-pip.on { fill: var(--warn); stroke: var(--warn); }

.fl-bar { fill: var(--panel); stroke: var(--line); stroke-width: 1; }
/* Scaled rather than resized: a `width` attribute animates unevenly across engines, and
   the value arrives from script as a custom property, which the CSP does not police. */
.fl-bar-fill {
  fill: var(--accent); stroke: none;
  transform-box: fill-box; transform-origin: left center;
  transform: scaleX(var(--v, 0));
  transition: transform var(--dur) var(--ease);
}
.fl-queued { fill: var(--warn); }

/* Every node carries the log, so every card draws one — the leader's simply fills
   first, and the gap between its count and a follower's is the only thing on screen
   that distinguishes them. It fills, is compacted, and fills again. */
.fl-tick { fill: var(--panel); stroke: var(--line); stroke-width: 1; transition: fill var(--dur-fast) var(--ease); }
.fl-tick.on { fill: var(--accent); stroke: var(--accent); }

/* The badge is the whole of what makes a leader look different, and that is the point:
   it is a node in the placement pool like the other two, not a box in front of them. */
.fl-lead { fill: var(--accent); stroke: none; }
.fl-lead-t { fill: var(--accent-fg); font-family: var(--mono); font-size: 9.5px; font-weight: 600; }

.fl-head { fill: var(--muted); font-family: var(--mono); font-size: 10.5px; letter-spacing: .1em; text-transform: uppercase; }
.fl-axis { letter-spacing: .12em; }

/* --- Wires --------------------------------------------------------------------------
 * One arrowhead definition, placed at whichever end of the path the traffic is heading
 * for. `orient="auto-start-reverse"` is what makes a marker at the *start* point back
 * down the path, so a step whose answer travels the other way needs no second wire. */
.fl-edge {
  stroke: var(--line); stroke-width: 2; fill: none; stroke-linecap: round;
  transition: stroke var(--dur) var(--ease), stroke-width var(--dur) var(--ease);
}
.fl-edge.on { stroke: var(--accent); stroke-width: 2.5; }
/* The three peer taps overlap into one spine on purpose, so a hop between any two nodes
   is a single path rather than a relay through the one in between. Drawn lighter than a
   client's wire, because it is the cluster talking to itself. */
.fl-peer { stroke-dasharray: 7 5; }
#fl-tip path { fill: var(--line); }
#fl-tip-on path { fill: var(--accent); }
.fl-edge[data-wire] { marker-end: url(#fl-tip); }
.fl-edge[data-wire].on { marker-end: url(#fl-tip-on); }
.fl-edge[data-wire].rev { marker-end: none; marker-start: url(#fl-tip-on); }

/* Traffic on the hero's wires, which have no stepper to animate them. */
@keyframes fl-dash { to { stroke-dashoffset: -28; } }
#hero-svg .fl-edge.on { stroke-dasharray: 6 8; animation: fl-dash 1.6s linear infinite; }
/* The hero has no stepper, so every node in it is lit at once. At the stepper's
   intensity that is six glows and an all-orange diagram, which reads as an alarm rather
   than as a cluster — so it keeps the accent outline and gives up the rest. */
#hero-svg .fl-node.on { filter: drop-shadow(0 1px 5px rgb(from var(--accent-hot) r g b / 0.2)); }
#hero-svg .fl-node.on .fl-sub { fill: var(--muted); }
#hero-svg .fl-peer { opacity: .6; }

/* The hero's load bars breathe rather than being driven by a model — it is a picture,
   not a simulation, and a second simulation on the page would be one to keep in step
   with the first. The rest value is the transform below, so switching the animation off
   leaves three plausible bars rather than three empty ones. */
#hero-svg .fl-bar-fill { --v: .4; }
#hero-svg .lv-a { animation: fl-load-a 9s ease-in-out infinite; }
#hero-svg .lv-b { animation: fl-load-b 11s ease-in-out infinite; }
#hero-svg .lv-c { animation: fl-load-c 7s ease-in-out infinite; }
@keyframes fl-load-a { 0%, 100% { transform: scaleX(.22); } 50% { transform: scaleX(.54); } }
@keyframes fl-load-b { 0%, 100% { transform: scaleX(.61); } 50% { transform: scaleX(.34); } }
@keyframes fl-load-c { 0%, 100% { transform: scaleX(.40); } 50% { transform: scaleX(.78); } }

.fl-mote { fill: var(--accent-hot); }
/* Ambient traffic is small and quiet; the job the current step is about is not. */
.fl-mote.bg { fill: var(--accent-hot); opacity: .55; }
.fl-mote.hot { fill: var(--accent-hot); filter: drop-shadow(0 0 7px rgb(from var(--accent-hot) r g b / 0.9)); }

.flow-steps { list-style: none; margin: 0; padding: 0; counter-reset: s; }
.flow-steps li {
  padding: .8rem 0 .8rem 2.6rem; position: relative; color: var(--muted);
  font-size: .93rem; border-top: 1px solid var(--line); cursor: pointer;
}
.flow-steps li:first-child { border-top: 0; }
.flow-steps li::before {
  counter-increment: s; content: counter(s, decimal-leading-zero);
  position: absolute; left: 0; top: .85rem;
  font-family: var(--mono); font-size: .78rem; color: var(--muted);
}
.flow-steps li[aria-current="true"] { color: var(--text); }
.flow-steps li[aria-current="true"]::before { color: var(--accent); }
.flow-steps li code { font-size: .85em; color: var(--accent); }
.flow-controls { display: flex; gap: .5rem; flex-wrap: wrap; }

/* The steps sit on the dark band, where the ordinary --muted is a brown against
   espresso. Same idiom as .on-ridge .card: name the fallback, then the relative colour
   that browsers with it will use instead. */
.on-ridge .flow-steps li { color: var(--sand); color: rgb(from var(--cream) r g b / 0.62); border-top-color: var(--hill-1); border-top-color: rgb(from var(--cream) r g b / 0.14); }
.on-ridge .flow-steps li[aria-current="true"] { color: var(--cream); }
.on-ridge .flow-steps li::before { color: var(--sand); color: rgb(from var(--cream) r g b / 0.45); }
.on-ridge .flow-steps li[aria-current="true"]::before { color: var(--accent-hot); }
.on-ridge .flow-steps li code { color: var(--sand); }
.on-ridge .flow-steps li strong { color: var(--cream); }

/* --- Buttons on a control row (the flow stepper, the copy buttons) ------------------ */
.chip {
  font: inherit; font-family: var(--mono); font-size: .8rem; cursor: pointer;
  padding: .35rem .7rem; border-radius: 999px;
  background: var(--panel); color: var(--muted); border: 1px solid var(--line);
}
.chip:hover { color: var(--text); }
.chip[aria-pressed="true"] { background: var(--accent); color: var(--accent-fg); border-color: var(--accent); }


/* --- A section that pairs prose with a worked example -------------------------------- */
.split { display: grid; grid-template-columns: 1fr 1fr; gap: clamp(1.5rem, 4vw, 3rem); align-items: start; margin-top: 2.5rem; }
@media (max-width: 900px) { .split { grid-template-columns: 1fr; } }
.split .code:first-child { margin-top: 0; }
.split h3 { font-size: 1.02rem; margin: 1.4rem 0 .4rem; }
.split h3:first-child { margin-top: 0; }
.split p { margin: 0; color: var(--muted); font-size: .95rem; }
.split ul { margin: .6rem 0 0; padding-left: 1.1rem; color: var(--muted); font-size: .95rem; }
.split li { margin: .3rem 0; }
.split li code, .split p code { color: var(--accent); font-size: .88em; }

/* The features grid on the dark band. The cards lose their own fill and take the ridge's,
   the way .on-ridge .card does. */
.on-ridge .features { background: var(--hill-1); border-color: var(--hill-1); }
.on-ridge .feat { background: transparent; }
.on-ridge .feat p { color: var(--sand); color: rgb(from var(--cream) r g b / 0.66); }
.on-ridge .feat b { color: var(--sand); }
/* --- Code blocks --------------------------------------------------------------------- */
.code { position: relative; background: var(--panel-2); border: 1px solid var(--line); border-radius: var(--radius); margin: 1rem 0 0; }
.code pre { margin: 0; padding: 1rem 1.1rem; overflow-x: auto; font-size: .85rem; line-height: 1.65; }
.code .copy { position: absolute; top: .5rem; right: .5rem; opacity: 0; transition: opacity var(--dur-fast) var(--ease); }
.code:hover .copy, .code:focus-within .copy { opacity: 1; }
.k-cmd { color: var(--tok-cmd); font-weight: 600; }
.k-str { color: var(--tok-str); }
.k-flag { color: var(--tok-var); }
.k-com { color: var(--tok-comment); }
.k-num { color: var(--tok-num); }

.steps { display: grid; gap: 1.5rem; margin-top: 2.5rem; }
.step { display: grid; grid-template-columns: 2.5rem 1fr; gap: 1rem; align-items: start; }
.step > .n { font-family: var(--mono); font-size: .85rem; color: var(--accent); padding-top: .15rem; }
.step h3 { font-size: 1.02rem; margin-bottom: .3rem; }
.step p { margin: 0; color: var(--muted); font-size: .92rem; }

/* --- Footer ------------------------------------------------------------------------- */
footer { border-top: 1px solid var(--line); padding: 3rem 0; color: var(--muted); font-size: .88rem; }
.foot { display: flex; gap: 2rem; flex-wrap: wrap; align-items: center; }
.foot nav { display: flex; gap: 1.2rem; margin-left: auto; flex-wrap: wrap; }
.foot a { color: var(--muted); text-decoration: none; }
.foot a:hover { color: var(--accent); }
[data-repo=""] .repo-link { display: none; }

/* --- The docs page -------------------------------------------------------------------
 * The manual is one long generated document, so it gets measure and rhythm here rather
 * than any structure of its own. */
.doc { max-width: 78ch; margin: 0 auto; padding: 3rem 0 5rem; }
.doc h1 { font-size: clamp(2rem, 5vw, 2.8rem); margin: 2.5rem 0 1rem; }
.doc h2 { font-size: clamp(1.4rem, 3vw, 1.9rem); margin: 2.5rem 0 .8rem; padding-top: 1.2rem; border-top: 1px solid var(--line); max-width: none; }
.doc h3 { font-size: 1.15rem; margin: 1.8rem 0 .6rem; }
.doc h4 { font-size: 1rem; margin: 1.4rem 0 .5rem; }
.doc p, .doc li { color: var(--text); }
.doc a { overflow-wrap: anywhere; }
.doc code { background: var(--panel-2); padding: .12em .35em; border-radius: 4px; font-size: .88em; }
.doc pre { background: var(--panel-2); border: 1px solid var(--line); border-radius: var(--radius); padding: 1rem; overflow-x: auto; }
.doc pre code { background: none; padding: 0; font-size: .85rem; }
.doc blockquote { margin: 1.2rem 0; padding: .6rem 1.1rem; border-left: 3px solid var(--accent); color: var(--muted); background: var(--panel); border-radius: 0 var(--radius) var(--radius) 0; }
.doc table { width: 100%; border-collapse: collapse; margin: 1.2rem 0; font-size: .9rem; display: block; overflow-x: auto; }
.doc th, .doc td { text-align: left; padding: .5rem .7rem; border: 1px solid var(--line); }
.doc th { background: var(--panel-2); font-family: var(--mono); font-size: .8rem; }
.doc hr { border: 0; border-top: 1px solid var(--line); margin: 2.5rem 0; }
.doc img { max-width: 100%; height: auto; }

/* --- Motion --------------------------------------------------------------------------
 * Everything animated here has a legible resting state, so switching it all off costs
 * the page nothing but the atmosphere. */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
  .sun { display: none; }
}
