/* gfx.css: the figure component of the "How I work" page. Tokens only.
   The markup it styles is fixed in m2/how/FIG-CONTRACT.md. The shared component comes first; each diagram's own block
   (grid tracks, stage min-heights, anything only that diagram needs) sits between its "@fig D-NN start" and "@fig D-NN end"
   markers at the end, and only that diagram's author edits it (m2/how/tools/merge-figs.cjs replaces it from m2/how/figs/D-NN.css).
   Wide = a figure (the container) 720 px or wider; narrow = under 720 px. Fixed tracks of STANDARD's table are written as fr
   proportions that give its px values at the 1216 px design width with a --space-3 gap, so no grid overflows between 720 and 1216. */

/* the figure; the placement hooks do not inherit, so a nested grid never picks up its parent's placement */
@property --col { syntax: "*"; inherits: false; }
@property --row { syntax: "*"; inherits: false; }
@property --ncol { syntax: "*"; inherits: false; }
@property --nrow { syntax: "*"; inherits: false; }
figure.gfx { container-type: inline-size; margin: 0; width: 100%; }

/* the control row: in the HTML from the first paint, so nothing shifts; the buttons carry hidden until player.js reveals them */
.gfx-controls { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); min-height: var(--control-h); margin-bottom: var(--space-3); }
.gfx-btn { display: inline-flex; align-items: center; gap: var(--space-1); min-width: var(--control-h); min-height: var(--control-h); padding: 0 var(--control-pad); font: inherit; font-size: var(--size-graphic); line-height: var(--leading-snug); color: var(--ink); background: var(--paper); border: var(--line) solid var(--rule); border-radius: var(--radius); cursor: pointer; transition: background-color var(--dur-ui) var(--ease), border-color var(--dur-ui) var(--ease), color var(--dur-ui) var(--ease), transform var(--dur-press) var(--ease); }
.gfx-btn[hidden] { display: none; }
.gfx-btn[data-act="pause"] { min-width: calc(var(--control-h) * 2); } /* LOCAL: one width for "Pause" and "Play", so the label swap at the end of a sequence shifts nothing (CLS 0) */
.gfx-btn svg { width: 1em; height: 1em; flex: none; fill: currentColor; }
.gfx-btn:focus-visible { outline: var(--focus); outline-offset: var(--focus-offset); }
.gfx-btn:active { background: var(--paper-2); transform: translateY(1px); }
.gfx-btn[aria-pressed="true"] { background: var(--ink); color: var(--paper); border-color: var(--ink); }
.gfx-btn[aria-pressed="true"] .i-pause, .gfx-btn:not([aria-pressed="true"]) .i-play { display: none; }
.gfx-still { display: none; align-items: center; min-height: var(--control-h); font-size: var(--size-graphic); color: var(--ink-3); }

/* the stage: the edge layers behind, the node grid over them, the token on top, the cards above all */
.gfx-stage { position: relative; }
.gfx-stage > svg.edges { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; overflow: visible; }
svg.edges.wide { display: none; }
svg.edges.narrow { display: block; }

/* the node grid (narrow first: one column) and the placement hooks: a node's inline --ncol/--nrow (narrow) and --col/--row (wide) */
.gfx .nodes { position: relative; display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--space-3); margin: 0; padding: 0; list-style: none; }
.gfx .nodes > * { grid-column: var(--ncol, auto); grid-row: var(--nrow, auto); }

/* a node: li.node > button.node-btn (label, optional b, optional span.node-sub) + div.card; the role class on the li colours the border */
.gfx .node { position: relative; min-width: 0; }
.gfx .node-btn { display: block; width: 100%; min-height: var(--control-h); padding: var(--space-2) var(--control-pad); font: inherit; font-size: var(--size-graphic); line-height: var(--leading-snug); font-weight: var(--weight-mid); text-align: left; color: var(--ink); background: var(--paper); border: var(--line) solid var(--rule-strong); border-radius: var(--radius); cursor: pointer; transition: color var(--dur-ui) var(--ease), background-color var(--dur-ui) var(--ease), border-color var(--dur-ui) var(--ease), transform var(--dur-press) var(--ease), opacity var(--gfx-move, var(--dur-step)) var(--ease); }
.gfx .node-btn { overflow-wrap: break-word; } /* LOCAL: a word longer than its column breaks instead of spilling out of the node (D-12 "cancellations," at 752-784 px) */
.gfx .node-btn b { font-weight: var(--weight-strong); font-variant-numeric: tabular-nums; }
.gfx .node-sub { display: block; font-weight: var(--weight-body); color: inherit; }
.gfx .node.before > .node-btn { border: var(--line-strong) solid var(--contrast); }
.gfx .node.process > .node-btn { border: var(--line-strong) solid var(--process); }
.gfx .node.after > .node-btn { border: var(--line-strong) solid var(--accent); }
.gfx .node-btn:focus-visible { outline: var(--focus); outline-offset: var(--focus-offset); }
.gfx .node-btn:active { background: var(--paper-2); transform: translateY(1px); }
/* r2: the open state names .node so it outranks the role borders above (an open role-coloured node showed no change) */
.gfx .node > .node-btn[aria-expanded="true"] { background: var(--paper-2); border-color: var(--accent); }

/* lit and unlit (steps mode): player.js adds gfx-armed, then is-on step by step; the button dims, not the li, so an open card stays full strength */
/* an unlit node keeps full opacity (0.38 painted 1.95:1, and 0.89, the first value that passed, showed no change);
   its border stays solid but goes to --rule and its text to --ink-3 (5.4:1 light, 6.4:1 dark), so the step is seen and the text keeps 4.5:1.
   Dashed is kept for meaning only (moved by a decision, parked, rollback), never for "not yet". An unlit chart dot (wide) is a
   hollow ring in its own colour: see the 720 px block. Lit, the role border, the ink and the filled dot return. Screen only: print shows every step lit. */
@media screen {
  .gfx-armed .node:not(.is-on) > .node-btn { opacity: 1; border-color: var(--rule); color: var(--ink-3); }
  .gfx-armed .node:not(.is-on) > .node-btn[aria-expanded="true"] { border-color: var(--accent); }
}
.gfx-armed .reveal:not(.is-on) { opacity: 0; }
.gfx:not(.gfx-armed) .node > .node-btn, .gfx:not(.gfx-armed) .reveal { opacity: 1; }
.gfx .reveal { transition: opacity var(--gfx-move, var(--dur-step)) var(--ease); }

/* the token (D-01, D-04, D-05): an HTML dot the script moves onto a node by transform; never shown without the script */
.gfx .token { position: absolute; left: 0; top: 0; z-index: 2; width: calc(var(--space-2) + var(--line-strong)); height: calc(var(--space-2) + var(--line-strong)); border-radius: var(--radius-pin); background: var(--accent); pointer-events: none; opacity: 0; transition: transform var(--gfx-move, var(--dur-step)) var(--ease), opacity var(--dur-ui) var(--ease); }
.gfx .token.process { background: var(--process); }
.gfx .token.is-on { opacity: 1; }

/* labels that are not nodes: axis words, lane names, column heads; tick numerals only at --size-6 */
.gfx .label { font-size: var(--size-graphic); line-height: var(--leading-snug); color: var(--ink-2); }
.gfx .tick { font-size: var(--size-graphic); color: var(--ink-3); font-variant-numeric: tabular-nums; }
.gfx svg text { font-size: var(--size-graphic); fill: var(--ink-2); font-variant-numeric: tabular-nums; }
.gfx svg text.tick { font-size: var(--size-graphic); fill: var(--ink-3); }

/* charts with node buttons over them (D-05 scatter, D-08 burn-down): div.plot > svg[role=img] + ol.nodes. Narrow: the chart is
   not drawn and the nodes are an ordinary list. Wide: the chart shows and each li.node sits at its inline --x/--y (percent of
   the plot box; placed, never animated), its button a dot with a 44 px hit area by ::after and its label in span.wide-sr */
.gfx .plot { position: relative; }
.gfx .plot > svg { display: none; }

/* the card (STANDARD section 4): a popover at a wide container, display none at a narrow one (the card area serves there) */
.gfx .card { display: none; }
.gfx .card-title { font-size: var(--size-4); line-height: var(--leading-snug); font-weight: var(--weight-strong); color: var(--ink); }
.gfx .card-text { margin-top: var(--space-1); font-size: var(--size-4); line-height: var(--leading-body); font-weight: var(--weight-body); color: var(--ink-2); }

/* the card area (narrow only): the caption's text at rest, the open card's title and text when one opens */
.gfx .card-area { margin-top: var(--space-3); min-height: calc(4 * var(--size-4) * var(--leading-body) + 2 * var(--space-3)); padding: var(--space-3) 0; border-top: var(--line) solid var(--rule); font-size: var(--size-4); line-height: var(--leading-body); color: var(--ink-3); }
.gfx .card-area.is-card { color: var(--ink-2); }
/* r2: under 720 px the tapped, focused or hovered node's own card opens under its button, over the nodes below it: the li gives up
   its position so the card takes the node list's width and stays at its place in the flow (top: auto), and nothing moves, so the
   routed edges and the token stay true. The card area stays only as the live region, visually hidden (never display none). */
