/* WeRtheRobots — the var-to-visual seam for every scene on the site.
 *
 * DUAL-TARGET FILE. Inlined into each Claude Design artboard and linked by every page.
 *
 * The models emit numbers; this file decides what those numbers look like. Nothing here knows
 * about time, and nothing in a model knows about appearance — which is what makes ?beat=
 * pinning, reduced motion and node-side testing all the same code path.
 *
 * NO CSS TRANSITIONS ANYWHERE. Every value already arrives eased, from the model, once per
 * frame. A transition on top would fight the timeline, lag the beat it is meant to land on,
 * and keep animating after the scene has retired — which would break the zero-rAF guarantee
 * in spirit even where it kept it in letter.
 *
 * MONOCHROME. ds/tokens/colors.css quarantines the Communication palette to campaign panels
 * and the Graphics palette to data visualisation, and its semantic aliases (--lin3s-error,
 * --lin3s-warning, --lin3s-success) ARE those same quarantined hues. So no scene uses colour:
 * weight, size and dashing carry every distinction instead.
 */

/* ---------------------------------------------------------------- the stage */
.stage { display: block; width: 100%; height: auto; overflow: visible; }
.stage text { font-family: var(--lin3s-font-body); fill: var(--lin3s-ink); }

/* ---------------------------------------------------------------- §18, the vocabulary */
/* dot — one case, task, order or customer */
.g-dot { fill: var(--lin3s-ink); }
/* a unit of value: hollow, so a hundred of them read as a shower rather than a mass */
.g-value { fill: none; stroke: var(--lin3s-ink); stroke-width: 1; }
/* a manual action */
.g-action { fill: none; stroke: var(--lin3s-ink-muted); stroke-width: 1; }
/* line — a workflow */
.g-line, .pr-rail, .cu-path, .sw-lane, .st-rail {
  fill: none; stroke: var(--lin3s-ink); stroke-width: 1.25;
}
/* square — an application or system */
.g-win__frame { fill: var(--lin3s-canvas); stroke: var(--lin3s-ink); stroke-width: 1.25; }
.g-win__bar { fill: none; stroke: var(--lin3s-ink); stroke-width: 1; }
.g-win__dot { fill: var(--lin3s-ink-muted); }
.g-win__lit { fill: var(--lin3s-ink); opacity: 0; }
.g-win__label,
.pr-step__label { font-size: 11px; letter-spacing: .06em; fill: var(--lin3s-ink-soft); }
/* diamond — a decision */
.g-diamond { fill: var(--lin3s-canvas); stroke: var(--lin3s-ink); stroke-width: 1.25; }
/* cursor — human work */
.g-cursor { fill: var(--lin3s-ink); stroke: var(--lin3s-canvas); stroke-width: 1.1; }
/* agent — an AI decision or action */
.g-agent__ring { fill: var(--lin3s-canvas); stroke: var(--lin3s-ink); stroke-width: 1.5; }
.g-agent__core { fill: var(--lin3s-ink); }
/* shield / perimeter — a guardrail. Dashed, so it never reads as another window. */
.pr-perim, .sw-perim, .st-perim {
  fill: none; stroke: var(--lin3s-ink-muted); stroke-width: 1; stroke-dasharray: 5 5;
}
/* triangle — an exception */
.g-triangle { fill: none; stroke: var(--lin3s-ink); stroke-width: 1.25; }
/* clock — waiting time */
.g-clock__face { fill: var(--lin3s-canvas); stroke: var(--lin3s-ink-muted); stroke-width: 1; }
.g-clock__tick { stroke: var(--lin3s-ink-muted); stroke-width: 1; }
.g-clock__hand { stroke: var(--lin3s-ink); stroke-width: 1.25; transform-origin: 0 0; }
/* check — a completed action */
.g-check { fill: none; stroke: var(--lin3s-ink); stroke-width: 1.6; stroke-linecap: round;
           stroke-linejoin: round; }
.g-check--strong { stroke-width: 2.2; }

/* ---------------------------------------------------------------- the process chain */
/* The workflow line draws itself: the model reveals it, CSS turns that into dash offset. */
.pr-rail, .cu-path { stroke-dashoffset: calc(var(--len) * (1 - var(--pr-line, 0))); }
.cu-path { stroke-dashoffset: calc(var(--len) * (1 - var(--cu-line, 0)));
           stroke: var(--lin3s-ink-muted); }
.pr-arrow { fill: var(--lin3s-ink); }

.pr-step__box { fill: var(--lin3s-canvas); stroke: var(--lin3s-ink); stroke-width: 1.25; }
.pr-step__lit { fill: var(--lin3s-ink); }
.pr-step__num { font-size: 9px; letter-spacing: .14em; fill: var(--lin3s-ink-muted); }
/* a step being worked: the label inverts under the fill rather than changing colour */
.pr-step__label { font-size: 10.5px; }

.pr-branch__line { fill: none; stroke: var(--lin3s-ink-muted); stroke-width: 1;
                   stroke-dasharray: 3 3; }
.pr-branch__label { font-size: 10.5px; fill: var(--lin3s-ink-muted); letter-spacing: .02em; }

.pr-gate__card { fill: var(--lin3s-canvas); stroke: var(--lin3s-ink); stroke-width: 1.25; }
.pr-gate__text { font-size: 12px; font-weight: 500; letter-spacing: .02em; }
.pr-gate__cta { font-size: 10px; letter-spacing: .14em; text-transform: uppercase;
                fill: var(--lin3s-ink-muted); }
.pr-gate__stem { fill: none; stroke: var(--lin3s-ink-muted); stroke-width: 1;
                 stroke-dasharray: 3 3; }
.pr-approve__click { fill: none; stroke: var(--lin3s-ink); stroke-width: 1; }
.pr-clock .g-clock__hand { transform: rotate(calc(var(--pr-hand, 0) * 900deg)); }

.pr-out__label { font-size: 11px; font-weight: 500; letter-spacing: .1em;
                 text-transform: uppercase; }

/* ---------------------------------------------------------------- hero: two passes, one stage */
.hero__count-text { font-size: 13px; font-weight: 500; letter-spacing: .04em;
                    fill: var(--lin3s-ink-muted); }
.cu-cursor__click { fill: none; stroke: var(--lin3s-ink); stroke-width: 1; }
.cu-cursor__carry circle { fill: var(--lin3s-ink); }
.cu-send .g-dot { fill: var(--lin3s-ink); }

/* ---------------------------------------------------------------- the data stories */
.sw-item { }
/* the subset a story is about carries weight; everything else recedes. No colour involved. */
.sw-item[data-flag="0"].g-dot { fill: var(--lin3s-ink-muted); }
.sw-item[data-flag="1"].g-dot { fill: var(--lin3s-ink); }
.sw-item[data-flag="1"].g-value { stroke: var(--lin3s-ink); }
.sw-item[data-flag="0"].g-value { stroke: var(--lin3s-ink-muted); }
.sw-lane { stroke: var(--lin3s-hairline); stroke-width: 1; }
.sw-rule { fill: none; stroke: var(--lin3s-ink-muted); stroke-width: 1; }
.sw-label { font-size: 11px; letter-spacing: .1em; text-transform: uppercase;
            fill: var(--lin3s-ink); }
.sw-label--quiet { fill: var(--lin3s-ink-muted); }
.sw-guard, .st-guard { font-size: 11.5px; letter-spacing: .02em; fill: var(--lin3s-ink-soft); }
.sw-row { font-size: 11.5px; letter-spacing: .02em; fill: var(--lin3s-ink-soft); }

/* ---------------------------------------------------------------- the technology stack */
.st-chip { fill: var(--lin3s-canvas-muted); stroke: var(--lin3s-hairline); stroke-width: 1; }
.st-sys, .st-node__box, .st-socket__box {
  fill: var(--lin3s-canvas); stroke: var(--lin3s-ink); stroke-width: 1.25;
}
.st-item__label { font-size: 10.5px; letter-spacing: .04em; fill: var(--lin3s-ink-soft); }
.st-node__label, .st-socket__label {
  font-size: 12px; font-weight: 500; letter-spacing: .16em; fill: var(--lin3s-ink);
}
.st-socket__pins { fill: none; stroke: var(--lin3s-ink); stroke-width: 1.5; }
/* the eight bespoke connections, before there is a standard one */
.st-wire { fill: none; stroke: var(--lin3s-ink-muted); stroke-width: 1;
           stroke-dasharray: 2 3; }
.st-trunk, .st-fan { fill: none; stroke: var(--lin3s-ink); stroke-width: 1.25; }
.st-fan { stroke-width: 1; }
.st-bar { fill: var(--lin3s-canvas-muted); stroke: var(--lin3s-hairline); stroke-width: 1; }
.st-bar__label, .st-note, .st-win__label {
  font-size: 11px; letter-spacing: .04em; fill: var(--lin3s-ink-muted);
}
.st-feed { fill: none; stroke: var(--lin3s-ink); stroke-width: 1; stroke-dasharray: 3 3; }
.st-win__label { letter-spacing: .14em; }

/* ---------------------------------------------------------------- the scene frame */
.scene { position: relative; }
.scene__stage { margin: 0; }
.scene__status,
.scene__action {
  font-family: var(--lin3s-font-body); font-size: 13px; letter-spacing: .01em;
  color: var(--lin3s-ink-muted); margin: 16px 0 0; min-height: 1.4em;
}
.scene__action { color: var(--lin3s-ink); font-weight: 500; }

/* ---------------------------------------------------------------- §3's BEFORE, static */
.mc-rail { fill: none; stroke: var(--lin3s-ink-muted); stroke-width: 1.25;
           stroke-dasharray: 4 4; }
.mc-hand .g-cursor { fill: var(--lin3s-ink-soft); }
.mc-dup__box { fill: var(--lin3s-canvas); stroke: var(--lin3s-ink-muted); stroke-width: 1; }
.mc-step .pr-step__box { stroke: var(--lin3s-ink-muted); }