@container (width < 720px) {
  .gfx .node { position: static; }
  .gfx .node-btn[aria-expanded="true"] ~ .card, .gfx .node-btn:focus-visible ~ .card { display: block; position: absolute; left: 0; right: 0; z-index: 3; margin-top: var(--space-1); padding: var(--space-3); text-align: left; background: var(--paper); border: var(--line) solid var(--rule); border-radius: var(--radius); box-shadow: var(--shadow-1); }
  .gfx .card-area { position: absolute; width: var(--line); height: var(--line); min-height: 0; margin: calc(var(--line) * -1); padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
}

/* the steps list and the caption */
.gfx ol.steps { margin: var(--space-3) 0 0; padding: 0 0 0 var(--space-4); list-style: decimal; font-size: var(--size-4); line-height: var(--leading-body); color: var(--ink-2); }
.gfx ol.steps > li + li { margin-top: var(--space-1); }
/* the current step gains weight by a paint-only stroke, not font-weight, so its line never rewraps and the text below never jumps */
.gfx ol.steps > li[aria-current="step"] { color: var(--ink); -webkit-text-stroke: 0.025em currentColor; }
.gfx figcaption { margin-top: var(--space-2); font-size: var(--size-4); line-height: var(--leading-body); color: var(--ink-3); max-width: var(--measure-text); }

/* edges, arrowheads (markers holding path.arrow) and flow dots, in the edge layers */
.gfx .edge { fill: none; stroke: var(--ink-3); stroke-width: var(--line-strong); stroke-linejoin: round; }
.gfx .edge.process { stroke: var(--process); }
.gfx .edge.before { stroke: var(--contrast); }
.gfx .edge.after { stroke: var(--accent); }
.gfx .edge.dashed { stroke-dasharray: 4 4; }
.gfx .arrow { fill: var(--ink-3); }
.gfx .arrow.process { fill: var(--process); }
.gfx .arrow.before { fill: var(--contrast); }
.gfx .arrow.after { fill: var(--accent); }
.gfx .dot { fill: var(--process); offset-rotate: 0deg; offset-distance: 0%; animation: gfx-flow var(--d, var(--flow-cycle)) linear var(--dl, calc(var(--flow-cycle) * 0)) infinite; }
.gfx .dot.after { fill: var(--accent); }
.gfx.is-paused .dot, .gfx.is-out .dot { animation-play-state: paused; }
/* each dot fades in at the start of its edge and out at the end, so the loop never pops back */
@keyframes gfx-flow { 0% { offset-distance: 0%; opacity: 0; } 12% { opacity: 1; } 88% { opacity: 1; } 100% { offset-distance: 100%; opacity: 0; } }

/* utilities: wide-only, narrow-only, and the text equivalent that is visually hidden at a wide container (never display none) */
.visually-hidden { position: absolute; width: var(--line); height: var(--line); margin: calc(var(--line) * -1); padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
.gfx .wide-only { display: none; }

/* the wide layout (a 720 px container): edge layer swap, the card as a popover, the placement hooks */
@container (min-width: 720px) {
  svg.edges.wide { display: block; }
  svg.edges.narrow { display: none; }
  .gfx .nodes > * { grid-column: var(--col, auto); grid-row: var(--row, auto); }
  .gfx .wide-only { display: block; }
  .gfx .narrow-only { display: none; }
  .gfx .wide-sr { position: absolute; width: var(--line); height: var(--line); margin: calc(var(--line) * -1); padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
  .gfx .card-area { display: none; }
  .gfx .card { display: block; position: absolute; top: calc(100% + var(--space-1)); left: 0; z-index: 3; width: 18rem; max-width: calc(100cqw - 2 * var(--gutter)); padding: var(--space-3); text-align: left; background: var(--paper); border: var(--line) solid var(--rule); border-radius: var(--radius); box-shadow: var(--shadow-1); opacity: 0; transform: translateY(var(--space-1)); visibility: hidden; transition: opacity var(--dur-ui) var(--ease), transform var(--dur-ui) var(--ease), visibility var(--dur-ui) linear; }
  .gfx .card::before { content: ""; position: absolute; left: 0; right: 0; bottom: 100%; height: calc(var(--space-1) + var(--line)); }
  .gfx .node[data-align="end"] > .card { left: auto; right: 0; }
  .gfx .plot > svg { display: block; width: 100%; height: auto; }
  .gfx .plot > .nodes { position: absolute; inset: 0; display: block; }
  .gfx .plot .node { position: absolute; left: var(--x); top: var(--y); translate: -50% -50%; }
  .gfx .plot .dot-btn { position: relative; width: var(--space-3); min-width: 0; height: var(--space-3); min-height: 0; padding: 0; border-radius: var(--radius-pin); }
  .gfx .plot .dot-btn::after { content: ""; position: absolute; left: 50%; top: 50%; width: var(--control-h); height: var(--control-h); translate: -50% -50%; }
  /* an unlit chart dot is a hollow ring in its own colour, a paper fill inside a 2 px border; the fill fades back with the
     button's background-color transition. Screen only: print shows every step lit. A .hit node (D-05) hollows its ::before instead. */
  @media screen { .gfx-armed.gfx .plot .node:not(.is-on):not(.hit) > .dot-btn { background-color: var(--paper); border-width: var(--line-strong); border-style: solid; } }
  .gfx .node-btn:focus-visible ~ .card, .gfx .node-btn[aria-expanded="true"] ~ .card { opacity: 1; transform: none; visibility: visible; }
}
@media (hover: hover) {
  .gfx .node-btn:hover, .gfx-armed .node:not(.is-on) > .node-btn:hover { border-color: var(--accent); color: var(--accent); }
  .gfx-btn:hover { border-color: var(--rule-strong); background: var(--paper-2); }
  .gfx-btn[aria-pressed="true"]:hover { background: var(--ink); border-color: var(--ink); }
  .gfx .node:hover > .card { opacity: 1; transform: none; visibility: visible; } /* (WCAG 1.4.13): the li is the hover box, so the pointer crosses from the button to its card without a gap; was `.node-btn:hover ~ .card, .card:hover` */
  @container (width < 720px) { .gfx .node:hover > .card { display: block; position: absolute; left: 0; right: 0; z-index: 3; margin-top: var(--space-1); padding: var(--space-3); text-align: left; background: var(--paper); border: var(--line) solid var(--rule); border-radius: var(--radius); box-shadow: var(--shadow-1); } }
}
/* Escape closes a hovered or focused card until the pointer or focus leaves (cards.js); last, so it wins */
.gfx .node-btn.is-dismissed ~ .card { opacity: 0; transform: translateY(var(--space-1)); visibility: hidden; }

/* the still state: reduced motion (scripts never arm or create dots), and print */
@media (prefers-reduced-motion: reduce) {
  .gfx .gfx-still { display: inline-flex; }
  .gfx .gfx-btn { display: none; }
  .gfx .node > .node-btn, .gfx .reveal { opacity: 1; }
  .gfx .dot { display: none; }
  .gfx .node-btn, .gfx .reveal, .gfx .card, .gfx .token { transition: none; }
}
@media print {
  .gfx-controls, .gfx .dot, .gfx .card-area { display: none; }
  .gfx-armed .node:not(.is-on) > .node-btn, .gfx-armed .reveal:not(.is-on) { opacity: 1; }
}

/* forced colours: marks in CanvasText, the result and the token in LinkText, no dimming */
@media (forced-colors: active) {
  .gfx .node > .node-btn, .gfx .node.before > .node-btn, .gfx .node.process > .node-btn { border-color: CanvasText; }
  .gfx .node.after > .node-btn, .gfx .node > .node-btn[aria-expanded="true"] { border-color: LinkText; }
  .gfx-armed .node:not(.is-on) > .node-btn, .gfx-armed .reveal:not(.is-on) { opacity: 1; }
  .gfx-armed.gfx .plot .node:not(.is-on):not(.hit) > .dot-btn { background-color: Canvas; }
  .gfx .edge, .gfx .edge.process, .gfx .edge.before { stroke: CanvasText; }
  .gfx .edge.after { stroke: LinkText; }
  .gfx .arrow, .gfx .arrow.process, .gfx .arrow.before { fill: CanvasText; }
  .gfx .arrow.after, .gfx .dot { fill: LinkText; }
  .gfx .token { forced-color-adjust: none; background: LinkText; }
  .gfx .card { border-color: CanvasText; }
}

/* ===== the thirteen diagrams: grids and stage min-heights of STANDARD section 3 (narrow, then wide) ===== */

/* @fig D-01 start: the stage line (steps) */
/* @fig D-01: the stage line (steps). Narrow: one column, the return up the left lane. Wide: eight columns, the arc in row 3. */
.gfx[data-d="01"] .gfx-stage { min-height: 533px; }
.gfx[data-d="01"] .nodes { gap: var(--space-2); padding-left: var(--space-4); }
.gfx[data-d="01"] :is(#D01-l-loop, #D01-l-loop-ns) { padding-left: var(--space-2); }
/* the token stops on a span pinned to each node's left edge, so it never covers a word */
.gfx[data-d="01"] .node-btn { position: relative; }
.gfx[data-d="01"] .spot { position: absolute; left: 0; top: 50%; width: calc(var(--space-2) + var(--line-strong)); height: calc(var(--space-2) + var(--line-strong)); translate: -50% -50%; }
/* the return arc stands at rest as a hairline in --rule (decoration), so its row reads as a slot; step 8 draws the accent arc over it */
.gfx[data-d="01"] .edge.rest { stroke: var(--rule); stroke-width: var(--line); }
/* the arc's name stands at rest in ink-3 under the hairline, so the row reads as a named slot; step 8 brings it to ink-2 as the accent arc fades in */
.gfx[data-d="01"] :is(#D01-l-loop, #D01-l-loop-ns) { transition: color var(--dur-ui) var(--ease); }
.gfx-armed.gfx[data-d="01"] :is(#D01-l-loop, #D01-l-loop-ns):not(.is-on) { opacity: 1; color: var(--ink-3); }
.gfx-snap.gfx[data-d="01"] :is(#D01-l-loop, #D01-l-loop-ns) { transition: none; }
@container (min-width: 720px) {
  .gfx[data-d="01"] .gfx-stage { min-height: 196px; }
  .gfx[data-d="01"] .nodes { grid-template-columns: repeat(8, minmax(0, 1fr)); grid-template-rows: 44px auto 56px; gap: var(--space-3) var(--space-4); padding-left: 0; }
  .gfx[data-d="01"] :is(#D01-l-loop, #D01-l-loop-ns) { align-self: end; justify-self: center; padding-left: 0; }
}
@media (forced-colors: active) {
  .gfx[data-d="01"] .edge.rest { stroke: GrayText; }
}
/* @fig D-01 end */

/* @fig D-02 start: the voice of the customer (flow) */
/* @fig D-02: the voice of the customer (flow). Narrow: one column, the return up the left lane, the two inputs into
   Opportunity from the right lane. Wide: the ring of STANDARD section 3, five columns by three rows. */
.gfx[data-d="02"] .gfx-stage { min-height: 600px; }
.gfx[data-d="02"] .nodes { gap: var(--space-3); padding-left: var(--space-4); padding-right: var(--space-5); }
@container (min-width: 720px) {
  .gfx[data-d="02"] .gfx-stage { min-height: 300px; }
  .gfx[data-d="02"] .nodes { grid-template-columns: repeat(5, minmax(0, 1fr)); grid-template-rows: repeat(3, auto); gap: var(--space-5) var(--space-5); padding-left: 0; padding-right: 0; }
}
/* @fig D-02 end */

/* @fig D-03 start: the door matrix (still; no edges) */
/* @fig D-03: the door matrix (still; no edges). Narrow: each row head, then its two answers; then each door head over
   its decision dots; then the record. Wide: the 3-column matrix, the dots row, the record under the one-way column. */
.gfx[data-d="03"] .gfx-stage { min-height: 788px; }
.gfx[data-d="03"] .nodes { gap: var(--space-2); }
.gfx[data-d="03"] .cell { padding-left: var(--control-pad); }
.gfx[data-d="03"] .dots { padding: 0 0 var(--space-2) var(--control-pad); }
.gfx[data-d="03"] .dots ul { display: flex; flex-wrap: wrap; gap: var(--space-1) var(--space-3); margin: 0; padding: 0; list-style: none; }
.gfx[data-d="03"] .dots li { display: inline-flex; align-items: center; gap: var(--space-1); }
.gfx[data-d="03"] .dots li::before { content: ""; flex: none; width: var(--space-2); height: var(--space-2); border-radius: var(--radius-pin); background: var(--ink-3); }
.gfx[data-d="03"] .dots li.esc::before { background: var(--contrast); }
@media (forced-colors: active) {
  .gfx[data-d="03"] .dots li::before { forced-color-adjust: none; background: CanvasText; }
  .gfx[data-d="03"] .dots li.esc::before { background: LinkText; }
}
@container (min-width: 720px) {
  .gfx[data-d="03"] .gfx-stage { min-height: 436px; }
  .gfx[data-d="03"] .nodes { grid-template-columns: minmax(0, 50fr) repeat(2, minmax(0, 123fr)); grid-template-rows: auto repeat(4, auto) auto auto; gap: var(--space-3) var(--space-4); }
  .gfx[data-d="03"] .cell { align-self: center; padding-left: var(--control-pad); }
  .gfx[data-d="03"] .dots { padding: 0 0 0 var(--control-pad); }
}
/* @fig D-03 end */

/* @fig D-04 start: the AI test (steps) */
/* @fig D-04: the AI test (steps). Narrow: one column placed row by row (--nrow): the "no" lane on the right into the rule
   node, "no" beside it after gate 1; the "yes" lane on the left into the AI node, "yes" beside it under the reply label; the
   life cycle under the rule, its edge straight down. Wide: token labels, the gates column, the outcomes, the life cycle at the
   far right fed from the rule; "no" beside the bus, "yes" under the yes edge's bottom run.
   Token spots: each token starts on an empty span before its label's word and stops on a span 6 px inside the left edge of a
   node, so it never covers a word or an arrowhead; a token label fades when its token reaches its outcome (and in the still). */
.gfx[data-d="04"] .gfx-stage { min-height: 640px; }
.gfx[data-d="04"] .nodes { gap: var(--space-3); padding: 0 var(--space-4); }
.gfx[data-d="04"] .spot { display: inline-block; width: calc(var(--space-2) + var(--line-strong)); height: calc(var(--space-2) + var(--line-strong)); vertical-align: middle; }
.gfx[data-d="04"] .tok { padding-left: var(--control-pad); }
.gfx[data-d="04"] .tok .spot { margin-right: var(--space-2); }
.gfx[data-d="04"] .node-btn { position: relative; }
/* the token runs the decision path past "yes" and "no" (375, step 1->2, about 80 ms); the words stay on paper above it */
.gfx[data-d="04"] .label:is([id$="-yes"], [id$="-no"]) { position: relative; z-index: 3; background: var(--paper); }
/* D-04 nodes take a role mid-loop; the role edge is the 1 px border plus a 1 px ring that inherits the border colour in every
   state (unlit, hover, open), so the node repaints without growing (it grew 2 px a loop at 768) */
.gfx[data-d="04"] .node:is(.before, .process, .after) > .node-btn { border-width: var(--line); }
.gfx[data-d="04"] .node:is(.before, .process, .after) > .node-btn::after { content: ""; position: absolute; inset: 0; border: calc(var(--line-strong) - var(--line)) solid; border-color: inherit; border-radius: calc(var(--radius) - var(--line)); pointer-events: none; }
.gfx[data-d="04"] .node-btn .spot { position: absolute; left: calc(var(--space-2) - var(--line-strong)); top: 50%; translate: -50% -50%; }
.gfx[data-d="04"] .tok { transition: opacity var(--gfx-move, var(--dur-step)) var(--ease); }
.gfx[data-d="04"] .tok.is-gone { opacity: 0; }
.gfx[data-d="04"] :is(#D04-l-no, #D04-l-no-ns) { justify-self: end; margin-right: calc(-1 * var(--space-2)); }
.gfx[data-d="04"] :is(#D04-l-yes, #D04-l-yes-ns) { justify-self: start; margin-left: calc(-1 * var(--space-1)); }
@container (min-width: 720px) {
  .gfx[data-d="04"] .gfx-stage { min-height: 360px; }
  .gfx[data-d="04"] .nodes { grid-template-columns: max-content 320px minmax(0, 3fr) minmax(0, 2fr); grid-template-rows: repeat(5, auto); gap: var(--space-4) var(--space-5); padding: 0; }
  .gfx[data-d="04"] .tok { align-self: center; justify-self: end; padding-left: 0; }
  /* "no" sits beside the bus between gates 1 and 2; "yes" under the yes edge's bottom run (y = 336 at 1216) */
  .gfx[data-d="04"] :is(#D04-l-no, #D04-l-no-ns), .gfx[data-d="04"] :is(#D04-l-yes, #D04-l-yes-ns) { align-self: end; justify-self: start; margin-right: 0; }
  .gfx[data-d="04"] :is(#D04-l-no, #D04-l-no-ns) { margin-left: calc(var(--line-strong) - var(--space-3)); translate: 0 var(--space-4); }
  .gfx[data-d="04"] :is(#D04-l-yes, #D04-l-yes-ns) { margin-left: var(--space-2); translate: 0 calc(var(--space-5) + var(--line-strong)); }
  .gfx[data-d="04"] :is(#D04-8, #D04-8-ns) { align-self: center; }
}
/* @fig D-04 end */

/* @fig D-05 start: the score, the bands and the roadmap (steps) */
/* @fig D-05: the score, the bands and the roadmap (steps). Narrow: the factors 2 x 2, the ranked list (band heads, then their features), then the roadmap lanes. Wide: the factors across the top; the gate legend over the scatter (dots and labelled markers over the chart svg) and the roadmap stacked, side by side from a 1000 px container. */
.gfx[data-d="05"] .gfx-stage { display: grid; grid-template-columns: minmax(0, 1fr); row-gap: var(--space-4); align-items: start; align-content: start; min-height: 1280px; }
.gfx[data-d="05"] .factors { grid-template-columns: repeat(2, minmax(0, 1fr)); grid-auto-rows: 1fr; gap: var(--space-2); }
.gfx[data-d="05"] .factors > .node > .node-btn { height: 100%; }
.gfx[data-d="05"] .ranked { gap: var(--space-1); }
.gfx[data-d="05"] .ranked > .band ~ .band { margin-top: var(--space-2); }
/* r2: below 720 px the four band heads are group labels over their rows (THINK D-05: "P0 · 35 to 50 or a gate"), not node boxes;
   the role colour stays on the feature rows. Still buttons for their cards: hover, focus and the open state show as for any node */
@container (width < 720px) {
  .gfx[data-d="05"] .ranked > .band > .node-btn { padding: var(--space-3) var(--control-pad) var(--space-1); border: var(--line) solid transparent; background: none; font-weight: var(--weight-strong); }
  .gfx[data-d="05"] .ranked > .band > .node-btn[aria-expanded="true"] { background: var(--paper-2); border-color: var(--accent); }
}
/* the gate legend and the effort axis title belong to the chart; the narrow list has no axes, so they wait for the wide form */
.gfx[data-d="05"] .ranked > .legend, .gfx[data-d="05"] .ranked > .axis-title { display: none; }
.gfx[data-d="05"] .token.pre { opacity: 0; }
/* the token starts on F4's dot: span.at marks it (the row centre narrow, the dot wide), since F4's button reaches past its dot */
.gfx[data-d="05"] .ranked > .node:has(> .at) { position: relative; }
.gfx[data-d="05"] .ranked > .node > .at { position: absolute; left: 50%; top: 50%; }
/* the plot svg: axis, band lines, gate rings; the feature labels carry a paper halo so a band line passes behind them */
.gfx[data-d="05"] .plot .axis { fill: none; stroke: var(--rule-strong); stroke-width: var(--line); }
.gfx[data-d="05"] .plot .band-line { fill: none; stroke: var(--rule-strong); stroke-width: var(--line); stroke-dasharray: 4 4; }
.gfx[data-d="05"] .plot .ring { fill: none; stroke: var(--contrast); stroke-width: var(--line-strong); }
.gfx[data-d="05"] .plot :is(#D05-flabels, #D05-flabels-ns) text { paint-order: stroke; stroke: var(--paper); stroke-width: calc(var(--line-strong) * 2); stroke-linejoin: round; }
/* the roadmap: milestone row, then four lanes of chips */
.gfx[data-d="05"] .roadmap { gap: 0; }
.gfx[data-d="05"] .miles { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-1) var(--space-3); padding-bottom: var(--space-2); }
.gfx[data-d="05"] .miles > span { display: block; }
.gfx[data-d="05"] .miles b { color: var(--ink); font-weight: var(--weight-strong); font-variant-numeric: tabular-nums; transition: color var(--dur-ui) var(--ease); }
/* the travelling token passes under the milestone numbers (narrow, step 4 to 5), so a number it crosses stays on paper and readable */
.gfx[data-d="05"] .miles b { position: relative; z-index: 3; background: var(--paper); }
.gfx[data-d="05"] .lane { display: grid; grid-template-columns: minmax(0, 2fr) minmax(0, 3fr); column-gap: var(--space-2); align-items: center; min-height: var(--control-h); padding: var(--space-1) 0; border-top: var(--line) solid var(--rule); }
.gfx[data-d="05"] .lane-name { font-weight: var(--weight-mid); color: var(--ink); transition: color var(--dur-ui) var(--ease); }
/* the roadmap frame (lane names, rules, milestone numbers) stands at rest in ink-3, so its slot reads as a slot before steps 5 and 6; only the chips and the milestone names are reveals */
.gfx-armed.gfx[data-d="05"] .lane:has(> .chips:not(.is-on)) > .lane-name, .gfx-armed.gfx[data-d="05"] .miles > span:has(> .reveal:not(.is-on)) > b { color: var(--ink-3); }
/* the start state is painted without transitions (player.js arm), so these colour fades wait for a step */
.gfx-snap.gfx[data-d="05"] .lane-name, .gfx-snap.gfx[data-d="05"] .miles b, .gfx-snap.gfx[data-d="05"] .plot .dot-btn::before { transition: none; }
.gfx[data-d="05"] .chips { display: flex; flex-wrap: wrap; gap: var(--space-1); }
.gfx[data-d="05"] .chip { display: inline-flex; align-items: center; gap: var(--space-1); padding: var(--space-1) var(--space-2); color: var(--ink); border: var(--line) solid var(--rule-strong); font-variant-numeric: tabular-nums; }
.gfx[data-d="05"] .p0 .chip { border: var(--line-strong) solid var(--accent); }
.gfx[data-d="05"] .p0 .chip.moved { border-style: dashed; }
.gfx[data-d="05"] .nh .chip { border-style: dashed; color: var(--ink-2); }
.gfx[data-d="05"] .pin { display: inline-block; flex: none; box-sizing: border-box; width: calc(var(--space-2) + var(--line-strong)); height: calc(var(--space-2) + var(--line-strong)); border: var(--line) solid var(--accent); border-radius: var(--radius-pin); }
@container (min-width: 720px) {
  .gfx[data-d="05"] .gfx-stage { min-height: 420px; row-gap: var(--space-3); }
  .gfx[data-d="05"] .factors { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--space-3); }
  .gfx[data-d="05"] .ranked > .band ~ .band { margin-top: 0; }
  /* the gate legend stands above the plot, outside the chart area; the effort axis title is plain text like "score" (still a button for its card) */
  .gfx[data-d="05"] .plot { margin-top: var(--control-h); }
  .gfx[data-d="05"] .plot .ranked > .legend { display: block; top: auto; bottom: 100%; left: 0; translate: none; }
  .gfx[data-d="05"] .plot .ranked > .axis-title { display: block; }
  .gfx[data-d="05"] .plot .axis-title > .node-btn { font-weight: var(--weight-body); }
  .gfx[data-d="05"] .plot .axis-title > .node-btn:not(:hover):not(:focus-visible):not([aria-expanded="true"]) { border-color: transparent; background: transparent; color: var(--ink-2); }
  /* dots: neutral in ink-3, the P0 features in the accent; markers keep their labels on one line */
  /* the 44 px ::after hit area takes the node as its box, so it does not count as button overflow */
  .gfx[data-d="05"] .plot .dot-btn { position: static; display: block; }
  /* (WCAG 2.5.8): every dot button is a transparent 24 x 24 box with the 16 px dot drawn by ::before at its
     centre. F3 over F2, F4 over F7 and F10 beside F5 sit under 24 px apart, so each of those is a 24 x 28 box (F10 28 x 24)
     reaching away from its neighbour, the dot at the end that marks the point; the node is shifted so the dot keeps its place,
     and the 44 px ::after stays offset away from the neighbour */
  .gfx[data-d="05"] .plot .ranked > .node { --d05-dot: var(--ink-3); }
  .gfx[data-d="05"] .plot .ranked > .node.after { --d05-dot: var(--accent); }
  .gfx[data-d="05"] .plot .ranked > .node > .dot-btn { width: var(--space-4); height: var(--space-4); background: transparent; border-color: transparent; }
  .gfx-armed.gfx[data-d="05"] .plot .ranked > .node:not(.is-on) > .dot-btn { background: transparent; border-width: var(--line); }
  .gfx[data-d="05"] .plot .ranked > .node.hit > .dot-btn { width: var(--space-4); height: calc(var(--space-4) + var(--space-1)); background: transparent; border-color: transparent; }
  .gfx[data-d="05"] .plot .ranked > .node.hit.hit-right > .dot-btn { width: calc(var(--space-4) + var(--space-1)); height: var(--space-4); background: transparent; border-color: transparent; }
  .gfx[data-d="05"] .plot .ranked > .node:has(> .at) { position: absolute; }
  .gfx[data-d="05"] .plot .ranked > .node.hit-up > .at { top: auto; bottom: var(--space-2); }
  .gfx[data-d="05"] .plot .ranked > .node.hit-up { translate: -50% calc(-100% + var(--space-2)); }
  .gfx[data-d="05"] .plot .ranked > .node.hit-down { translate: -50% calc(-1 * var(--space-2)); }
  .gfx[data-d="05"] .plot .ranked > .node.hit-right { translate: calc(-1 * var(--space-2)) -50%; }
  .gfx[data-d="05"] .plot .ranked > .node > .dot-btn::before { content: ""; position: absolute; left: 50%; top: 50%; translate: -50% -50%; box-sizing: border-box; width: var(--space-3); height: var(--space-3); border: var(--line) solid var(--d05-dot); border-radius: var(--radius-pin); background: var(--d05-dot); transition: background-color var(--dur-ui) var(--ease); }
  .gfx[data-d="05"] .plot .ranked > .node.hit-up > .dot-btn::before { left: 50%; top: auto; bottom: 0; translate: -50% 0; }
  .gfx[data-d="05"] .plot .ranked > .node.hit-down > .dot-btn::before { left: 50%; top: 0; translate: -50% 0; }
  .gfx[data-d="05"] .plot .ranked > .node.hit-right > .dot-btn::before { left: 0; top: 50%; translate: 0 -50%; }
  .gfx-armed.gfx[data-d="05"] .plot .ranked > .node:not(.is-on) > .dot-btn::before { background: var(--paper); border-width: var(--line-strong); }
  .gfx[data-d="05"] .plot .ranked > .node.hit-up > .dot-btn::after { translate: -50% calc(-50% - (var(--space-2) + var(--space-1)) / 2); }
  .gfx[data-d="05"] .plot .ranked > .node.hit-down > .dot-btn::after { translate: -50% calc(-50% + (var(--space-2) + var(--space-1)) / 2); }
  .gfx[data-d="05"] .plot .ranked > .node.hit-right > .dot-btn::after { translate: calc(-50% + (var(--space-2) + var(--space-1)) / 2) -50%; }
  .gfx[data-d="05"] .plot .band, .gfx[data-d="05"] .plot .mark, .gfx[data-d="05"] .plot .axis-title { width: max-content; }
  .gfx[data-d="05"] .plot .band { translate: -100% -50%; }
  .gfx[data-d="05"] .plot .mark > .node-btn { display: inline-flex; align-items: center; gap: var(--space-1); }
  .gfx[data-d="05"] .plot .mark.before > .node-btn::before { content: ""; flex: none; box-sizing: border-box; width: var(--space-3); height: var(--space-3); border: var(--line-strong) solid var(--contrast); border-radius: var(--radius-pin); }
  .gfx[data-d="05"] .plot .node:has(> .node-btn:hover), .gfx[data-d="05"] .plot .node:has(> .node-btn:focus-visible), .gfx[data-d="05"] .plot .node:has(> .node-btn[aria-expanded="true"]), .gfx[data-d="05"] .plot .node:has(> .card:hover) { z-index: 4; }
  .gfx[data-d="05"] .miles { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@container (min-width: 1000px) {
  .gfx[data-d="05"] .gfx-stage { grid-template-columns: minmax(0, 640fr) minmax(0, 560fr); column-gap: var(--space-3); }
  .gfx[data-d="05"] .factors { grid-column: 1 / -1; }
}
@media print {
  .gfx-armed.gfx[data-d="05"] .plot .ranked > .node:not(.is-on) > .dot-btn::before { background: var(--d05-dot); border-width: var(--line); }
  .gfx-armed.gfx[data-d="05"] .lane:has(> .chips:not(.is-on)) > .lane-name, .gfx-armed.gfx[data-d="05"] .miles > span:has(> .reveal:not(.is-on)) > b { color: var(--ink); }
}
@media (forced-colors: active) {
  .gfx[data-d="05"] .plot .axis, .gfx[data-d="05"] .plot .band-line, .gfx[data-d="05"] .plot .ring { stroke: CanvasText; }
  .gfx[data-d="05"] .plot :is(#D05-flabels, #D05-flabels-ns) text { stroke: Canvas; }
  .gfx[data-d="05"] .plot .ranked > .node > .dot-btn::before { forced-color-adjust: none; }
  .gfx[data-d="05"] .plot .ranked > .node, .gfx[data-d="05"] .plot .ranked > .node.after { --d05-dot: CanvasText; }
  .gfx-armed.gfx[data-d="05"] .plot .ranked > .node:not(.is-on) > .dot-btn::before { background: Canvas; }
  .gfx[data-d="05"] .chip, .gfx[data-d="05"] .p0 .chip, .gfx[data-d="05"] .pin, .gfx[data-d="05"] .plot .mark.before > .node-btn::before { border-color: CanvasText; }
}
/* @fig D-05 end */

/* @fig D-06 start: epics to features to stories (steps) */
/* @fig D-06: epics to features to stories, sized twice (steps). Narrow and up to a 1100 px container: an indented list, each
   epic then its features with their band and story count, then the level heads. From 1100 px: a head column and thirteen
   feature columns; the root, the epics, then the three band rows (PI 1, PI 2, Parked) with each feature in its epic's column
   and its band's row; edges root to epics to features. The band strips are tinted, never opaque, so the edges show through
   them. Row 7 is the stories row (count and points per built feature, beside the "44 stories" head); row 8 names the 7
   stories of the two platform items, so the row sums to 44. Edges into rows 5 and 6 bend at the gutter above PI 1
   (data-mid), like the row 4 edges. Placement uses --wc/--wr, not the shared --col/--row, so the 720 px hook leaves the list
   alone (r3: under 1100 px the thirteen columns were 34 to 54 px and wrapped every number).
   a feature is a label, not a button (no card), so it takes a 2 px left rule in its role colour (--process; parked,
   --rule-strong), never the node border. Unlit (steps, screen), the features stand from step 1 in --ink-3 with a --rule rule,
   solid; step 2 lights them. */
.gfx[data-d="06"] .gfx-stage { min-height: 902px; }
.gfx[data-d="06"] .nodes { gap: var(--space-2); }
.gfx[data-d="06"] .epic { margin-top: var(--space-2); }
.gfx[data-d="06"] .feat { padding-left: var(--space-4); color: var(--ink); font-variant-numeric: tabular-nums; }
.gfx[data-d="06"] .feat b { font-weight: var(--weight-mid); }
.gfx[data-d="06"] .head { margin-top: var(--space-1); }
.gfx[data-d="06"] .head .node-sub { display: inline; }
.gfx[data-d="06"] .gap b { text-decoration: underline; text-decoration-color: var(--contrast); text-decoration-thickness: var(--line-strong); text-underline-offset: var(--space-1); }
.gfx[data-d="06"] .twice > .node-btn { border: var(--line-strong) solid var(--contrast); }
.gfx[data-d="06"] .feat { transition: opacity var(--gfx-move, var(--dur-step)) var(--ease), color var(--dur-ui) var(--ease), border-color var(--dur-ui) var(--ease); }
.gfx[data-d="06"] .story-note { padding-left: var(--space-4); }
@media screen {
  .gfx-armed.gfx[data-d="06"] .feat:not(.is-on) { opacity: 1; color: var(--ink-3); border-left-color: var(--rule); }
  .gfx-armed.gfx[data-d="06"] .feat:not(.is-on) .f-id { color: var(--ink-3); }
  .gfx-armed.gfx[data-d="06"] .twice:not(.is-on) > .node-btn { border-color: var(--rule); }
}
.gfx-snap.gfx[data-d="06"] .feat { transition: none; }
@container (min-width: 720px) {
  .gfx[data-d="06"] .nodes { grid-template-columns: minmax(0, 30rem); }
  .gfx[data-d="06"] .wide-only, .gfx[data-d="06"] svg.edges.wide { display: none; }
  .gfx[data-d="06"] .narrow-only { display: inline; }
}
@container (min-width: 1100px) {
  .gfx[data-d="06"] .gfx-stage { min-height: 446px; }
  .gfx[data-d="06"] .wide-only, .gfx[data-d="06"] svg.edges.wide { display: block; }
  .gfx[data-d="06"] .narrow-only { display: none; }
  .gfx[data-d="06"] .nodes > * { grid-column: var(--wc); grid-row: var(--wr); }
  .gfx[data-d="06"] .nodes { grid-template-columns: minmax(0, 240px) repeat(13, minmax(0, 1fr)); grid-template-rows: repeat(8, auto); gap: var(--space-2) var(--space-1); }
  .gfx[data-d="06"] .epic, .gfx[data-d="06"] .twice { margin-top: var(--space-4); }
  .gfx[data-d="06"] .head { margin-top: 0; }
  .gfx[data-d="06"] .feat { display: flex; flex-direction: column; align-items: flex-start; justify-content: center; justify-self: center; padding: var(--space-1) 0 var(--space-1) var(--space-1); border-left: var(--line-strong) solid var(--process); }
  .gfx[data-d="06"] .feat .f-id { font-weight: var(--weight-mid); color: var(--ink); }
  /* r3: "13 → 21" needs 58 px; between 1100 and 1120 px the column gives 56, so the summed number drops whole to its own line */
  .gfx[data-d="06"] .f-num > .reveal { display: inline-block; margin-left: var(--space-1); }
  .gfx[data-d="06"] :is(#D06-l-f12, #D06-l-f12-ns), .gfx[data-d="06"] :is(#D06-l-f13, #D06-l-f13-ns) { border-left-color: var(--rule-strong); }
  .gfx[data-d="06"] .story { text-align: center; font-variant-numeric: tabular-nums; }
  .gfx[data-d="06"] .story .pts { display: block; }
  .gfx[data-d="06"] .story b { font-weight: var(--weight-mid); color: var(--ink); }
  .gfx[data-d="06"] .story-note { align-self: center; padding-left: 0; }
  .gfx[data-d="06"] .band-strip { border-radius: var(--radius); }
  .gfx[data-d="06"] .band-strip.pi { background: color-mix(in srgb, var(--process) 8%, transparent); border: var(--line) solid var(--rule); }
  .gfx[data-d="06"] .band-strip.parked { border: var(--line) dashed var(--rule-strong); }
  .gfx[data-d="06"] .parked-name { align-self: center; padding-left: var(--control-pad); color: var(--ink); font-weight: var(--weight-mid); }
}
@media (prefers-reduced-motion: reduce) {
  .gfx[data-d="06"] .feat { transition: none; }
}
@media (forced-colors: active) {
  .gfx[data-d="06"] .gap b { text-decoration-color: CanvasText; }
  .gfx[data-d="06"] .twice > .node-btn, .gfx[data-d="06"] .band-strip.pi, .gfx[data-d="06"] .band-strip.parked, .gfx[data-d="06"] .feat { border-color: CanvasText; }
}
/* @fig D-06 end */

/* @fig D-07 start: the workback plan (steps) */
/* @fig D-07: the workback plan (steps). Narrow and up to a 1100 px container: a dated list from the launch back to the first
   interview, each phase a group head, under the axis title. From 1100 px: a week axis from L−31 to L with the fourteen
   milestones placed by week, each naming its week, its date and what it is; the axis title top left. Most milestones sit in
   two staggered rows (3 and 4); the four consecutive weeks L−24 to L−21 climb one row a week (rows 4 to 1) and L−7 sits in
   row 2 above L−6, so no two milestones in a row sit closer than 24 px and no two edges share a segment. Edges run right to left from each milestone to the one it depends on, adjacent weeks meeting
   through the row gap, and the phase brackets sit under the axis. Placement uses --wc/--wr, not the shared --col/--row, so
   the 720 px hook leaves the list alone. */
.gfx[data-d="07"] .gfx-stage { min-height: 896px; }
.gfx[data-d="07"] .axis-title { margin-bottom: var(--space-2); }
.gfx[data-d="07"] .nodes { gap: var(--space-2); }
.gfx[data-d="07"] .axis { display: none; }
.gfx[data-d="07"] .phase { color: var(--ink); font-weight: var(--weight-mid); }
.gfx[data-d="07"] .node + .phase { margin-top: var(--space-3); }
/* every milestone border at the strong width, so step 5 turning L−31 contrast changes a colour, never the row height the edges were routed on */
.gfx[data-d="07"] .node > .node-btn { border-width: var(--line-strong); }
.gfx[data-d="07"] .wk { font-variant-numeric: tabular-nums; }
.gfx[data-d="07"] .sep, .gfx[data-d="07"] .dt, .gfx[data-d="07"] .what { font-weight: var(--weight-body); color: var(--ink-2); }
.gfx[data-d="07"] .dt { font-variant-numeric: tabular-nums; }
@container (min-width: 720px) {
  .gfx[data-d="07"] .nodes { grid-template-columns: minmax(0, 30rem); }
  .gfx[data-d="07"] svg.edges.wide { display: none; }
}
@container (min-width: 1100px) {
  .gfx[data-d="07"] .gfx-stage { min-height: 492px; }
  .gfx[data-d="07"] svg.edges.wide { display: block; }
  /* r3: outer columns at 24 px so the 72 px milestones at L−31 and L stay inside the stage */
  .gfx[data-d="07"] .nodes { grid-template-columns: var(--space-4) repeat(32, minmax(0, 1fr)) var(--space-4); grid-template-rows: repeat(6, auto); gap: var(--space-2) 0; padding-top: var(--space-2); }
  .gfx[data-d="07"] .nodes > * { grid-column: var(--wc); grid-row: var(--wr); }
  /* r3: 72 px wide (the widest word, "interviews" at 12 px, fits); in a row the buttons share one height, so a
     right-to-left edge between two of them stays level */
  .gfx[data-d="07"] .node { display: flex; flex-direction: column; justify-self: center; width: calc(var(--space-6) + var(--space-2)); }
  .gfx[data-d="07"] .node:not(.top) { margin-top: var(--space-4); }
  .gfx[data-d="07"] .node-btn { flex: 1 0 auto; padding: var(--space-1); text-align: center; }
  .gfx[data-d="07"] .sep { display: none; }
  .gfx[data-d="07"] .dt, .gfx[data-d="07"] .what { display: block; }
  .gfx[data-d="07"] .what { font-size: var(--size-graphic); }
  .gfx[data-d="07"] .axis-title { align-self: start; margin: 0; }
  /* the axis: a line from the centre of L−31's column to the centre of L's, a tick hanging from it every two weeks */
  .gfx[data-d="07"] .axis { position: relative; display: grid; grid-template-columns: repeat(32, minmax(0, 1fr)); height: var(--space-2); margin-top: var(--space-2); }
  .gfx[data-d="07"] .axis::before { content: ""; position: absolute; left: calc(100% / 64); right: calc(100% / 64); top: 0; border-top: var(--line-strong) solid var(--rule-strong); }
  .gfx[data-d="07"] .axis > span { grid-column: var(--tc); grid-row: 1; justify-self: center; width: 0; height: var(--space-2); border-left: var(--line) solid var(--rule-strong); }
  /* the phase brackets: from the centre of the first week's column to the centre of the last, the legs reaching up.
     the label keeps the whole grid area (no percentage margin, so the spacing stays on the 4 px grid); one
     ::before inset by half a week's column draws the line and both legs */
  .gfx[data-d="07"] .phase, .gfx[data-d="07"] .node + .phase { position: relative; margin: var(--space-3) 0 0; padding-top: var(--space-1); text-align: center; }
  .gfx[data-d="07"] .phase::before { content: ""; position: absolute; left: calc(50% / var(--span) + var(--space-1) / 2); right: calc(50% / var(--span) + var(--space-1) / 2); top: calc(var(--line-strong) - var(--space-2)); box-sizing: border-box; height: var(--space-2); border: var(--line-strong) solid var(--process); border-top: 0; }
}
@media (forced-colors: active) {
  .gfx[data-d="07"] .axis::before, .gfx[data-d="07"] .axis > span, .gfx[data-d="07"] .phase::before { border-color: CanvasText; }
}
/* @fig D-07 end */

/* @fig D-08 start: the burn-down (steps) */
/* @fig D-08: the burn-down (steps). Narrow: the chart is not drawn; PI 1 is a table (sprint, remaining, added), then the
   four sprint buttons in a row and the two markers as rows, then the PI 2 table. Wide: the chart at the left (scope in the
   contrast colour, remaining in the accent, ideal in the rule colour), the sprint ends as dots over their points, the two
   markers as labelled buttons, and the PI 2 table at the right; the PI 1 table stays as the chart's text equivalent. */
.gfx[data-d="08"] .gfx-stage { min-height: 520px; }
.gfx[data-d="08"] .burn { width: 100%; border-collapse: collapse; font-size: var(--size-graphic); line-height: var(--leading-snug); font-variant-numeric: tabular-nums; color: var(--ink-2); }
.gfx[data-d="08"] .burn caption { padding-bottom: var(--space-1); text-align: left; font-weight: var(--weight-mid); color: var(--ink); }
.gfx[data-d="08"] .burn th, .gfx[data-d="08"] .burn td { padding: var(--space-1) var(--space-2) var(--space-1) 0; text-align: left; border-bottom: var(--line) solid var(--rule); }
.gfx[data-d="08"] .burn thead th { font-weight: var(--weight-body); color: var(--ink-3); border-bottom-color: var(--rule-strong); }
.gfx[data-d="08"] .burn tbody th { font-weight: var(--weight-mid); color: var(--ink); }
.gfx[data-d="08"] .burn b { font-weight: var(--weight-mid); color: var(--ink); }
.gfx[data-d="08"] .pi2 { margin-top: var(--space-4); }
.gfx[data-d="08"] .plot { margin-top: var(--space-3); }
.gfx[data-d="08"] .nodes { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--space-2); }
.gfx[data-d="08"] .nodes > .mark { grid-column: 1 / -1; }
.gfx[data-d="08"] .dot-btn { text-align: center; }
/* the chart's lines */
.gfx[data-d="08"] .plot .axis { fill: none; stroke: var(--rule-strong); stroke-width: var(--line); }
.gfx[data-d="08"] .plot .grid { fill: none; stroke: var(--rule); stroke-width: var(--line); }
/* the chart scales 0.88 to 1, so its tick numerals are set at --size-graphic (14 px) in the viewBox and paint 12.3 to 14 px,
   never under 12; a token size, so the page keeps 7 font sizes (--size-6 / 0.88 computed to an eighth, 13.64 px) */
.gfx[data-d="08"] .plot svg text.tick { font-size: var(--size-graphic); }
.gfx[data-d="08"] .plot .ideal { fill: none; stroke: var(--rule-strong); stroke-width: var(--line); stroke-dasharray: 4 4; }
.gfx[data-d="08"] .plot .scope { fill: none; stroke: var(--contrast); stroke-width: var(--line-strong); }
.gfx[data-d="08"] .plot .remain { fill: none; stroke: var(--accent); stroke-width: calc(var(--line-strong) * 1.5); stroke-linecap: round; }
.gfx[data-d="08"] .plot .demo { fill: none; stroke: var(--accent); stroke-width: var(--line); stroke-dasharray: 2 4; }
/* the scope step: the line after sprint 2 is drawn at 88 and sits at 83 until step 3 adds .up (scripts off: it has .up) */
.gfx[data-d="08"] :is(#D08-l-sc2, #D08-l-sc2-ns) { transform: translateY(13.33px); }
.gfx[data-d="08"] :is(#D08-l-sc2, #D08-l-sc2-ns).up { transform: none; }
@media (prefers-reduced-motion: no-preference) {
  .gfx[data-d="08"] :is(#D08-l-sc2, #D08-l-sc2-ns) { transition: opacity var(--gfx-move, var(--dur-step)) var(--ease), transform var(--gfx-move, var(--dur-step)) var(--ease); }
}
@container (min-width: 720px) {
  .gfx[data-d="08"] .gfx-stage { min-height: 320px; }
  /* the chart never above its drawn size, so the labelled markers keep clear of the lines (scale 0.88 to 1) */
  .gfx[data-d="08"] .plot { max-width: 760px; }
  .gfx[data-d="08"] .pi2 { width: auto; min-width: 18rem; }
  /* dots in the accent on the remaining line; the 44 px ::after hit area takes the node as its box */
  .gfx[data-d="08"] .plot .dot-btn { position: static; display: block; background: var(--accent); border-color: var(--accent); }
  .gfx[data-d="08"] .plot .mark { width: max-content; translate: 0 -50%; }
  .gfx[data-d="08"] .plot .mark.end { translate: -100% -50%; }
  .gfx[data-d="08"] .plot .node:has(> .node-btn:hover) { z-index: 4; }
  .gfx[data-d="08"] .plot .node:has(> .node-btn:focus-visible) { z-index: 4; }
  .gfx[data-d="08"] .plot .node:has(> .node-btn[aria-expanded="true"]) { z-index: 4; }
  .gfx[data-d="08"] .plot .node:has(> .card:hover) { z-index: 4; }
}
/* from 1100 px the PI 2 table moves to the right of the chart */
@container (min-width: 1100px) {
  .gfx[data-d="08"] .gfx-stage { display: grid; grid-template-columns: minmax(0, 19fr) minmax(0, 11fr); align-items: start; column-gap: var(--space-5); }
  .gfx[data-d="08"] .plot { margin-top: 0; }
  .gfx[data-d="08"] .pi2 { width: 100%; min-width: 0; }
}
@media (forced-colors: active) {
  .gfx[data-d="08"] .plot .axis, .gfx[data-d="08"] .plot .grid, .gfx[data-d="08"] .plot .ideal, .gfx[data-d="08"] .plot .scope, .gfx[data-d="08"] .plot .demo { stroke: CanvasText; }
  .gfx[data-d="08"] .plot .remain { stroke: LinkText; }
  .gfx[data-d="08"] .plot .dot-btn { forced-color-adjust: none; background: LinkText; border-color: LinkText; }
}
/* @fig D-08 end */

/* @fig D-09 start: who is in the room (steps) */
/* @fig D-09: who is in the room, at every stage (steps). Narrow: a list by stage, each stage head (D-01's names) then its
   marks, each mark prefixed with its group. 720 to 1099 px: the grid transposed, a stage per row and a column per group
   (customers, engineers, stakeholders). From 1100 px: the swimlane, eight stage columns with each group's name as a title
   across its lane and its marks under it. The sign-offs are in the accent, the offsite and the design sessions in the
   process colour; the column head lights with its step. Placement uses --tc/--tr (transposed) and --col/--row (lanes). */
.gfx[data-d="09"] .gfx-stage { min-height: 1420px; }
.gfx[data-d="09"] .nodes { gap: var(--space-1); }
.gfx[data-d="09"] .stage-h { margin-top: var(--space-3); padding-bottom: var(--space-1); color: var(--ink-3); font-weight: var(--weight-mid); border-bottom: var(--line-strong) solid var(--rule); }
.gfx[data-d="09"] .lane + .stage-h { margin-top: 0; }
.gfx[data-d="09"] .stage-h .num { font-variant-numeric: tabular-nums; }
.gfx[data-d="09"] .stage-h.lit { color: var(--ink); border-bottom-color: var(--accent); }
.gfx[data-d="09"] .pre { font-weight: var(--weight-body); color: var(--ink-2); }
@media (prefers-reduced-motion: no-preference) {
  .gfx[data-d="09"] .stage-h { transition: color var(--dur-ui) var(--ease), border-color var(--dur-ui) var(--ease); }
}
@container (min-width: 720px) {
  .gfx[data-d="09"] .gfx-stage { min-height: 440px; }
  .gfx[data-d="09"] .nodes { grid-template-columns: minmax(0, 8rem) repeat(3, minmax(0, 1fr)); grid-template-rows: repeat(9, auto); gap: var(--space-1) var(--space-2); }
  .gfx[data-d="09"] .nodes > * { grid-column: var(--tc); grid-row: var(--tr); }
  .gfx[data-d="09"] .stage-h, .gfx[data-d="09"] .lane + .stage-h { margin-top: 0; display: flex; align-items: center; gap: var(--space-1); }
  .gfx[data-d="09"] .lane { align-self: end; padding-bottom: var(--space-1); color: var(--ink); font-weight: var(--weight-mid); }
  .gfx[data-d="09"] .node > .node-btn { height: 100%; }
  /* the stakeholders column is the last: its cards open to the left */
  .gfx[data-d="09"] .node.r3 > .card { left: auto; right: 0; }
}
@container (min-width: 1100px) {
  .gfx[data-d="09"] .gfx-stage { min-height: 320px; }
  .gfx[data-d="09"] .nodes { grid-template-columns: repeat(8, minmax(0, 1fr)); grid-template-rows: repeat(7, auto); gap: var(--space-1); }
  .gfx[data-d="09"] .nodes > * { grid-column: var(--col); grid-row: var(--row); }
  .gfx[data-d="09"] .stage-h, .gfx[data-d="09"] .lane + .stage-h { display: block; }
  .gfx[data-d="09"] .lane { align-self: auto; margin-top: var(--space-2); padding: var(--space-1) 0 0; border-top: var(--line) solid var(--rule); }
  .gfx[data-d="09"] .node-btn { padding: var(--space-2); }
  .gfx[data-d="09"] .node.r3:not([data-align="end"]) > .card { left: 0; right: auto; }
}
@media (forced-colors: active) {
  .gfx[data-d="09"] .stage-h, .gfx[data-d="09"] .lane { border-color: CanvasText; }
  .gfx[data-d="09"] .stage-h.lit { border-color: LinkText; }
}
/* @fig D-09 end */

/* @fig D-10 start: the dial-up ladder (steps) */
/* @fig D-10: the dial-up ladder (steps). Narrow: one column, each riser passing through its gate mark, the rollback edges in the left lane. Wide: the preparation column, the Gates node over the ladder, four stages rising by token offsets, rollback under the middle. */
.gfx[data-d="10"] .gfx-stage { min-height: 720px; }
.gfx[data-d="10"] .nodes { padding-left: var(--space-4); }
.gfx[data-d="10"] .label { justify-self: center; text-align: center; }
.gfx[data-d="10"] .label svg { width: 1em; height: 1em; vertical-align: -0.125em; fill: none; stroke: currentColor; stroke-width: var(--line-strong); }
.gfx[data-d="10"] :is(#D10-l-breach, #D10-l-breach-ns) > span { display: block; }
.gfx[data-d="10"] .label.before { color: var(--contrast); }
@container (min-width: 720px) {
  .gfx[data-d="10"] .gfx-stage { min-height: 300px; }
  .gfx[data-d="10"] .nodes { grid-template-columns: minmax(0, 260fr) repeat(4, minmax(0, 199fr)); grid-template-rows: auto auto auto; column-gap: var(--space-5); padding-left: 0; }
  .gfx[data-d="10"] .node, .gfx[data-d="10"] .label { align-self: start; }
  .gfx[data-d="10"] .label { justify-self: end; text-align: right; }
  .gfx[data-d="10"] :is(#D10-2, #D10-2-ns) { align-self: center; }
  .gfx[data-d="10"] :is(#D10-3, #D10-3-ns) { align-self: end; }
  /* the rise is a transform, so it leaves the spacing inventory; only the lowest stage keeps its margin,
     because that margin sizes the row (a transform reserves no space, and the stage wraps to two lines below 1100 px) */
  .gfx[data-d="10"] :is(#D10-7, #D10-7-ns) { translate: 0 calc(var(--space-5) - var(--space-1)); }
  .gfx[data-d="10"] :is(#D10-6, #D10-6-ns) { translate: 0 calc(2 * (var(--space-5) - var(--space-1))); }
  .gfx[data-d="10"] :is(#D10-5, #D10-5-ns) { margin-top: calc(3 * (var(--space-5) - var(--space-1))); }
  /* a transformed node is its own stacking context: the open, hovered or focused one comes forward so its card stays on top */
  .gfx[data-d="10"] .node:hover, .gfx[data-d="10"] .node:has(> .node-btn:focus-visible), .gfx[data-d="10"] .node:has(> .node-btn[aria-expanded="true"]) { z-index: 4; }
  .gfx[data-d="10"] :is(#D10-l-g3, #D10-l-g3-ns) { margin-top: var(--space-2); }
  .gfx[data-d="10"] :is(#D10-l-breach, #D10-l-breach-ns) { margin-top: var(--space-4); }
  .gfx[data-d="10"] :is(#D10-l-g1, #D10-l-g1-ns) { translate: 0 calc(var(--space-6) + var(--space-3)); }
}
@media (forced-colors: active) {
  .gfx[data-d="10"] .label.before { color: CanvasText; }
}
/* @fig D-10 end */

/* @fig D-11 start: the metrics tree (steps) */
/* @fig D-11: the metrics tree (steps). Narrow: a list top down, each level head followed by its metrics, indented, each metric on one line as name · number. Wide: level heads at the left, the tree in six sub-columns (inputs full width, outputs inside, the outcome centred) on rows 1, 3 and 5, the defect column at the right. */
.gfx[data-d="11"] .gfx-stage { min-height: 744px; }
.gfx[data-d="11"] .nodes { gap: var(--space-2); }
.gfx[data-d="11"] .node:not(.lvl) { margin-left: var(--space-4); }
.gfx[data-d="11"] .lvl { margin-top: var(--space-3); }
.gfx[data-d="11"] .node-sub { display: inline; }
.gfx[data-d="11"] .label { font-weight: var(--weight-mid); color: var(--ink); }
@container (min-width: 720px) {
  .gfx[data-d="11"] .gfx-stage { min-height: 300px; }
  .gfx[data-d="11"] .nodes { grid-template-columns: minmax(0, 120fr) repeat(6, minmax(0, 109fr)) minmax(0, 276fr); grid-template-rows: repeat(5, auto); gap: var(--space-2) var(--space-4); }
  .gfx[data-d="11"] .node, .gfx[data-d="11"] .label { align-self: center; }
  .gfx[data-d="11"] .node:not(.lvl) { margin-left: 0; }
  .gfx[data-d="11"] .lvl { margin-top: 0; }
  .gfx[data-d="11"] .node-sub { display: block; }
  .gfx[data-d="11"] :is(#D11-9, #D11-9-ns), .gfx[data-d="11"] :is(#D11-10, #D11-10-ns), .gfx[data-d="11"] :is(#D11-11, #D11-11-ns), .gfx[data-d="11"] :is(#D11-12, #D11-12-ns), .gfx[data-d="11"] :is(#D11-13, #D11-13-ns) { margin-left: var(--space-4); }
  .gfx[data-d="11"] .label { padding-left: var(--control-pad); }
}
/* @fig D-11 end */

/* @fig D-12 start: the flywheel (flow) */
/* @fig D-12: the flywheel (flow). Narrow: one column, loop A with its return up the left lane, the note with its two edges in the right lane, then loop B with its return up the left lane. Wide: loop A as a pentagon over six sub-columns, a spacer column, loop B as a square in the right two columns, the note low under loop B's left side; both loops run counter-clockwise. */
.gfx[data-d="12"] .gfx-stage { min-height: 736px; }
.gfx[data-d="12"] .nodes { gap: var(--space-4); padding-left: var(--space-4); padding-right: var(--space-4); }
.gfx[data-d="12"] :is(#D12-6, #D12-6-ns), .gfx[data-d="12"] :is(#D12-7, #D12-7-ns) { margin-top: var(--space-3); }
@container (min-width: 720px) {
  .gfx[data-d="12"] .gfx-stage { min-height: 360px; }
  .gfx[data-d="12"] .nodes { grid-template-columns: repeat(6, minmax(0, 83fr)) minmax(0, 38fr) repeat(2, minmax(0, 180fr)); grid-template-rows: repeat(3, minmax(92px, auto)); gap: var(--space-5); padding-left: 0; padding-right: 0; }
  .gfx[data-d="12"] .node { align-self: center; }
  .gfx[data-d="12"] :is(#D12-6, #D12-6-ns), .gfx[data-d="12"] :is(#D12-7, #D12-7-ns) { margin-top: 0; }
}
/* @fig D-12 end */

/* @fig D-13 start: the AI improvement loop (steps) */
/* @fig D-13: the AI improvement loop (steps). Narrow: one column in loop order; the return runs up the left lane and the "no" branch round the right lane. Wide: the measure row on top, the fix path right to left below, yes and no on their edges. */
.gfx[data-d="13"] .gfx-stage { min-height: 680px; }
.gfx[data-d="13"] .nodes { gap: var(--space-4); padding-left: var(--space-4); padding-right: var(--space-4); }
.gfx[data-d="13"] .label { justify-self: center; padding: 0 var(--space-2); }
@container (min-width: 720px) {
  .gfx[data-d="13"] .gfx-stage { min-height: 300px; }
  .gfx[data-d="13"] .nodes { grid-template-columns: repeat(4, minmax(0, 1fr)); grid-template-rows: minmax(104px, auto) 92px minmax(104px, auto); gap: 0 var(--space-5); padding-left: 0; padding-right: 0; }
  .gfx[data-d="13"] .node { align-self: center; }
  .gfx[data-d="13"] .label { align-self: center; padding: 0 0 var(--space-5); }
}
/* @fig D-13 end */

/* arming paints the start state at once (player.js adds gfx-snap for one style flush) */
.gfx.gfx-snap .node-btn, .gfx.gfx-snap .reveal, .gfx.gfx-snap .token { transition: none; }

/* ---- skin (site copy): every node is filled in one of the three role colours, a solid band in that colour holds its
   icon, connectors are weighted, and one icon control has a step indicator. Follows every rule above, so it restyles
   without editing them. Tokens only. Role colours: --contrast the problem or the before, --process the work, --accent
   the outcome; a person's decision is the one solid --accent node. */
.gfx { --band: 2.5rem; --tint: 26%; --tint-p: 48%; --tint-park: 20%; --dim: 10%; }
@media (prefers-color-scheme: dark) { .gfx { --tint: 34%; --tint-p: 38%; --dim: 14%; } }
/* hue ruling r3: the process ladder carries meaning only from 45 % (light) and 34 % (dark), where its OKLCH chroma reaches
   0.015; under that the sage reads grey. So a process fill uses --tint-p, the accent and contrast fills --tint (--rtint) */
.gfx .node { --role: var(--process); --role-ink: var(--process-ink); --rtint: var(--tint-p); }
.gfx .node.before, .gfx .node.twice { --role: var(--contrast); --role-ink: var(--contrast-ink); --rtint: var(--tint); }
.gfx .node.after, .gfx .node.human { --role: var(--accent); --role-ink: var(--accent-ink); --rtint: var(--tint); }
/* the role of each node, figure by figure, so every diagram carries all three colours */
.gfx :is(:is(#D01-1, #D01-1-ns), :is(#D01-2, #D01-2-ns), :is(#D02-5, #D02-5-ns), :is(#D04-6, #D04-6-ns), :is(#D10-9, #D10-9-ns), :is(#D11-9, #D11-9-ns), :is(#D11-10, #D11-10-ns), :is(#D11-11, #D11-11-ns), :is(#D11-12, #D11-12-ns), :is(#D11-13, #D11-13-ns), :is(#D12-7, #D12-7-ns), :is(#D12-8, #D12-8-ns), :is(#D12-9, #D12-9-ns), :is(#D12-10, #D12-10-ns)) { --role: var(--contrast); --role-ink: var(--contrast-ink); --rtint: var(--tint); }
.gfx :is(:is(#D01-3, #D01-3-ns), :is(#D01-4, #D01-4-ns), :is(#D01-5, #D01-5-ns), :is(#D01-6, #D01-6-ns), :is(#D04-1, #D04-1-ns), :is(#D04-2, #D04-2-ns), :is(#D04-3, #D04-3-ns), :is(#D04-4, #D04-4-ns), :is(#D04-5, #D04-5-ns), :is(#D10-1, #D10-1-ns), :is(#D10-2, #D10-2-ns), :is(#D10-3, #D10-3-ns), :is(#D10-4, #D10-4-ns), :is(#D11-5, #D11-5-ns), :is(#D11-6, #D11-6-ns), :is(#D11-7, #D11-7-ns), :is(#D11-8, #D11-8-ns), :is(#D12-4, #D12-4-ns), :is(#D12-6, #D12-6-ns)) { --role: var(--process); --role-ink: var(--process-ink); --rtint: var(--tint-p); }
.gfx :is(:is(#D01-7, #D01-7-ns), :is(#D01-8, #D01-8-ns), :is(#D02-8, #D02-8-ns), :is(#D04-7, #D04-7-ns), :is(#D04-8, #D04-8-ns), :is(#D04-10, #D04-10-ns), :is(#D10-5, #D10-5-ns), :is(#D10-6, #D10-6-ns), :is(#D10-7, #D10-7-ns), :is(#D10-8, #D10-8-ns), :is(#D11-1, #D11-1-ns), :is(#D11-2, #D11-2-ns), :is(#D11-3, #D11-3-ns), :is(#D11-4, #D11-4-ns), :is(#D12-1, #D12-1-ns), :is(#D12-2, #D12-2-ns), :is(#D12-3, #D12-3-ns), :is(#D12-5, #D12-5-ns)) { --role: var(--accent); --role-ink: var(--accent-ink); --rtint: var(--tint); }
/* D-02: back to the customer is the outcome, as the roadmap item (accent); D-03: an ordinary decision dot is the lead
   colour, an escalation the contrast (no grey dot carries meaning) */
@media (forced-colors: none) { .gfx[data-d="03"] .dots li:not(.esc)::before { background: var(--accent); } }
.gfx[data-d="09"] .node.r1 { --role: var(--contrast); --role-ink: var(--contrast-ink); --rtint: var(--tint); }
.gfx[data-d="09"] .node.r2 { --role: var(--process); --role-ink: var(--process-ink); --rtint: var(--tint-p); }
.gfx[data-d="09"] .node.r3 { --role: var(--accent); --role-ink: var(--accent-ink); --rtint: var(--tint); }
/* lit: a tint of the role colour with the role border; chart marks keep their own drawing */
.gfx.gfx .node:where(:not(.band, .mark, .axis-title, .legend)) > .node-btn:where(:not(.dot-btn)) {
  background: color-mix(in srgb, var(--role) var(--rtint, var(--tint)), var(--paper)); border: var(--line-strong) solid var(--role);
  border-radius: var(--space-1); color: var(--ink); opacity: 1; text-wrap: balance;
}
/* hue ruling: a chart mark (D-08) and the D-05 gate key are labels on a button, so they take their role tint, never the page */
.gfx.gfx[data-d="08"] .node.mark > .node-btn:where(:not(.dot-btn)), .gfx.gfx[data-d="05"] .node.legend > .node-btn { background: color-mix(in srgb, var(--role) var(--rtint, var(--tint)), var(--paper)); }
/* a level head (D-11) is a solid band of its role colour */
.gfx.gfx .node.lvl > .node-btn { background: var(--role); color: var(--role-ink); }
.gfx.gfx .node.lvl > .node-btn .node-sub { color: inherit; }
/* a person's decision: the one solid fill, so every human gate reads at a glance; the title is heavier than the line under it */
.gfx.gfx .node.human > .node-btn { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); font-weight: var(--weight-strong); }
.gfx.gfx .node.human > .node-btn .node-sub { color: color-mix(in srgb, var(--accent-ink) 88%, var(--accent)); font-weight: var(--weight-body); }
.gfx.gfx .node.human > .node-btn b { color: inherit; }
.gfx.gfx .node > .node-btn[aria-expanded="true"]:where(:not(.dot-btn)) { box-shadow: 0 0 0 var(--line-strong) var(--paper), 0 0 0 calc(var(--line-strong) * 2) var(--accent); }
/* not reached yet: the same node, dimmed (a light tint, a pale band), never an empty outline */
@media screen {
  .gfx.gfx-armed.gfx .node:not(.is-on) > .node-btn:where(:not(.dot-btn)) { background: color-mix(in srgb, var(--role) var(--dim), var(--paper)); border-color: color-mix(in srgb, var(--role) 45%, var(--paper)); color: var(--ink-2); opacity: 1; }
  .gfx.gfx-armed.gfx .node:not(.is-on) > .node-btn .node-sub { color: var(--ink-2); }
  .gfx.gfx-armed.gfx .node:not(.is-on) > .node-btn > .ic { background: color-mix(in srgb, var(--role) 40%, var(--paper)); color: var(--ink-2); }
}
@media (hover: hover) {
  .gfx.gfx .node > .node-btn:where(:not(.dot-btn)):hover { box-shadow: 0 0 0 var(--line-strong) var(--paper), 0 0 0 calc(var(--line-strong) * 2) var(--accent); }
}
/* the icon band: the leading edge of the node, solid in the role colour, the icon centred in it */
.gfx .node-btn:has(> .ic) { position: relative; padding-left: calc(var(--band) + var(--control-pad)); }
.gfx .node-btn > .ic { position: absolute; left: 0; top: 0; bottom: 0; display: grid; place-items: center; width: var(--band); background: var(--role); color: var(--role-ink); transition: background-color var(--dur-ui) var(--ease), color var(--dur-ui) var(--ease); }
.gfx .ic svg, .layers .ic svg, .fn .ic svg { width: 1rem; height: 1rem; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.gfx .node-btn > .ic svg { width: 1.125rem; height: 1.125rem; }
.gfx.gfx .node.human > .node-btn > .ic { background: color-mix(in srgb, var(--accent-ink) 18%, var(--accent)); color: var(--accent-ink); }
/* D-04: the token spots sit at the leading edge, so the band goes to the trailing edge */
.gfx[data-d="04"] .node-btn:has(> .ic) { padding-left: var(--control-pad); padding-right: calc(var(--band) + var(--control-pad)); }
.gfx[data-d="04"] .node-btn > .ic { left: auto; right: 0; }
/* the token stops on the node's left border, outside the text box; a paper ring keeps it clear on any fill */
.gfx:is([data-d="01"], [data-d="04"]) .node-btn .spot { left: calc(var(--line-strong) / -2); }
.gfx .token { box-shadow: 0 0 0 var(--line-strong) var(--paper); }
/* narrow columns (D-01 and D-09 wide, D-11 from 720 to 1099 px) keep their text width: the band runs across the top */
@container (min-width: 1000px) {
  .gfx[data-d="01"] .node-btn:has(> .ic) { padding-left: var(--control-pad); padding-top: calc(2rem + var(--space-2)); }
  .gfx[data-d="01"] .node-btn > .ic { right: 0; bottom: auto; width: auto; height: 2rem; justify-items: start; padding-left: var(--control-pad); }
  .gfx[data-d="01"] .node-btn .spot { left: auto; right: var(--control-pad); top: 1rem; translate: 50% -50%; }
}
@container (min-width: 720px) {
  .gfx[data-d="09"] .node-btn:has(> .ic) { padding-left: var(--control-pad); padding-top: calc(2rem + var(--space-2)); }
  .gfx[data-d="09"] .node-btn > .ic { right: 0; bottom: auto; width: auto; height: 2rem; justify-items: start; padding-left: var(--control-pad); }
}
@container (min-width: 720px) and (width < 1100px) {
  .gfx[data-d="11"] .node-btn:has(> .ic) { padding-left: var(--control-pad); padding-top: calc(2rem + var(--space-2)); hyphens: auto; }
  .gfx[data-d="11"] .node-btn > .ic { right: 0; bottom: auto; width: auto; height: 2rem; justify-items: start; padding-left: var(--control-pad); }
  .gfx[data-d="11"] .label { padding-left: 0; }
  .gfx[data-d="11"] .nodes { grid-template-columns: max-content repeat(6, minmax(0, 109fr)) minmax(0, 236fr); }
  .gfx[data-d="11"] .lvl > .node-btn { hyphens: manual; }
}
/* D-11 from 1100 px: the level column fits its longest head ("Outputs") beside the icon band, on one line */
@container (min-width: 1100px) { .gfx[data-d="11"] .nodes { grid-template-columns: minmax(10.5rem, 120fr) repeat(6, minmax(0, 109fr)) minmax(0, 276fr); } }
.gfx[data-d="11"] .lvl > .node-btn { hyphens: manual; }
.gfx[data-d="07"] .node-btn { hyphens: manual; }
/* D-07 from 1100 px: each milestone is 88 px, or its longest word if wider, so no word breaks */
@container (min-width: 1100px) { .gfx[data-d="07"] .node { width: calc(var(--space-6) + var(--space-4)); min-width: min-content; } }
/* connectors: heavier, round-capped, in the process colour; a person's branch in the accent */
.gfx .edge { stroke: var(--process); stroke-width: 3px; stroke-linecap: round; }
.gfx .edge.dashed { stroke-dasharray: 5 7; }
.gfx .edge.human { stroke: var(--accent); }
.gfx .arrow { fill: var(--process); }
/* an HTML label wipes in instead of fading, so its text never sits at part opacity (contrast holds through the step) */
.gfx-armed .nodes .reveal:not(.is-on) { opacity: 1; clip-path: inset(0 100% 0 0); }
.gfx .nodes .reveal { transition: clip-path var(--gfx-move, var(--dur-step)) var(--ease); }
/* the step legend under each figure: a numbered chip in the accent per step, the current step marked */
.gfx ol.steps { list-style: none; counter-reset: gfx-step; display: grid; gap: var(--space-2); padding: 0; color: var(--ink); }
.gfx ol.steps > li { counter-increment: gfx-step; position: relative; min-height: 1.75rem; padding: calc(var(--space-1) + 0.125rem) var(--space-2) var(--space-1) calc(1.75rem + var(--space-3)); color: var(--ink); border-radius: var(--space-1); transition: background-color var(--dur-ui) var(--ease); }
.gfx ol.steps > li::before { content: counter(gfx-step); position: absolute; left: var(--space-1); top: var(--space-1); display: grid; place-items: center; width: 1.75rem; height: 1.75rem; border-radius: var(--radius-pin); background: var(--accent); color: var(--accent-ink); font-size: var(--size-graphic); font-weight: var(--weight-strong); font-variant-numeric: tabular-nums; line-height: 1; }
.gfx ol.steps > li[aria-current="step"] { background: color-mix(in srgb, var(--accent) 14%, var(--paper)); color: var(--ink); font-weight: var(--weight-mid); }
.gfx ol.steps > li[aria-current="step"]::before { box-shadow: 0 0 0 var(--line-strong) var(--paper), 0 0 0 calc(var(--line-strong) * 2) var(--accent); }
@container (min-width: 1000px) {
  .gfx ol.steps { display: block; columns: 2; column-gap: var(--space-5); }
  .gfx ol.steps > li { break-inside: avoid; margin-bottom: var(--space-2); }
}
/* the control: one 44 px play/pause button, then a dot per step (filled up to the current one) */
.gfx-controls { gap: var(--space-3); }
.gfx .gfx-btn[data-act="pause"] { justify-content: center; width: var(--control-h); min-width: var(--control-h); height: var(--control-h); padding: 0; border: 0; border-radius: var(--radius-pin); background: var(--accent); color: var(--accent-ink); }
.gfx .gfx-btn[data-act="pause"] svg { width: 1.125rem; height: 1.125rem; }
.gfx .gfx-btn[data-act="pause"]:active { background: var(--accent); transform: translateY(1px); }
@media (hover: hover) { .gfx .gfx-btn[data-act="pause"]:hover { background: color-mix(in srgb, var(--accent) 82%, var(--ink)); color: var(--accent-ink); } }
.gfx .gfx-btn .i-play, .gfx.is-paused .gfx-btn .i-pause { display: none; }
.gfx.is-paused .gfx-btn .i-play { display: block; }
.gfx-dots { display: inline-flex; align-items: center; gap: var(--space-2); }
.gfx-dots i { box-sizing: border-box; width: .5rem; height: .5rem; border: var(--line-strong) solid var(--accent); border-radius: var(--radius-pin); transition: background-color var(--dur-ui) var(--ease), scale var(--dur-ui) var(--ease); }
.gfx:not([data-step]) .gfx-dots, .gfx[data-state="still"] .gfx-dots, .gfx[data-step="0"] .gfx-dots { visibility: hidden; }
.gfx[data-step="1"] .gfx-dots i:nth-child(-n+1) { background: var(--accent); } .gfx[data-step="1"] .gfx-dots i:nth-child(1) { scale: 1.5; }
.gfx[data-step="2"] .gfx-dots i:nth-child(-n+2) { background: var(--accent); } .gfx[data-step="2"] .gfx-dots i:nth-child(2) { scale: 1.5; }
.gfx[data-step="3"] .gfx-dots i:nth-child(-n+3) { background: var(--accent); } .gfx[data-step="3"] .gfx-dots i:nth-child(3) { scale: 1.5; }
.gfx[data-step="4"] .gfx-dots i:nth-child(-n+4) { background: var(--accent); } .gfx[data-step="4"] .gfx-dots i:nth-child(4) { scale: 1.5; }
.gfx[data-step="5"] .gfx-dots i:nth-child(-n+5) { background: var(--accent); } .gfx[data-step="5"] .gfx-dots i:nth-child(5) { scale: 1.5; }
.gfx[data-step="6"] .gfx-dots i:nth-child(-n+6) { background: var(--accent); } .gfx[data-step="6"] .gfx-dots i:nth-child(6) { scale: 1.5; }
.gfx[data-step="7"] .gfx-dots i:nth-child(-n+7) { background: var(--accent); } .gfx[data-step="7"] .gfx-dots i:nth-child(7) { scale: 1.5; }
.gfx[data-step="8"] .gfx-dots i:nth-child(-n+8) { background: var(--accent); } .gfx[data-step="8"] .gfx-dots i:nth-child(8) { scale: 1.5; }
.gfx[data-step="9"] .gfx-dots i:nth-child(-n+9) { background: var(--accent); } .gfx[data-step="9"] .gfx-dots i:nth-child(9) { scale: 1.5; }
.gfx[data-step="10"] .gfx-dots i:nth-child(-n+10) { background: var(--accent); } .gfx[data-step="10"] .gfx-dots i:nth-child(10) { scale: 1.5; }
.gfx[data-step="11"] .gfx-dots i:nth-child(-n+11) { background: var(--accent); } .gfx[data-step="11"] .gfx-dots i:nth-child(11) { scale: 1.5; }
.gfx[data-step="12"] .gfx-dots i:nth-child(-n+12) { background: var(--accent); } .gfx[data-step="12"] .gfx-dots i:nth-child(12) { scale: 1.5; }
@media (prefers-reduced-motion: reduce) { .gfx .gfx-dots { display: none; } .gfx .nodes .reveal { clip-path: none; transition: none; } }
@media print { .gfx-armed .nodes .reveal:not(.is-on) { clip-path: none; } }
@media (forced-colors: active) {
  .gfx.gfx .node > .node-btn:where(:not(.dot-btn)), .gfx.gfx .node.human > .node-btn, .gfx.gfx .node.lvl > .node-btn { background: Canvas; color: CanvasText; border-color: CanvasText; }
  .gfx .node-btn > .ic, .gfx.gfx .node.human > .node-btn > .ic { background: Canvas; color: CanvasText; forced-color-adjust: none; box-shadow: inset 0 0 0 var(--line) CanvasText; }
  .gfx .edge.human { stroke: LinkText; }
  .gfx .gfx-btn[data-act="pause"] { background: ButtonFace; color: ButtonText; border: var(--line) solid ButtonText; }
  .gfx-dots i { border-color: CanvasText; }
  .gfx ol.steps > li::before { forced-color-adjust: none; background: Canvas; color: CanvasText; box-shadow: inset 0 0 0 var(--line) CanvasText; }
  .gfx ol.steps > li[aria-current="step"] { outline: var(--line) solid Highlight; }
}
/* D-01: the eight-column row needs 1000 px; under that the stage line keeps the one-column form (its own edge layer),
   at a readable width */
@container (min-width: 720px) and (width < 1000px) {
  .gfx[data-d="01"] svg.edges.wide { display: none; }
  .gfx[data-d="01"] svg.edges.narrow { display: block; }
  .gfx[data-d="01"] .gfx-stage { min-height: 533px; max-width: 34rem; }
  .gfx[data-d="01"] .nodes { grid-template-columns: minmax(0, 1fr); grid-template-rows: none; gap: var(--space-2); padding-left: var(--space-4); }
  .gfx[data-d="01"] .nodes > * { grid-column: var(--ncol, auto); grid-row: var(--nrow, auto); }
  .gfx[data-d="01"] :is(#D01-l-loop, #D01-l-loop-ns) { align-self: auto; justify-self: start; padding-left: var(--space-2); }
}
/* from 1000 to 1099 px the eight columns are tight: a smaller gap keeps each stage name whole, never hyphenated */
@container (min-width: 1000px) and (width < 1100px) {
  .gfx[data-d="01"] .nodes { column-gap: var(--space-3); }
  .gfx.gfx[data-d="01"] .node > .node-btn:where(:not(.dot-btn)) { padding-inline: var(--space-2); hyphens: manual; }
  .gfx[data-d="01"] .node-btn > .ic { padding-left: var(--space-2); }
  .gfx[data-d="01"] .node-btn .spot { right: var(--space-2); }
}
.gfx[data-d="01"] .node-btn { hyphens: manual; }
/* D-04: the wide form needs 1000 px for four columns; 720 to 999 px keeps the one-column form. "no" shares row 2 with
   "Ranking" (narrow), so it does not open a second column; the reading labels stay shown in the still version */
@container (width < 720px) { .gfx[data-d="04"] .nodes > :is(:is(#D04-l-rank, #D04-l-rank-ns), :is(#D04-l-no, #D04-l-no-ns)) { grid-column: 1; } }
@container (min-width: 720px) and (width < 1000px) {
  .gfx[data-d="04"] svg.edges.wide { display: none; }
  .gfx[data-d="04"] svg.edges.narrow { display: block; }
  .gfx[data-d="04"] .nodes { grid-template-columns: minmax(0, 1fr); grid-template-rows: none; gap: var(--space-3); padding: 0 var(--space-4); }
  .gfx[data-d="04"] .nodes > * { grid-column: var(--ncol, auto); grid-row: var(--nrow, auto); }
  .gfx[data-d="04"] .nodes > :is(:is(#D04-l-rank, #D04-l-rank-ns), :is(#D04-l-no, #D04-l-no-ns)) { grid-column: 1; }
  .gfx[data-d="04"] .tok { align-self: auto; justify-self: auto; padding-left: var(--control-pad); }
  .gfx[data-d="04"] :is(#D04-l-no, #D04-l-no-ns) { justify-self: end; align-self: auto; margin: 0 calc(-1 * var(--space-2)) 0 0; translate: none; }
  .gfx[data-d="04"] :is(#D04-l-yes, #D04-l-yes-ns) { justify-self: start; align-self: auto; margin: 0 0 0 calc(-1 * var(--space-1)); translate: none; }
}
.gfx[data-d="04"] :is(#D04-l-clin, #D04-l-clin-ns) { padding-left: var(--control-pad); color: var(--accent); font-weight: var(--weight-mid); }
@container (min-width: 1000px) {
  .gfx[data-d="04"] .nodes { grid-template-columns: minmax(0, 13rem) 20rem minmax(0, 3fr) minmax(0, 2fr); grid-template-rows: repeat(6, auto); }
  /* the clinical node keeps an inset from the figure's edge; its label sits over it, at the edge's run */
  .gfx[data-d="04"] :is(#D04-11, #D04-11-ns) { align-self: start; margin-left: var(--space-2); }
  .gfx[data-d="04"] :is(#D04-l-clin, #D04-l-clin-ns) { align-self: end; justify-self: end; padding-left: 0; }
  /* "yes" under the yes edge's bottom run, which sits 20 px under gate 5 (row 5 now grows with the hand-off node) */
  .gfx[data-d="04"] :is(#D04-l-yes, #D04-l-yes-ns) { align-self: start; translate: 0 calc(var(--control-h) + var(--space-4)); }
  /* the still version: each reading label stands over the node its token stops on, not beside the gates */
  :is(.gfx[data-state="still"], html:not(.js) .gfx)[data-d="04"] :is(#D04-l-rank, #D04-l-rank-ns) { grid-column: 3; grid-row: 1; justify-self: end; align-self: end; }
  :is(.gfx[data-state="still"], html:not(.js) .gfx)[data-d="04"] :is(#D04-l-reply, #D04-l-reply-ns) { grid-column: 3; grid-row: 4; justify-self: end; align-self: end; }
}
/* D-13: the release sign-off under the flag in the first column; the middle row grows with it */
@container (min-width: 720px) {
  .gfx[data-d="13"] .nodes { grid-template-rows: minmax(104px, auto) minmax(92px, auto) minmax(104px, auto); row-gap: var(--space-4); }
  .gfx[data-d="13"] :is(#D13-8, #D13-8-ns) { align-self: center; }
}
/* D-05: the bands and the roadmap carry the role colours (P0 solid accent, P1 process, P2 contrast, parked neutral) */
.gfx[data-d="05"] .band, .gfx[data-d="05"] .lane { --role: var(--process); --role-ink: var(--process-ink); --rtint: var(--tint-p); }
.gfx[data-d="05"] :is(:is(#D05-5, #D05-5-ns), .lane.p0) { --role: var(--accent); --role-ink: var(--accent-ink); --rtint: var(--tint); }
/* tech debt is the problem-side factor: contrast, so no figure is over 60 % one token (hue ruling) */
.gfx[data-d="05"] :is(:is(#D05-4, #D05-4-ns), :is(#D05-16, #D05-16-ns), .lane.p2) { --role: var(--contrast); --role-ink: var(--contrast-ink); --rtint: var(--tint); }
.gfx[data-d="05"] :is(:is(#D05-19, #D05-19-ns), .lane.nh) { --role: color-mix(in srgb, var(--contrast) 45%, var(--paper)); --role-ink: var(--ink); --rtint: var(--tint); }
.gfx.gfx[data-d="05"] .band > .node-btn { background: color-mix(in srgb, var(--role) var(--rtint, var(--tint)), var(--paper)); border: var(--line-strong) solid var(--role); border-radius: var(--space-1); color: var(--ink); opacity: 1; }
.gfx.gfx[data-d="05"]:not(.gfx-armed) :is(#D05-5, #D05-5-ns) > .node-btn, .gfx.gfx[data-d="05"] :is(#D05-5, #D05-5-ns).is-on > .node-btn { background: var(--accent); color: var(--accent-ink); }
.gfx.gfx[data-d="05"] :is(#D05-19, #D05-19-ns) > .node-btn { background: color-mix(in srgb, var(--contrast) var(--tint-park), var(--paper)); border-style: dashed; color: var(--ink); }
.gfx[data-d="05"] .lane-name { display: flex; align-items: center; gap: var(--space-2); }
.gfx[data-d="05"] .lane-name::before { content: ""; flex: none; width: .75rem; height: .75rem; border-radius: var(--space-1); background: var(--role); }
.gfx[data-d="05"] .chips { align-items: center; }
.gfx.gfx[data-d="05"] .chip { background: color-mix(in srgb, var(--role) var(--rtint, var(--tint)), var(--paper)); border: var(--line-strong) solid var(--role); border-radius: var(--space-1); color: var(--ink); font-weight: var(--weight-mid); }
.gfx.gfx[data-d="05"] .p0 .chip { background: var(--accent); color: var(--accent-ink); }
.gfx.gfx[data-d="05"] .p0 .chip.moved { background: color-mix(in srgb, var(--accent) var(--tint), var(--paper)); color: var(--ink); border-style: dashed; }
.gfx.gfx[data-d="05"] .nh .chip { background: color-mix(in srgb, var(--contrast) var(--tint-park), var(--paper)); border-style: dashed; color: var(--ink); }
/* D-05: every chart dot is a 44 x 44 target (the dot drawn at the end nearest its point, the rest reaching away from
   the neighbour), so no hit area overlaps another; the chart stays one column and stops at 56rem */
@container (min-width: 720px) {
  .gfx[data-d="05"] .plot .ranked > .node > .dot-btn, .gfx[data-d="05"] .plot .ranked > .node.hit > .dot-btn, .gfx[data-d="05"] .plot .ranked > .node.hit.hit-right > .dot-btn { width: var(--control-h); height: var(--control-h); }
  .gfx[data-d="05"] .plot .dot-btn::after, .gfx[data-d="05"] .plot .ranked > .node > .dot-btn::after { content: none; }
  .gfx[data-d="05"] .plot { width: 100%; max-width: 56rem; }
}
/* the band colour is the drawn dot's (::before reads --d05-dot), never the 44 px target's: the button stays transparent */
.gfx[data-d="05"] .plot :is(:is(#D05-12, #D05-12-ns), :is(#D05-13, #D05-13-ns), :is(#D05-14, #D05-14-ns), :is(#D05-15, #D05-15-ns)) { --d05-dot: var(--process); }
.gfx[data-d="05"] .plot :is(:is(#D05-17, #D05-17-ns), :is(#D05-18, #D05-18-ns)) { --d05-dot: var(--contrast); }
.gfx[data-d="05"] .plot :is(:is(#D05-20, #D05-20-ns), :is(#D05-21, #D05-21-ns)) { --d05-dot: color-mix(in srgb, var(--contrast) 45%, var(--paper)); }
.gfx.gfx[data-d="05"] .plot .node > .dot-btn { background: transparent; }
@container (min-width: 1000px) {
  .gfx[data-d="05"] .gfx-stage { grid-template-columns: minmax(0, 1fr); }
}
/* D-08: each sprint dot is a 44 x 44 button with the 16 px dot drawn at its centre; the chart text stays at 14 px or
   more when the chart scales down to its 0.95 floor */
@container (min-width: 720px) {
  .gfx.gfx[data-d="08"] .plot .node > .dot-btn { width: var(--control-h); height: var(--control-h); border: 0; background: radial-gradient(circle closest-side, var(--accent) calc(var(--space-3) / 2 - 0.5px), transparent calc(var(--space-3) / 2)); }
  .gfx.gfx[data-d="08"] .plot .node > .dot-btn::after { content: none; }
  .gfx.gfx-armed.gfx[data-d="08"] .plot .node:not(.is-on):not(.hit) > .dot-btn { background: radial-gradient(circle closest-side, var(--paper) calc(var(--space-3) / 2 - var(--line-strong) - 0.5px), var(--accent) calc(var(--space-3) / 2 - var(--line-strong)) calc(var(--space-3) / 2 - 0.5px), transparent calc(var(--space-3) / 2)); }
  .gfx[data-d="08"] .plot svg text, .gfx[data-d="08"] .plot svg text.tick { font-size: calc(var(--size-graphic) + 1px); }
}
@media (forced-colors: active) { .gfx.gfx[data-d="08"] .plot .node > .dot-btn { forced-color-adjust: none; background: radial-gradient(circle closest-side, LinkText calc(var(--space-3) / 2 - 0.5px), transparent calc(var(--space-3) / 2)); } }
/* table rows cannot wipe, so they appear at once instead of fading (no row sits at part opacity) */
.gfx .burn tr.reveal { transition: none; }
/* the no-script copies: their nodes are spans, drawn as the buttons are */
.gfx-ns .node-btn { cursor: default; }
/* D-13 narrow: the "no" label stands clear of Error analysis, so its arrow reads as the branch into it */
@container (width < 720px) { .gfx[data-d="13"] :is(#D13-l-no, #D13-l-no-ns) { margin-bottom: var(--space-4); font-weight: var(--weight-mid); color: var(--ink); } }
/* D-02, D-03, D-10 and D-12: their wide grids need 1000 px; from 720 to 999 px each keeps its one-column form (its own
   narrow edge layer and row order) at a readable width, as D-01 does, so no label breaks inside a word */
@container (min-width: 720px) and (width < 1000px) {
  .gfx:is([data-d="02"], [data-d="10"], [data-d="12"]) svg.edges.wide { display: none; }
  .gfx:is([data-d="02"], [data-d="10"], [data-d="12"]) svg.edges.narrow { display: block; }
  .gfx:is([data-d="02"], [data-d="03"], [data-d="10"], [data-d="12"]) .gfx-stage { max-width: 34rem; }
  .gfx:is([data-d="02"], [data-d="03"], [data-d="10"], [data-d="12"]) .nodes { grid-template-columns: minmax(0, 1fr); grid-template-rows: none; }
  .gfx:is([data-d="02"], [data-d="03"], [data-d="10"], [data-d="12"]) .nodes > * { grid-column: var(--ncol, auto); grid-row: var(--nrow, auto); }
  .gfx[data-d="02"] .gfx-stage { min-height: 600px; }
  .gfx[data-d="02"] .nodes { gap: var(--space-3); padding-left: var(--space-4); padding-right: var(--space-5); }
  .gfx[data-d="03"] .gfx-stage { min-height: 788px; }
  .gfx[data-d="03"] .nodes { gap: var(--space-2); }
  .gfx[data-d="03"] .cell { align-self: auto; }
  .gfx[data-d="03"] .dots { padding: 0 0 var(--space-2) var(--control-pad); }
  .gfx[data-d="03"] .narrow-only { display: inline; }
  .gfx[data-d="10"] .gfx-stage { min-height: 720px; }
  .gfx[data-d="10"] .nodes { column-gap: var(--space-3); padding-left: var(--space-4); }
  .gfx[data-d="10"] :is(.node, .label) { align-self: auto; }
  .gfx[data-d="10"] .label { justify-self: center; text-align: center; }
  .gfx[data-d="10"] :is(:is(#D10-2, #D10-2-ns), :is(#D10-3, #D10-3-ns)) { align-self: auto; }
  .gfx[data-d="10"] :is(:is(#D10-5, #D10-5-ns), :is(#D10-6, #D10-6-ns), :is(#D10-7, #D10-7-ns), :is(#D10-l-g1, #D10-l-g1-ns), :is(#D10-l-g3, #D10-l-g3-ns), :is(#D10-l-breach, #D10-l-breach-ns)) { translate: none; margin-top: 0; }
  .gfx[data-d="12"] .gfx-stage { min-height: 736px; }
  .gfx[data-d="12"] .nodes { gap: var(--space-4); padding-left: var(--space-4); padding-right: var(--space-4); }
  .gfx[data-d="12"] .node { align-self: auto; }
  .gfx[data-d="12"] :is(:is(#D12-6, #D12-6-ns), :is(#D12-7, #D12-7-ns)) { margin-top: var(--space-3); }
}
/* D-05 under a 328 px container (a 320 px phone): the four factors stand in one column, so "Organization" stays whole */
@container (width < 20.5rem) { .gfx[data-d="05"] .factors { grid-template-columns: minmax(0, 1fr); grid-auto-rows: auto; } }
/* D-04 in the one-column form (under 1000 px): each input label stands inside the gate box it is read at, as in the
   wide form (Ranking beside gate 1, Reply reading beside gate 2): Ranking at the foot of the gate 1 box, where it stops,
   and Reply reading at the foot of the gate 2 box, the first gate it reaches after passing gate 1; never on an arrow.
   The same in play, still, end and without scripts */
@container (width < 1000px) {
  .gfx[data-d="04"] :is(:is(#D04-1, #D04-1-ns), :is(#D04-2, #D04-2-ns)) > .node-btn { padding-bottom: calc(var(--space-2) + 1.75rem); }
  /* every item in the one column: a label sharing a gate's row must not push the gate into a second, implicit column */
  .gfx.gfx[data-d="04"] .nodes > * { grid-column: var(--ncol, 1); }
  .gfx.gfx[data-d="04"] .nodes > :is(:is(#D04-l-rank, #D04-l-rank-ns), :is(#D04-l-reply, #D04-l-reply-ns)) { grid-column: 1; align-self: end; justify-self: start; z-index: 1; margin: 0 0 var(--space-2); padding: 0 0 0 var(--control-pad); line-height: 1.5rem; pointer-events: none; translate: none; }
  .gfx.gfx[data-d="04"] .nodes > :is(#D04-l-rank, #D04-l-rank-ns) { grid-row: 1; }
  .gfx.gfx[data-d="04"] .nodes > :is(#D04-l-reply, #D04-l-reply-ns) { grid-row: 3; }
}
/* minors r3: the D-11 outcome head is a chip like Outputs and Inputs (a solid band of the accent, its icon at the left) */
.gfx[data-d="11"] .label.lvl-chip { position: relative; display: flex; align-items: center; min-height: var(--control-h); padding: var(--space-2) var(--control-pad) var(--space-2) calc(var(--band) + var(--control-pad)); border: var(--line-strong) solid var(--accent); border-radius: var(--space-1); background: var(--accent); color: var(--accent-ink); font-weight: var(--weight-mid); }
.gfx[data-d="11"] .label.lvl-chip > .ic { position: absolute; left: 0; top: 0; bottom: 0; display: grid; place-items: center; width: var(--band); color: var(--accent-ink); }
.gfx[data-d="11"] .label.lvl-chip > .ic svg { width: 1.125rem; height: 1.125rem; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
@container (min-width: 720px) { .gfx.gfx[data-d="11"] .label.lvl-chip { padding-left: calc(var(--band) + var(--control-pad)); } }
@container (min-width: 720px) and (width < 1100px) {
  .gfx.gfx[data-d="11"] .label.lvl-chip { padding-left: var(--control-pad); padding-top: calc(2rem + var(--space-2)); }
  .gfx[data-d="11"] .label.lvl-chip > .ic { right: 0; bottom: auto; width: auto; height: 2rem; justify-items: start; padding-left: var(--control-pad); }
}
/* D-12 names its loops in the graphic: loop A (accent, the slots) and loop B (contrast, the fixes) */
.gfx[data-d="12"] .label.loop-tag { justify-self: start; align-self: start; padding: var(--space-1) var(--space-2); border-left: var(--space-1) solid var(--accent); background: color-mix(in srgb, var(--accent) 12%, var(--paper)); color: var(--ink); border-radius: 0 var(--space-1) var(--space-1) 0; }
/* the loop name is ink; the loop colour is the bar and the tint (contrast text on its own tint fails 4.5:1) */
.gfx[data-d="12"] .label.loop-tag b { color: var(--ink); font-weight: var(--weight-strong); }
.gfx[data-d="12"] :is(#D12-l-b, #D12-l-b-ns) { border-left-color: var(--contrast); background: color-mix(in srgb, var(--contrast) 20%, var(--paper)); }
@container (min-width: 1000px) { .gfx[data-d="12"] :is(#D12-l-b, #D12-l-b-ns) { justify-self: end; align-self: end; } }
@media (forced-colors: active) { .gfx[data-d="11"] .label.lvl-chip { background: Canvas; color: CanvasText; border-color: CanvasText; } .gfx[data-d="12"] .label.loop-tag { border-color: CanvasText; } }
/* B-1 r3: the transparent plot list over the D-05 chart takes no pointer; only its buttons and cards do, so each F label
   stays the top element where it is drawn (hover, tap and the label's own hit test) */
.gfx[data-d="05"] .plot .nodes, .gfx[data-d="05"] .plot .nodes > li { pointer-events: none; }
.gfx[data-d="05"] .plot .nodes > li > * { pointer-events: auto; }
/* M-2 (hue ruling r3): D-06 encodes the level by token and tint step. The roadmap item is the accent at the full step and
   its epics the accent at the light step; the features and the level heads are the process ladder (from 45 %); "sized
   twice" is the contrast. The increment rows are drawn by a process rule, not a grey fill. */
.gfx[data-d="06"] { --tint-a2: 14%; }
.gfx[data-d="06"] :is(#D06-1, #D06-1-ns) { --role: var(--accent); --role-ink: var(--accent-ink); --rtint: var(--tint); }
.gfx[data-d="06"] .epic { --role: var(--accent); --role-ink: var(--accent-ink); --rtint: var(--tint-a2); }
@container (min-width: 1100px) {
  .gfx[data-d="06"] .band-strip.pi { background: transparent; border: var(--line) solid color-mix(in srgb, var(--process) 70%, var(--paper)); }
  .gfx[data-d="06"] .feat { background: color-mix(in srgb, var(--process) var(--tint-p), var(--paper)); border-radius: 0 var(--space-1) var(--space-1) 0; padding-right: var(--space-2); }
  .gfx[data-d="06"] :is(:is(#D06-l-f12, #D06-l-f12-ns), :is(#D06-l-f13, #D06-l-f13-ns)) { background: transparent; }
}
/* D-07 colours each milestone by its phase, as the brackets under the axis do: discover the contrast, decide and plan the
   accent at the light step, build the process ladder, dial-up the accent, the launch the accent at the strong step */
.gfx[data-d="07"] :is(:is(#D07-10, #D07-10-ns), :is(#D07-11, #D07-11-ns), :is(#D07-12, #D07-12-ns)) { --role: var(--accent); --role-ink: var(--accent-ink); --rtint: 12%; }
.gfx[data-d="07"] :is(:is(#D07-5, #D07-5-ns), :is(#D07-6, #D07-6-ns), :is(#D07-7, #D07-7-ns), :is(#D07-8, #D07-8-ns), :is(#D07-9, #D07-9-ns)) { --role: var(--process); --role-ink: var(--process-ink); --rtint: var(--tint-p); }
.gfx[data-d="07"] :is(:is(#D07-2, #D07-2-ns), :is(#D07-3, #D07-3-ns), :is(#D07-4, #D07-4-ns)) { --role: var(--accent); --role-ink: var(--accent-ink); --rtint: var(--tint); }
.gfx[data-d="07"] :is(#D07-1, #D07-1-ns) { --role: var(--accent); --role-ink: var(--accent-ink); --rtint: 44%; }
@media (prefers-color-scheme: dark) { .gfx[data-d="07"] :is(#D07-1, #D07-1-ns) { --rtint: 40%; } }
/* the launch tile is the deepest accent step: its date and line take full ink (muted ink fails 4.5:1 there) */
.gfx.gfx[data-d="07"] :is(#D07-1, #D07-1-ns) > .node-btn :is(.dt, .what) { color: var(--ink); }
@container (min-width: 720px) {
  .gfx[data-d="07"] :is(#D07-l-disc, #D07-l-disc-ns)::before { border-color: var(--contrast); }
  .gfx[data-d="07"] :is(:is(#D07-l-decide, #D07-l-decide-ns), :is(#D07-l-dial, #D07-l-dial-ns))::before { border-color: var(--accent); }
}
/* B-1 r3: the F labels' own svg lies over the dot targets in the same box as the chart (display follows the chart svg) */
.gfx[data-d="05"] .plot > svg.flabels { position: absolute; left: 0; top: 0; width: 100%; height: auto; z-index: 1; pointer-events: none; overflow: visible; }
.gfx[data-d="05"] .plot > svg.flabels text { pointer-events: auto; }
/* R4-1 D-07 from 1100 px: the outer columns are half a milestone (88 px) plus 4 px, so the first and last tiles sit inside the content box */
@container (min-width: 1100px) { .gfx.gfx[data-d="07"] .nodes { grid-template-columns: calc((var(--space-6) + var(--space-4)) / 2 + var(--space-1)) repeat(32, minmax(0, 1fr)) calc((var(--space-6) + var(--space-4)) / 2 + var(--space-1)); } }
/* R4-2 r4 D-05: the "gate" legend joins the band legend column: right-aligned under "Nice-to-have · parked", just
   below the effort axis line (y 256 of the 340 viewBox) where the tick labels stop short, so it needs no row of its own */
@container (min-width: 720px) {
  .gfx[data-d="05"] .plot { margin-top: 0; }
  .gfx[data-d="05"] .plot .ranked > .legend { top: calc(100% * 256 / 340 + var(--space-2)); bottom: auto; left: 100%; translate: -100% 0; }
  /* r4 F-09: the legend sits at the plot's right edge, so its card opens leftwards (as data-align="end" nodes do), never past the page */
  .gfx[data-d="05"] .plot .ranked > .legend .card { left: auto; right: 0; }
}

/* Keep the rightmost breakdown tooltip inside the figure at wide sizes. */
@container (min-width: 720px) { .gfx[data-d="06"] #D06-9 > .card { left: auto; right: 0; } }