/* ---------------------------------------------------------------- §9, the six stations */
.bd-other__line { fill: none; stroke: var(--lin3s-hairline); stroke-width: 1; }
.bd-other .g-cursor { fill: var(--lin3s-ink-muted); }
.bd-ring { fill: none; stroke: var(--lin3s-ink); stroke-width: 1.5; }
.bd-rail { fill: none; stroke: var(--lin3s-ink); stroke-width: 1.25; }
.bd-hand .g-cursor { fill: var(--lin3s-ink-soft); }
.bd-kind { font-size: 9.5px; font-weight: 500; letter-spacing: .14em;
           fill: var(--lin3s-ink); }
.bd-stem { fill: none; stroke: var(--lin3s-hairline); stroke-width: 1; }
.bd-tele { fill: none; stroke: var(--lin3s-ink-muted); stroke-width: 1;
           stroke-dasharray: 2 4; }
.bd-measure { font-size: 10px; letter-spacing: .06em; fill: var(--lin3s-ink-muted); }
.bd-lane { font-size: 9.5px; font-weight: 500; letter-spacing: .16em;
           fill: var(--lin3s-ink-muted); }
.bd-count { font-size: 12px; font-weight: 500; fill: var(--lin3s-ink); }
.bd-count--quiet { font-weight: 400; fill: var(--lin3s-ink-muted); }
/* an exception is not a failure: it is the case a person should see */
.bd-case[data-flag="1"] { fill: none; stroke: var(--lin3s-ink); stroke-width: 1.4; }
.bd-case[data-flag="0"] { fill: var(--lin3s-ink); }

/* ---------------------------------------------------------------- §14, the lineage */
.ln-edge { fill: none; stroke: var(--lin3s-hairline); stroke-width: 1; }
.ln-area { font-size: 10px; font-weight: 500; letter-spacing: .14em;
           fill: var(--lin3s-ink-muted); }
.ln-hub__ring { fill: var(--lin3s-canvas); stroke: var(--lin3s-ink); stroke-width: 1.5; }
.ln-hub__label { font-size: 12px; font-weight: 500; letter-spacing: .1em; }
.ln-out { fill: none; stroke: var(--lin3s-ink); stroke-width: 1.25; }

/* ---------------------------------------------------------------- §14, the six areas */
.nw-edge {
  fill: none; stroke: var(--lin3s-ink-muted); stroke-width: 1;
  stroke-dashoffset: calc(var(--len) * (1 - var(--e, 0)));
}
.nw-node__box { fill: var(--lin3s-canvas); stroke: var(--lin3s-ink); stroke-width: 1.25; }
.nw-node__lit { fill: var(--lin3s-ink); }
.nw-node__rail { fill: none; stroke: var(--lin3s-ink-muted); stroke-width: 1; }
.nw-node__hand .g-cursor { fill: var(--lin3s-ink-soft); }
.nw-node__label {
  font-size: 11px; font-weight: 500; letter-spacing: .14em; fill: var(--lin3s-ink);
}
/* the one case that needs all six carries a halo, so it is legible against a lit panel */
.nw-tok__halo { fill: var(--lin3s-canvas); stroke: var(--lin3s-ink); stroke-width: 1.25; }

/* ---------------------------------------------------------------- §9's depth planes
 *
 * Sticky is not parallax. Until now the pinned stage was one flat plane holding still while the text
 * slid past it; parallax is planes moving at DIFFERENT rates, which is what makes a pinned zone read
 * as having depth rather than as a picture pasted over a scrolling page.
 *
 * Every offset comes from --bd-t, the scroll variable the animation already uses, so there is no
 * second listener and nothing new measured per frame. They are transforms, so the compositor does
 * the work.
 *
 * The amounts are deliberately small. Parallax that announces itself is a distraction from a diagram
 * whose whole job is to be read; 22px across the entire section is enough to separate the planes and
 * not enough to notice as an effect.
 */
.stage--build [data-plane="far"] {
  transform: translateY(calc(var(--bd-t, 0) * -22px));
}
.stage--build [data-plane="near"] {
  transform: translateY(calc(var(--bd-t, 0) * 12px));
}
/* NEVER PUT A CSS TRANSFORM ON AN ELEMENT paint.js POSITIONS.
 *
 * A CSS `transform` OVERRIDES an SVG `transform` attribute — CSS wins over presentation attributes.
 * Tagging the individual case dots as a depth plane and giving them `transform: none` therefore
 * collapsed all of them onto the origin while they still carried perfectly correct attributes:
 * measured, ten dots at one screen position. Nothing threw, and the suite passed.
 *
 * So the plane offset goes on the GROUP, which paint.js never touches, and it composes with the
 * children's own attributes instead of replacing them. tools/verify.mjs now asserts that every
 * item's rendered position matches the attribute it was given. */
.stage--build .bd-cases { transform: translateY(calc(var(--bd-t, 0) * 12px)); }

/* The depth planes are motion, so reduced motion flattens them. Spelled out per selector rather
 * than relying on `[data-plane]` alone: a media query adds no specificity, and the group rule above
 * is more specific, so a single blanket override silently lost to it. */
@media (prefers-reduced-motion: reduce) {
  .stage--build [data-plane="far"],
  .stage--build [data-plane="near"],
  .stage--build .bd-cases { transform: none; }
}
