/* New illustrations for the v2 homepage pass — 11 Sept, from Dylan's three sketches and the
 * call notes. Every one of these is composed from the design system's own drawing primitives
 * (Block, Face, Stroke, Cap, diagramTone — all exported on DS) exactly the way ForceMultiplier,
 * FleetMap and MigrationArc already are. Nothing here forks or edits the design system: these
 * are new components sitting beside it, built the same way its own diagrams are built.
 *
 * None of these are final. Each one carries its own orange confirm-or-cut note in review.jsx
 * (the ILLUSTRATIONS registry) — Dylan and Donny look at the drawing itself, not a description
 * of it, and say what's right and what needs to change.
 */

/** A small ellipse-arc helper, the one thing Sketch's arcPts doesn't do (it's circle-only). */
function ellipsePts(cx, cy, rx, ry, a0, a1, n) {
  const out = [];
  for (let i = 0; i <= n; i++) {
    const a = a0 + (a1 - a0) * i / n;
    out.push([cx + Math.cos(a) * rx, cy + Math.sin(a) * ry]);
  }
  return out;
}

/** Samples a cubic bezier into n+1 straight-line points, for feeding a smooth curve through
    Stroke (which only draws polylines). Mike, 24 Sept, on DdilResilience's cloud after it was
    first converted to a hand-drawn Stroke: "now that they're hand-drawn, they look goofy" — an
    11-point polygon traced the right silhouette but read as sharp, angular corners once wobbled,
    not a rounded cloud. Sampling each of the original bezier's own curves densely, instead of
    hand-picking a dozen vertices, keeps the silhouette smooth while still letting Stroke's
    per-segment jitter give it a sketched texture. */
function cubicPts(p0, c1, c2, p1, n) {
  const out = [];
  for (let i = 0; i <= n; i++) {
    const t = i / n, mt = 1 - t;
    const a = mt * mt * mt, b = 3 * mt * mt * t, c = 3 * mt * t * t, d = t * t * t;
    out.push([a * p0[0] + b * c1[0] + c * c2[0] + d * p1[0], a * p0[1] + b * c1[1] + c * c2[1] + d * p1[1]]);
  }
  return out;
}

/** An arrowhead chevron whose wings are perpendicular to the line's own direction, so it always
    points the right way regardless of the angle the line actually travels at — a fixed
    horizontal chevron on a diagonal line is the bug Mike flagged in KeySeal. */
function arrowHead(Stroke, x1, y1, x2, y2, size, seed, ink) {
  const dx = x2 - x1, dy = y2 - y1;
  const len = Math.hypot(dx, dy) || 1;
  const ux = dx / len, uy = dy / len;
  const px = -uy, py = ux;
  const backX = x2 - ux * size, backY = y2 - uy * size;
  const p1 = [backX + px * size * 0.6, backY + py * size * 0.6];
  const p3 = [backX - px * size * 0.6, backY - py * size * 0.6];
  return <Stroke pts={[p1, [x2, y2], p3]} seed={seed} weight={1.5} ink={ink} />;
}

/** A small hand-drawn terrain cue for DistributedSiteReach's optional `terrain` prop — Dylan,
    17 Sept, on Oil & Gas specifically: "these might be in severe environments... platform,
    pipeline station, refinery... floating oil platform or on a mountain or on the gulf away from
    town. Locations that would not have good IT." Drawn from the same Stroke/Face primitives as
    the rest of the file, centered under a site block at (cx, baseY), not as photographic or icon
    assets. 'mountain' is a single triangular peak outline, 'remote' is a few small isolated dots
    standing in for the middle of nowhere.

    Donny Davis, 17 Sept, replying to the V5 email with a screenshot of this exact diagram: "I like
    the illustration! ... For oil and gas, it would be awesome to put an offshore oil platform in
    there and show a starlink connecting. I know you are probably using the same graphic for all
    of them and just swapping text, so if its too much, it still works fine." The first pass at
    'offshore' was two short wavy lines floating under the block — too subtle to register as a
    platform at a glance. A second pass added support legs and a dashed satellite uplink, but an
    independent review of THAT pass, measuring the actual rendered strokes, still found the legs
    "thin enough to be nearly imperceptible" at normal viewing size — correct geometry, not enough
    visual weight. This pass keeps the same footprint (it's still constrained to ~9px of vertical
    room above the site label) but roughly doubles every stroke's weight, adds an X lattice brace
    between the legs — the one detail that reads as "oil rig" rather than "box on sticks" even
    small — and widens the wave's amplitude. The dish sits up-and-LEFT of the block specifically to
    stay clear of the hub-to-site line, which approaches every site from the upper right. */
function terrainCue(Stroke, Face, Cap, kind, cx, baseY, seed, ink) {
  if (kind === 'offshore') {
    const legY0 = baseY - 6, legY1 = baseY + 4;
    const legXs = [cx - 15, cx + 15];
    const dishX = cx - 18, dishY = baseY - 60;
    const uplinkFrom = [cx - 4, baseY - 34];
    return (
      <g>
        {legXs.map((lx, i) => (
          <Stroke key={i} pts={[[lx, legY0], [lx, legY1]]} seed={seed + i} weight={2.2} ink={ink} />
        ))}
        {/* An independent review of the widened-X pass: legs and X now read fine, but "the line
            below the legs... reads mostly as a flat baseline with one modest bump... doesn't
            register as choppy water at first glance." A single wide zigzag apparently gets
            smoothed by the hand-drawn line renderer into something closer to a gentle curve than
            a sharp wave. Switched to four full-amplitude cycles packed into the same width — more
            frequent direction changes read as "choppy" even after smoothing in a way a single
            slow wave doesn't — using the full legY0-to-legY1 range (touching the block's own
            underside at each crest, stopping 2px short of the site label at each trough) instead
            of the softened +1/-1 offsets from the previous pass. */}
        <Stroke pts={[[legXs[0], legY0 + 1], [legXs[1], legY1 - 1]]} seed={seed + 2} weight={2} ink={ink} />
        <Stroke pts={[[legXs[1], legY0 + 1], [legXs[0], legY1 - 1]]} seed={seed + 3} weight={2} ink={ink} />
        <Stroke pts={[
          [cx - 26, legY1], [cx - 19, legY0], [cx - 12, legY1], [cx - 5, legY0],
          [cx + 5, legY1], [cx + 12, legY0], [cx + 19, legY1], [cx + 26, legY0],
        ]} seed={seed + 4} weight={2.4} ink={ink} />
        {[0, 1, 2].map(i => {
          const t0 = i / 3, t1 = (i + 0.62) / 3;
          const lerp = (t) => [uplinkFrom[0] + (dishX - uplinkFrom[0]) * t, uplinkFrom[1] + (dishY - uplinkFrom[1]) * t];
          return <Stroke key={i} pts={[lerp(t0), lerp(t1)]} seed={seed + 10 + i} weight={1.4} ink={ink} />;
        })}
        <Face corners={[[dishX - 5, dishY - 4], [dishX + 5, dishY - 4], [dishX + 5, dishY + 2], [dishX - 5, dishY + 2]]}
          seed={seed + 20} fill="none" ink={ink} weight={1.4} />
        <Cap x={dishX} y={dishY - 8} anchor="middle" fill={ink} size={6} bold>Starlink</Cap>
      </g>
    );
  }
  if (kind === 'mountain') {
    return (
      <Stroke pts={[[cx - 16, baseY + 2], [cx - 4, baseY - 12], [cx + 4, baseY - 4], [cx + 16, baseY + 2]]}
        seed={seed} weight={1.2} ink={ink} />
    );
  }
  if (kind === 'remote') {
    return [-12, 0, 12].map((dx, i) => (
      <Face key={i} corners={[[cx + dx - 1.5, baseY - 5.5], [cx + dx + 1.5, baseY - 5.5], [cx + dx + 1.5, baseY - 2.5], [cx + dx - 1.5, baseY - 2.5]]}
        seed={seed + i} fill={ink} ink={ink} weight={0} />
    ));
  }
  return null;
}

/* Mike/Dylan, 23 Sept call: "change the boxes to an illustration" (Oil & Gas) and per-site icon
   notes for Telecom in the same breath — "you could just make it a stylized oil rig... pipeline
   station could just be a mountain and a refinery could just be like the little factory icon...
   your data center should almost certainly be a server rack, your point of presence could be like
   an electrical substation looking thing, your cell site would be like a tower with a little
   blinky thing on top." DistributedSiteReach's generic Block stood in for every site regardless of
   what kind of site it was; this draws a specific, recognizable shape per site instead, in the
   same thin hand-drawn stroke weight terrainCue above already uses. Returns null for an unlisted
   kind (including undefined) so the caller falls back to the plain Block — this is additive, not
   a replacement for sites that don't need a specific icon.

   Mike, 23 Sept, second pass: "this is horrific... the worst job ever... like an elementary
   schooler would have made it. Does that even remotely look like an oil rig platform? Does a
   pipeline station, is that really a mountain?" The first pass drew every shape from raw, un-
   wobbled SVG path/line/rect/circle primitives — the one function in this file that didn't use
   Stroke/Face at all, which is also the only illustration this file's own hand-drawn look never
   touched. Rebuilt every shape from Stroke/Face (matching terrainCue's own signature) with more
   structure per icon — a tapered, cross-braced lattice for the rig and the cell tower instead of a
   triangle and three bare bars, a two-peak silhouette with a snow-cap notch for the mountain, a
   building with a door and windows instead of a bare rectangle for the factory, and actual
   insulator poles on a transformer housing for the substation — so each one is identifiable on
   its own, not just by the caption under it. */
function siteIcon(Stroke, Face, kind, cx, baseY, seed, ink, accent) {
  const top = baseY - 44, bottom = baseY - 4;
  if (kind === 'rig') {
    const lv = [top, top + (bottom - top) * 0.38, top + (bottom - top) * 0.7, bottom];
    const hw = [4, 8, 12, 15];
    const L = lv.map((y, i) => [cx - hw[i], y]), R = lv.map((y, i) => [cx + hw[i], y]);
    return (
      <g>
        <Stroke pts={L} seed={seed} weight={1.5} ink={ink} />
        <Stroke pts={R} seed={seed + 1} weight={1.5} ink={ink} />
        {[0, 1, 2, 3].map(i => <Stroke key={`b${i}`} pts={[L[i], R[i]]} seed={seed + 2 + i} weight={1.3} ink={ink} />)}
        {[0, 1, 2].map(i => (
          <g key={`x${i}`}>
            <Stroke pts={[L[i], R[i + 1]]} seed={seed + 10 + i} weight={1} ink={ink} />
            <Stroke pts={[R[i], L[i + 1]]} seed={seed + 13 + i} weight={1} ink={ink} />
          </g>
        ))}
      </g>
    );
  }
  if (kind === 'mountain') {
    const peak1 = [cx - 9, top + 2], peak2 = [cx + 9, top + 12];
    return (
      <g>
        <Stroke pts={[[cx - 20, bottom], peak1, [cx - 1, bottom - 9], peak2, [cx + 20, bottom]]}
          seed={seed} weight={1.5} ink={ink} />
        {/* a short snow-cap line just under the taller peak's own tip */}
        <Stroke pts={[[peak1[0] - 4, peak1[1] + 6], [peak1[0], peak1[1] + 1], [peak1[0] + 4, peak1[1] + 6]]}
          seed={seed + 1} weight={1.2} ink={ink} />
      </g>
    );
  }
  if (kind === 'factory') {
    /* Mike, 24 Sept: "the refinery looks sort of like a house... I think that's the issue: is the
       door and the window." A door at roughly the same proportion and position a house's front
       door sits at, plus a small window beside it, is exactly the residential cue that undercuts
       an otherwise-industrial silhouette. Dylan's own spec (17 Sept) never asked for either —
       "the little factory icon that has smoke coming out of the stacks" — so both are dropped
       outright rather than reworked; the building reads as a plain warehouse box under two
       chimneys, which is the actual reference. */
    const roofY = top + 18;
    return (
      <g>
        <Face corners={[[cx - 16, roofY], [cx + 16, roofY], [cx + 16, bottom], [cx - 16, bottom]]}
          seed={seed} fill="none" ink={ink} weight={1.5} />
        <Face corners={[[cx - 11, top + 2], [cx - 6, top + 2], [cx - 6, roofY], [cx - 11, roofY]]}
          seed={seed + 1} fill="none" ink={ink} weight={1.3} />
        <Face corners={[[cx + 3, top + 8], [cx + 8, top + 8], [cx + 8, roofY], [cx + 3, roofY]]}
          seed={seed + 2} fill="none" ink={ink} weight={1.3} />
        <circle cx={cx - 8.5} cy={top - 2} r={2.6} fill="none" stroke={ink} strokeWidth={1.1} />
        <circle cx={cx - 3.5} cy={top - 7} r={3.2} fill="none" stroke={ink} strokeWidth={1.1} />
        <circle cx={cx + 5} cy={top + 2} r={2.2} fill="none" stroke={ink} strokeWidth={1.1} />
      </g>
    );
  }
  if (kind === 'tower') {
    const lv = [top + 2, top + 12, top + 24, bottom];
    const legHw = [1.5, 2.5, 3.2, 4];
    const L = lv.map((y, i) => [cx - legHw[i], y]), R = lv.map((y, i) => [cx + legHw[i], y]);
    const armHw = [9, 11, 7];
    return (
      <g>
        <Stroke pts={L} seed={seed} weight={1.3} ink={ink} />
        <Stroke pts={R} seed={seed + 1} weight={1.3} ink={ink} />
        {[0, 1, 2].map(i => (
          <g key={`arm${i}`}>
            <Stroke pts={[[cx - armHw[i], lv[i] + 4], [cx + armHw[i], lv[i] + 4]]} seed={seed + 5 + i} weight={1.4} ink={ink} />
            <Stroke pts={[L[i], R[i + 1]]} seed={seed + 10 + i} weight={0.9} ink={ink} />
          </g>
        ))}
        <circle cx={cx} cy={top - 3} r={5} fill="none" stroke={accent} strokeWidth={1} />
        <circle cx={cx} cy={top - 3} r={2.6} fill={accent} />
      </g>
    );
  }
  if (kind === 'substation') {
    const boxTop = bottom - 16;
    const poleTop = top + 12;
    return (
      <g>
        <Face corners={[[cx - 11, boxTop], [cx + 11, boxTop], [cx + 11, bottom], [cx - 11, bottom]]}
          seed={seed} fill="none" ink={ink} weight={1.4} />
        <Stroke pts={[[cx - 3, boxTop - 3], [cx + 1, boxTop - 8], [cx - 1, boxTop - 8], [cx + 3, boxTop - 13]]}
          seed={seed + 1} weight={1.1} ink={ink} />
        {[cx - 6, cx + 6].map((px, i) => (
          <g key={i}>
            <Stroke pts={[[px, boxTop], [px, poleTop]]} seed={seed + 2 + i} weight={1.2} ink={ink} />
            <Stroke pts={[[px - 3, poleTop], [px + 3, poleTop]]} seed={seed + 4 + i} weight={1.2} ink={ink} />
            <circle cx={px} cy={poleTop - 2} r={1.8} fill="none" stroke={ink} strokeWidth={1} />
          </g>
        ))}
        <Stroke pts={[[cx - 6, poleTop], [cx + 6, poleTop]]} seed={seed + 6} weight={1} ink={ink} />
      </g>
    );
  }
  return null;
}

/** Two thin bars inset inside a block's own front face — "this host runs guests", not another
    tier of infrastructure. Sized off the block's own box so it never runs past its edges. */
function vmBars(Face, x, y, w, h, seed, ink) {
  const pad = Math.max(2, Math.min(4, w * 0.1));
  const bw = w - pad * 2;
  const bh = Math.max(2, (h - pad * 2 - 2) / 2);
  return [0, 1].map(i => {
    const by = y + pad + i * (bh + 2);
    return <Face key={i} corners={[[x + pad, by], [x + pad + bw, by], [x + pad + bw, by + bh], [x + pad, by + bh]]}
      seed={seed + i} fill="none" ink={ink} weight={0.9} redraw={0} />;
  });
}

/* ------------------------------------------------------------------- BA — hero illustration */

/* GlobalReach — replaces ForceMultiplier in the hero. Dylan, 9/10: "your deployable kit, your
   regional data center, your enterprise... our main value is starting at the edge and going to
   the enterprise." One globe, one control plane above it, three tiers around it. Matches the
   sketch Dylan sent: control plane / edge kit / regional data center / enterprise infrastructure,
   arranged around a hand-drawn globe rather than stacked as a hierarchy.

   The satellite dish above the edge kit — Donny's idea from the same call, drawn as a dashed
   alternate reach to the edge kit — is gone as of the 15 Sept Triq V2 walkthrough. Luigi: "I think
   those are two different problems... the satellite kind of link hanging off there is just a
   little confusing... I don't think it necessarily needs to be on this infrastructure." The
   low-bandwidth/edge-link idea isn't lost as a concept, just off this specific core illustration,
   whose whole point is "one control plane reaches every location the same way."

   The two thin bars inside each infrastructure block are a VM-stack cue — Mike compared this
   against a plain version (no bars) and picked this one, so it's the only version now, not a
   toggle. Mike also caught a real geometry bug here: the edge-kit and regional-data-center
   connectors used to enter the globe at different depths (one nearly horizontal, one a steeper
   diagonal) and actually crossed into the sphere's interior, while the enterprise connector
   correctly just touched its surface. All three now touch the circle's own circumference, and
   edge-kit/regional-data-center are exact mirrors of each other across the vertical center line. */
function GlobalReach({ tone = 'paper', seed = 3, label, style }) {
  const { Block, Face, Stroke, Cap, Sketch } = DS;
  const { diagramTone } = Sketch;
  const t = diagramTone(tone);
  const cx = 210, cy = 158, r = 56;
  const globe = ellipsePts(cx, cy, r, r, 0, Math.PI * 2, 40);
  const meridian = ellipsePts(cx, cy, r * 0.36, r, 0, Math.PI * 2, 28);
  const equator = ellipsePts(cx, cy, r, r * 0.36, 0, Math.PI * 2, 28);
  // Mirrored touch points on the circle itself, at the same height either side of center —
  // computed once so "mirror of each other" is structural, not eyeballed.
  const touchY = cy - r * 0.6;
  const touchDX = Math.sqrt(Math.max(0, r * r - (cy - touchY) * (cy - touchY)));
  const leftTouch = [cx - touchDX, touchY];
  const rightTouch = [cx + touchDX, touchY];
  return (
    <svg viewBox="0 0 420 320" role={label ? 'img' : 'presentation'} aria-label={label} aria-hidden={label ? undefined : 'true'}
      style={{ width: '100%', height: 'auto', display: 'block', overflow: 'visible', ...style }}>
      {/* the globe */}
      <Stroke pts={globe} seed={seed} weight={1.8} ink={t.ink} />
      <Stroke pts={meridian} seed={seed + 2} weight={1.3} ink={t.hair} />
      <Stroke pts={equator} seed={seed + 4} weight={1.3} ink={t.hair} />

      {/* control plane, above the globe. The block has to be wide enough for its own label —
          it wasn't (84 units for a 20-character bold caption), and the text ran off both edges
          of the box at real size. */}
      <Block x={140} y={16} w={140} h={34} d={8} seed={seed + 10} front={t.accentFace} top={t.accentTop} right={t.accentRight} ink={t.ink} />
      <Cap x={210} y={37} anchor="middle" fill="#F0F1FB" size={9} bold>basalt control plane</Cap>
      <Stroke pts={[[210, 50], [210, cy - r - 4]]} seed={seed + 12} weight={1.6} ink={t.ink} />

      {/* edge kit — left. Touches the globe's own edge, mirrored with regional data center. */}
      <Stroke pts={[leftTouch, [70, 140]]} seed={seed + 20} weight={1.4} ink={t.hair} />
      <Block x={28} y={128} w={56} h={26} d={6} seed={seed + 22} front={t.front} top={t.top} right={t.right} ink={t.ink} />
      {vmBars(Face, 28, 128, 56, 26, seed + 60, t.ink)}
      <Cap x={28} y={172} fill={t.muted} size={8}>edge kit</Cap>

      {/* regional data center — right. Mirror of the edge-kit connector across the center line. */}
      <Stroke pts={[rightTouch, [352, 140]]} seed={seed + 30} weight={1.4} ink={t.hair} />
      <Block x={332} y={112} w={62} h={22} d={6} seed={seed + 32} front={t.front} top={t.top} right={t.right} ink={t.ink} />
      <Block x={332} y={140} w={62} h={22} d={6} seed={seed + 34} front={t.front} top={t.top} right={t.right} ink={t.ink} />
      {vmBars(Face, 332, 112, 62, 22, seed + 64, t.ink)}
      {vmBars(Face, 332, 140, 62, 22, seed + 66, t.ink)}
      <Cap x={332} y={182} fill={t.muted} size={8}>regional data center</Cap>

      {/* enterprise infrastructure — below. This one already touched the globe's edge rather
          than entering it; the other two connectors now match its behavior, not the other way
          around. */}
      <Stroke pts={[[cx - 10, cy + r - 2], [180, 258]]} seed={seed + 40} weight={1.4} ink={t.hair} />
      <Block x={158} y={248} w={30} h={40} d={7} seed={seed + 42} front={t.front} top={t.top} right={t.right} ink={t.ink} />
      <Block x={196} y={236} w={30} h={52} d={7} seed={seed + 44} front={t.front} top={t.top} right={t.right} ink={t.ink} />
      <Block x={234} y={258} w={30} h={30} d={7} seed={seed + 46} front={t.front} top={t.top} right={t.right} ink={t.ink} />
      {vmBars(Face, 158, 248, 30, 40, seed + 70, t.ink)}
      {vmBars(Face, 196, 236, 30, 52, seed + 72, t.ink)}
      {vmBars(Face, 234, 258, 30, 30, seed + 74, t.ink)}
      <Cap x={158} y={300} fill={t.muted} size={8}>enterprise infrastructure</Cap>
    </svg>
  );
}

/* ------------------------------------------------------------------- BD — regions and tenancy */

/* FleetTenancyMap — replaces FleetMap on this page. FleetMap itself is untouched and still
   correct for where it's used elsewhere (Solutions, per review.jsx's own notes); it just isn't
   the drawing this section needs, on two counts Dylan and Donny both raised on the 9/10 call.

   First, the visible label: FleetMap's own copy still says "global registry" — that text is
   baked into the design-system bundle, not a prop, so relabeling it here would mean forking the
   bundle. Redrawing it as a new component was the only way to actually get "global control
   plane" onto the page rather than just into the surrounding copy.

   Second, and the bigger reason: Donny, 9/10 — "this looks like regionality, not tenancy... how
   do we amplify the tenancy?" Dylan's own answer on the call was "we might need to show
   regionality and tenancy on the same diagram" — not a second drawing beside the first, one
   drawing. pac-fwd's tenants are Dylan's own example from the call ("Army, Navy, Air Force");
   the other two regions keep placeholder tenant names since nobody named real ones for them. */
function FleetTenancyMap({ tone = 'inverse', seed = 1, label, style }) {
  const { Block, Face, Stroke, Cap, Sketch } = DS;
  const { diagramTone } = Sketch;
  const t = diagramTone(tone);
  const regions = [
    { x: 70, key: 'eu-central', tenants: ['tenant 1', 'tenant 2'] },
    { x: 210, key: 'conus-east', tenants: ['tenant 1', 'tenant 2'] },
    { x: 350, key: 'pac-fwd', tenants: ['army', 'navy', 'air force'] },
  ];
  const boxW = 120, rowH = 54, topY = 104;
  /* Mike, v3 review: "tenant 1" sat only 8px under its region's own label ("eu-central"), and
     each tenant's icon pair sat only 8px under its own label — cramped enough to read as one
     run-on line rather than a region header followed by its tenants. HEAD_GAP opens up the gap
     from the region label to the first tenant row; LABEL_GAP does the same from a tenant's own
     label to its icons. Both flow into boxH so the region's own outline still wraps everything. */
  const HEAD_GAP = 40, LABEL_GAP = 12, BOTTOM_PAD = 20;
  /* Mike, v5 review: the summary caption sat at a fixed y=388 in a 400-tall viewBox, regardless
     of how tall the tallest region box actually was — a ~72-unit gap beneath pac-fwd's own
     "runs independently" line, almost double every other gap in the drawing, and just 12 units
     off the SVG's bottom edge. On a wide illustration column that read as a caption "floating in
     outer space," unclear whether it belonged to this diagram or the next section's. Deriving it
     from the tallest region's own boxH, at the same HEAD_GAP rhythm the rest of the drawing
     already uses, pulls it back onto the diagram it actually describes; the viewBox height
     follows it down instead of leaving dead space below. */
  const maxBoxH = Math.max(...regions.map(r => HEAD_GAP + (r.tenants.length - 1) * rowH + LABEL_GAP + 16 + BOTTOM_PAD));
  const captionY = topY + maxBoxH + 16 + HEAD_GAP;
  const viewH = captionY + BOTTOM_PAD;
  return (
    <svg viewBox={`0 0 420 ${viewH}`} role={label ? 'img' : 'presentation'} aria-label={label} aria-hidden={label ? undefined : 'true'}
      style={{ width: '100%', height: 'auto', display: 'block', overflow: 'visible', ...style }}>
      <Block x={130} y={16} w={160} h={34} d={8} seed={seed + 10} front={t.accentFace} top={t.accentTop} right={t.accentRight} ink={t.ink} />
      <Cap x={210} y={37} anchor="middle" fill="#F0F1FB" size={9} bold>global control plane</Cap>
      <Stroke pts={[[210, 50], [210, 74]]} seed={seed + 12} weight={1.6} ink={t.ink} />
      <Stroke pts={[[70, 74], [350, 74]]} seed={seed + 14} weight={1.6} ink={t.ink} />
      {regions.map((r, i) => {
        const boxH = HEAD_GAP + (r.tenants.length - 1) * rowH + LABEL_GAP + 16 + BOTTOM_PAD;
        return (
          <g key={r.key}>
            <Stroke pts={[[r.x, 74], [r.x, topY - 6]]} seed={seed + 16 + i} weight={1.4} ink={t.hair} />
            <Face corners={[[r.x - boxW / 2, topY], [r.x + boxW / 2, topY], [r.x + boxW / 2, topY + boxH], [r.x - boxW / 2, topY + boxH]]}
              seed={seed + 20 + i} fill="none" ink={t.hair} weight={1.2} />
            <Cap x={r.x} y={topY + 16} anchor="middle" fill={t.text} size={8} bold>{r.key}</Cap>
            {r.tenants.map((tn, ti) => {
              const y0 = topY + HEAD_GAP + ti * rowH;
              return (
                <g key={tn}>
                  <Cap x={r.x} y={y0} anchor="middle" fill={t.muted} size={7}>{tn}</Cap>
                  <Block x={r.x - 30} y={y0 + LABEL_GAP} w={24} h={16} d={4} seed={seed + 40 + i * 10 + ti} front={t.front} top={t.top} right={t.right} ink={t.ink} />
                  <Block x={r.x + 6} y={y0 + LABEL_GAP} w={24} h={16} d={4} seed={seed + 50 + i * 10 + ti} front={t.front} top={t.top} right={t.right} ink={t.ink} />
                </g>
              );
            })}
            <Cap x={r.x} y={topY + boxH + 16} anchor="middle" fill={t.ok} size={8}>runs independently</Cap>
          </g>
        );
      })}
      <Cap x={210} y={captionY} anchor="middle" fill={t.muted} size={8}>one control plane, many regions, several tenants per region</Cap>
    </svg>
  );
}

/* Mike, 16 Sept, HourPlus call — replaces NoInboundPorts on this section. Donnie, live on the
   call, rejecting the old two-box abstraction: "I don't particularly care for this graphic
   because it doesn't truly represent the real problem... if you were to put an island on the
   left with a bunch of controllers and a bunch of compute nodes, and then on the basalt side you
   had a couple of different regions with hosts going outbound into basalt, it would communicate
   the value proposition a little bit better." He drew exactly that (the reference image Mike
   attached) while still on the call — this is that drawing, redrawn in the site's own hand-drawn
   primitives rather than the flat reference icons.

   Two corrections from the same conversation this also fixes, both from Donnie: the boxes next
   to each site were mislabeled "controller" — "your controller is part of infrastructure... I
   think rather than controller and your infrastructure it should be hypervisor, host, hypervisor
   management" — so each site's own box now reads "Hypervisor," and the thing living outside the
   firewall on each side is the one actually called a controller. And the arrow direction per
   site: "the hypervisor is the thing that initiates the contact... the box that the hypervisor
   runs on is what initiates the connection" — so on the Basalt side, arrows originate at each
   site's own hypervisor and terminate at the controller, not the other way around.

   The left side draws three separate controllers, one per site, with a real gap punched in each
   one's own firewall segment ("you gotta show a hole in the firewall... make a little clearing")
   — the labor-duplication claim (a controller, and a hole, for every site) alongside the security
   one. The right side draws one controller behind one solid, gapless wall, reached by three
   separate outbound-initiated lines — the multi-tenancy claim (Tenant 1/2/3) and the security
   claim (no hole anywhere) on the same drawing, which is exactly what Donnie asked for: "we might
   need to show regionality and tenancy on the same diagram" as the outbound-only one, not two. */
/* Mike, 17 Sept, third pass: "you left-justified the illustration, yet your text is centered...
   double-check that design a little clearer." The first redraw used a 900:320 viewBox — almost
   3:1, wide and short — which meant `width:100%` in the split's own narrower `.rv-illustration-
   wrap` column scaled it down to a small strip pinned to the top of a much taller column, with a
   lot of dead space beneath it: it read as small and stuck in one corner next to a full-height
   StatRow, not as a centered, room-filling drawing. The reference image itself is close to
   square, not a wide banner. Same layout, same elements, same geometry — rows just spread out
   over roughly twice the vertical space (200 units apart instead of 95) so the whole drawing's
   own proportions are closer to that reference and to the column it actually renders in.

   Mike, 17 Sept, fourth pass, on this exact fix: "you didn't label the firewall... you didn't
   center the illustrations on the one with the typical inbound management illustration, that's
   not centered on the text, it still seems to be left-justified." Two real bugs, both on the left
   half only (the right, "Basalt," half was never his complaint): the left group's own content
   spans x=10-240, centered at x=125, but its caption sat at x=170 — 45 units off, which is exactly
   what reads as the drawing sitting left of its own heading. And that content started at x=10, a
   10-unit margin, against the right half's matching 40-unit margin (860 to the 900 edge) — hugging
   the canvas edge is the other half of "left-justified." Both fixed by shifting the whole left
   group +30 (new span 40-270, centered 155, margin 40 to match the right) and moving both left
   captions to that same x=155. The firewall itself — the concept the whole drawing turns on —
   never had its own word in either half; added "Firewall" next to the per-site gap on the left
   and once beside the solid wall on the right. */
function PerSiteControlPlanes({ tone = 'inverse', seed = 1, label, style }) {
  const { Block, Face, Stroke, Cap, Sketch } = DS;
  const { diagramTone } = Sketch;
  const t = diagramTone(tone);
  const rowY = [110, 320, 530];

  return (
    <svg viewBox="0 0 900 700" role={label ? 'img' : 'presentation'} aria-label={label} aria-hidden={label ? undefined : 'true'}
      style={{ width: '100%', height: 'auto', display: 'block', overflow: 'visible', ...style }}>
      {/* ---------------------------------------------------------- left: typical inbound management */}
      <Cap x={155} y={20} anchor="middle" fill={t.text} size={11} bold>Typical inbound management</Cap>
      {/* Mike, on the actual reference (the multi-tenant sketch with the person icons, not the
          single-site one): "there's a firewall around all the incumbent's hypervisor stacks too"
          — the firewall isn't a small token floating between the controller and the site, it's a
          boundary that wraps the whole site cluster, with the controller's own connection as the
          one gap punched in it. Built as four thin hatched bars forming that boundary's perimeter
          (top, right, bottom, and a two-piece left side with the gap the arrow passes through) —
          the same "two Face segments, not one" technique the old floating hole used, just sized
          to actually enclose the block instead of sitting beside it. */}
      {rowY.map((y0, i) => {
        // Mike, 23 Sept: "the 3D cube is 3D, the top and the right side of the bounding box ...
        // is too close." The hypervisor Block below is 3D (d=6) — its top and right FACES extend
        // that far past its own x+w/y, so a box sized only to the front face reads as tight on
        // those two sides specifically even though the front-face margin (left/bottom) looks fine.
        // Widened by the same 6px the block's own depth adds, on the two sides that need it.
        const bx0 = 156, bx1 = 290, by0 = y0 - 24, by1 = y0 + 46, gapTop = y0 + 1, gapBot = y0 + 17;
        return (
        <g key={i}>
          <Block x={40} y={y0} w={64} h={28} d={6} seed={seed + i * 10} front={t.front} top={t.top} right={t.right} ink={t.ink} />
          <Cap x={46} y={y0 + 18} fill={t.text} size={7}>Controller</Cap>
          <Cap x={220} y={y0 - 30} anchor="middle" fill={t.muted} size={7}>Firewall</Cap>
          <Face corners={[[bx0, by0], [bx1, by0], [bx1, by0 + 5], [bx0, by0 + 5]]}
            seed={seed + 100 + i} fill="none" ink={t.ink} weight={1.6} hatchTone={t.hatch} hatchGap={6} />
          <Face corners={[[bx0, by1 - 5], [bx1, by1 - 5], [bx1, by1], [bx0, by1]]}
            seed={seed + 105 + i} fill="none" ink={t.ink} weight={1.6} hatchTone={t.hatch} hatchGap={6} />
          <Face corners={[[bx1 - 5, by0], [bx1, by0], [bx1, by1], [bx1 - 5, by1]]}
            seed={seed + 110 + i} fill="none" ink={t.ink} weight={1.6} hatchTone={t.hatch} hatchGap={6} />
          <Face corners={[[bx0, by0], [bx0 + 5, by0], [bx0 + 5, gapTop], [bx0, gapTop]]}
            seed={seed + 115 + i} fill="none" ink={t.ink} weight={1.6} hatchTone={t.hatch} hatchGap={6} />
          <Face corners={[[bx0, gapBot], [bx0 + 5, gapBot], [bx0 + 5, by1], [bx0, by1]]}
            seed={seed + 120 + i} fill="none" ink={t.ink} weight={1.6} hatchTone={t.hatch} hatchGap={6} />
          <Stroke pts={[[104, y0 + 9], [166, y0 + 9]]} seed={seed + 125 + i} weight={1.6} ink={t.ink} />
          {arrowHead(Stroke, 104, y0 + 9, 170, y0 + 9, 7, seed + 126 + i, t.ink)}
          <Block x={170} y={y0 - 4} w={100} h={36} d={6} seed={seed + 130 + i} front={t.front} top={t.top} right={t.right} ink={t.ink} hatchTone={t.hair} hatchGap={6} />
          <Cap x={178} y={y0 + 10} fill={t.text} size={7} bold>Site {i + 1}</Cap>
          <Cap x={178} y={y0 + 22} fill={t.muted} size={7}>hypervisor</Cap>
        </g>
        );
      })}
      {/* Dylan, 16 Sept, HourPlus call: "I still want to see ... an attacker trying to get through
          that hole in basalt and getting rejected, and I want to see an attacker going through
          the ... hole that's in the typical inbound management as a way to get in." Additive —
          reuses the row-0 gap the legitimate controller arrow already passes through, so the
          attacker demonstrably uses the same hole rather than a drawn-in one of its own.

          Mike, 17 Sept, fifth pass: "your arrow is overlapping... your attacker arrow goes into
          the open port of the firewall, but then overlaps on top of the word site one. All you
          need to do is show the arrow headed towards the open port." The line used to continue
          past the gap to an `inside` point (195, gapY) that sat directly under the "Site 1" label
          (x=178+) — removed that second segment outright, stopping at the port.

          Dylan, 17 Sept, transcript re-audit: "I want to see an attacker rejected at Basalt AND
          an attacker getting in through the hole in typical inbound management" — this side had
          quietly regressed to just an arrow stopping at the gap, indistinguishable from a
          rejection. Only ~9px of clear space exists between the gap (past the firewall's own
          left-wall face at x=161) and the Site block (x=170) — not enough for the old overlapping
          approach — so the "got in" signal is a short stub to x=168 (still clear of the block)
          plus a green ✓, the same device as the Basalt side's ✕, so the two diagrams read as a
          clear pass/fail contrast at a glance.

          Mike/Dylan, 23 Sept call: "attacker x3 — whatever you do on the left, do it for all
          three enclaves." This only ever drew the attacker through row 0's own gap, leaving rows
          1 and 2 looking like the vulnerability was specific to Site 1 rather than a property of
          every separate per-site firewall. Mapped over rowY the same way the site blocks above
          already do, so each of the three gaps gets its own attacker/✓ pair. */}
      {rowY.map((y0, i) => {
        const gapY = (y0 + 1 + y0 + 17) / 2;
        const start = [100, y0 + 90];
        const gapPt = [158, gapY];
        const throughPt = [168, gapY];
        return (
          <g key={i}>
            <Stroke pts={[start, gapPt]} seed={seed + 500 + i * 5} weight={1.6} ink={t.failed} />
            <Stroke pts={[gapPt, throughPt]} seed={seed + 501 + i * 5} weight={1.6} ink={t.failed} />
            {arrowHead(Stroke, gapPt[0], gapPt[1], throughPt[0], throughPt[1], 6, seed + 502 + i * 5, t.failed)}
            <Cap x={throughPt[0] - 2} y={throughPt[1] - 11} anchor="middle" fill={t.ok} size={10} bold>✓</Cap>
            <Cap x={start[0]} y={start[1] + 14} anchor="middle" fill={t.failed} size={7}>Attacker</Cap>
          </g>
        );
      })}
      <Cap x={155} y={650} anchor="middle" fill={t.muted} size={8}>a controller, and its own firewall, for every site</Cap>

      {/* --------------------------------------------------------------------------- right: basalt */}
      {/* Mike, 23 Sept: "why would the word basalt not be on top of the firewall itself?" — the
          wall sits at the horizontal midpoint between the controller's right edge (590) and the
          site blocks' left edge (760), i.e. 675, and the title now shares that exact x so it
          reads directly above the wall instead of floating over open canvas. */}
      <Cap x={675} y={20} anchor="middle" fill={t.accent} size={11} bold>Basalt</Cap>
      <Block x={480} y={300} w={110} h={40} d={7} seed={seed + 200} front={t.accentFace} top={t.accentTop} right={t.accentRight} ink={t.ink} />
      <Cap x={490} y={324} fill="#F0F1FB" size={7} bold>Basalt controller</Cap>
      {/* one solid wall, no gap anywhere — the same segment repeated tall rather than three
          separate walls, since this is one boundary shared by every tenant. */}
      <Face corners={[[667, 60], [683, 60], [683, 610], [667, 610]]}
        seed={seed + 300} fill="none" ink={t.ink} weight={1.8} hatchTone={t.hatch} hatchGap={7} />
      <Cap x={675} y={50} anchor="middle" fill={t.muted} size={7}>Firewall</Cap>
      {/* Mike, on the reference image: the three tenant lines have to converge at one point ON
          the wall, not just at a shared point past it — every line previously ended at the same
          (600, 320) controller-side point, but since that point sits to the left of the wall
          (now x=667-683, recentered under the "Basalt" title), each line was still at its own
          height while it actually crossed the wall band, which read as three separate holes
          punched through it. gatePt is the wall's own center (675 horizontal, 335 vertical — the
          wall spans 60 to 610), so every line meets at the exact same pixel while passing through
          it; one shared line then carries on from there into the controller. */}
      {(() => { const gatePt = [675, 335]; return (<>
        {rowY.map((y0, i) => (
          <g key={i}>
            <Block x={760} y={y0 - 4} w={100} h={36} d={6} seed={seed + 400 + i * 10} front={t.front} top={t.top} right={t.right} ink={t.ink} hatchTone={t.hair} hatchGap={6} />
            <Cap x={768} y={y0 + 10} fill={t.text} size={7} bold>Site {i + 1}</Cap>
            <Cap x={768} y={y0 + 22} fill={t.muted} size={7}>hypervisor</Cap>
            {/* arrow originates at the site's own hypervisor and converges on the wall's own
                center — the host initiates, per Donnie's own correction, not the other way
                around. No arrowhead here; the shared segment past the wall carries the one. */}
            <Stroke pts={[[758, y0 + 12], gatePt]} seed={seed + 410 + i} weight={1.4} ink={t.ink} />
            {/* Mike, 23 Sept: "the tenant one, tenant two, and tenant three ... you can't read the
                whole text because it's on the line." The connecting line above departs from a
                point right next to this label's own x (758 vs. the label's 768) at a y that, for
                the outer two rows, sits within ~20-40px of the label's own y — close enough for
                the line's hand-drawn wobble to cross the text. Pushed further right and further
                down, clear of that departure point on every row, not just the one that visibly
                overlapped. */}
            <Cap x={786} y={y0 + 42} fill={t.muted} size={7}>Tenant {i + 1}</Cap>
          </g>
        ))}
        <Stroke pts={[gatePt, [600, 320]]} seed={seed + 450} weight={1.4} ink={t.ink} />
        {arrowHead(Stroke, gatePt[0], gatePt[1], 600, 320, 7, seed + 451, t.ink)}
      </>); })()}
      {/* Mike, 17 Sept, eighth pass: "you have the attacker trying to go through the basalt
          controller — that's not how it works, it tries to go through the firewall. Have it try
          and enter under the basalt controller and ping off and down." The controller block
          (x=480-590, y=300-340) is not itself the thing being probed — the labeled "Firewall"
          (the Face at x=650-666, spanning the full 60-610 height) is. So the attacker approaches
          from the left, but travels at y=420 — comfortably under the controller's own y-range,
          not through it — the whole way to the firewall, hits it at a point well below where the
          legitimate controller/tenant traffic crosses (gatePt sits at y=335; this hits at y=420,
          clear of that convergence and of Site 3's own line, which only touches x=658 at gatePt
          itself before diverging away), then pings off down and left at a clearly different
          angle.

          Ninth pass, same day: "the horizontal line is too long, it should be about half the
          length... have it start directly under the purple basalt controller, as far out as the
          left side of that box." Moved the start point from the open canvas at x=335 to x=480 —
          the controller block's own left edge — roughly halving the approach line (178px vs the
          old 323px) and anchoring it visually to the controller it's passing under, rather than
          floating in the gap between the two diagrams. hitPt's x tracks the wall's own recentered
          x (675) so the attacker still visibly hits the wall itself, not open space beside it. */}
      {(() => {
        const start = [480, 420];
        const hitPt = [675, 420];
        const bounce = [600, 500];
        return (
          <g>
            <Stroke pts={[start, hitPt]} seed={seed + 460} weight={1.6} ink={t.failed} />
            {arrowHead(Stroke, start[0], start[1], hitPt[0], hitPt[1], 6, seed + 461, t.failed)}
            <Cap x={hitPt[0]} y={hitPt[1] - 16} anchor="middle" fill={t.failed} size={10} bold>✕</Cap>
            <Stroke pts={[hitPt, bounce]} seed={seed + 462} weight={1.6} ink={t.failed} />
            {arrowHead(Stroke, hitPt[0], hitPt[1], bounce[0], bounce[1], 6, seed + 463, t.failed)}
            <Cap x={start[0]} y={start[1] + 16} anchor="middle" fill={t.failed} size={7}>Attacker</Cap>
          </g>
        );
      })()}
      <Cap x={730} y={650} anchor="middle" fill={t.muted} size={8}>every site reaches out through one solid wall: no hole, no exception</Cap>
    </svg>
  );
}

/* ---------------------------------------------------------- DB — Platform overview architecture */

/* PlatformArchitectureDiagram — replaces HostStack (a generic design-system stock diagram) in
   PlatformArchitecture (pages.jsx, Section DB). Dylan, 17 Sept: "the diagram model is a little
   too generic... there's nothing about the diagram model that says this is how we do things...
   section three and four of the control plane and agent model are not clear. Even claim two,
   native hyperconvergence — hyperconvergence means you don't have to have a separate storage
   appliance, you can just run a computer with basalt on it." Four specific claims, drawn
   concretely instead of as a generic hypervisor-with-guests picture: one host runs compute and
   storage together with no separate storage appliance beside it — drawn as an explicit, crossed-
   out absent box rather than just leaving one out, the same "thing that never happens" idiom
   DataCustody already uses; one global control plane reaches that host, captioned with region
   independence; the host's own agent has a single outbound-only arrow, no inbound one; and the
   four domains (compute, storage, networking, governance) are labeled as one list inside the one
   host block, not as four separate boxes. Not wired into pages.jsx from here — PlatformArchitecture
   there still calls HostStack directly, with its own TODO marking this as the intended swap for a
   separate pass to make. */
function PlatformArchitectureDiagram({ tone = 'inverse', seed = 1, label, style }) {
  const { Block, Face, Stroke, Cap, Sketch } = DS;
  const { diagramTone } = Sketch;
  const t = diagramTone(tone);
  const hostX = 90, hostY = 120, hostW = 180, hostH = 160;
  const hostCx = hostX + hostW / 2;
  const domains = ['compute', 'storage', 'networking', 'governance'];
  const domainX0 = hostX + 24, domainY0 = 166, domainGap = 28;
  const ghostX = 300, ghostY = 140, ghostW = 100, ghostH = 100;
  return (
    <svg viewBox="0 0 440 320" role={label ? 'img' : 'presentation'} aria-label={label} aria-hidden={label ? undefined : 'true'}
      style={{ width: '100%', height: 'auto', display: 'block', overflow: 'visible', ...style }}>
      {/* one global control plane, reaching this host — regions still run independently under it */}
      <Block x={hostCx - 75} y={16} w={150} h={32} d={7} seed={seed} front={t.accentFace} top={t.accentTop} right={t.accentRight} ink={t.ink} />
      <Cap x={hostCx} y={37} anchor="middle" fill="#F0F1FB" size={8} bold>global control plane</Cap>
      <Cap x={hostCx} y={60} anchor="middle" fill={t.muted} size={7}>one control plane: each region still runs independently</Cap>

      {/* the host's own agent: a single arrow out, none in */}
      <Stroke pts={[[hostCx, hostY - 4], [hostCx, 68]]} seed={seed + 10} weight={1.6} ink={t.accent} />
      {arrowHead(Stroke, hostCx, hostY - 4, hostCx, 68, 7, seed + 11, t.accent)}
      <Cap x={hostCx + 8} y={95} fill={t.muted} size={7}>agent: outbound only</Cap>

      {/* one host, running compute and storage together — nothing bolted on beside it */}
      <Block x={hostX} y={hostY} w={hostW} h={hostH} d={9} seed={seed + 20} front={t.front} top={t.top} right={t.right} ink={t.ink} />
      <Cap x={hostX + 14} y={hostY + 24} fill={t.text} size={8} bold>one Basalt host</Cap>
      <Stroke pts={[[hostX + 12, hostY + 34], [hostX + hostW - 22, hostY + 34]]} seed={seed + 21} weight={1} ink={t.hair} />
      {domains.map((d, i) => (
        <g key={d}>
          <Face corners={[[domainX0, domainY0 + i * domainGap - 6], [domainX0 + 6, domainY0 + i * domainGap - 6], [domainX0 + 6, domainY0 + i * domainGap], [domainX0, domainY0 + i * domainGap]]}
            seed={seed + 30 + i} fill={t.accent} ink={t.accent} weight={0} />
          <Cap x={domainX0 + 14} y={domainY0 + i * domainGap} fill={t.text} size={7}>{d}</Cap>
        </g>
      ))}
      <Cap x={hostCx} y={hostY + hostH + 18} anchor="middle" fill={t.muted} size={7}>one architecture, one host: not four separate boxes</Cap>

      {/* the thing that never exists — a separate storage appliance, drawn to make the absence
          explicit rather than just leaving it out. */}
      <Face corners={[[ghostX, ghostY], [ghostX + ghostW, ghostY], [ghostX + ghostW, ghostY + ghostH], [ghostX, ghostY + ghostH]]}
        seed={seed + 40} fill="none" ink={t.hair} weight={1.2} hatchTone={t.hatch} hatchGap={8} />
      <Cap x={ghostX + ghostW / 2} y={ghostY - 8} anchor="middle" fill={t.muted} size={7}>separate storage appliance</Cap>
      <Cap x={ghostX + ghostW / 2} y={ghostY + ghostH / 2 + 6} anchor="middle" fill={t.failed} size={16} bold>✕</Cap>
      <Cap x={ghostX + ghostW / 2} y={ghostY + ghostH + 18} anchor="middle" fill={t.muted} size={7}>no separate box to manage</Cap>
    </svg>
  );
}

/* ------------------------------------------------------------------- BE — migration */

/* StagedMigration — replaces MigrationArc on the homepage. MigrationArc itself is untouched: if
   live migration turns out to be a real, approved claim, it still belongs on the Migration &
   evaluation page (see review.jsx's own suggestion). This is the sketch Dylan sent: stand up
   alongside, validate side by side, migrate in stages — not a live-migration animation. */
function StagedMigration({ tone = 'paper', seed = 1, label, style }) {
  const { Block, Stroke, Cap, Sketch } = DS;
  const { diagramTone } = Sketch;
  const t = diagramTone(tone);
  const panel = (x, title, sub, children) => (
    <g>
      <Cap x={x} y={16} fill={t.text} size={9} bold>{title}</Cap>
      {children}
      <Cap x={x} y={168} fill={t.muted} size={8}>{sub}</Cap>
    </g>
  );
  const cluster = (x, accent2) => (
    <g>
      <Block x={x} y={40} w={44} h={22} d={6} seed={seed + x} front={t.front} top={t.top} right={t.right} ink={t.ink} />
      <Block x={x} y={68} w={44} h={22} d={6} seed={seed + x + 3} front={t.front} top={t.top} right={t.right} ink={t.ink} />
      <Block x={x + 56} y={40} w={44} h={22} d={6} seed={seed + x + 6}
        front={accent2 ? t.accentFace : t.front} top={accent2 ? t.accentTop : t.top} right={accent2 ? t.accentRight : t.right} ink={t.ink} />
      <Block x={x + 56} y={68} w={44} h={22} d={6} seed={seed + x + 9}
        front={accent2 ? t.accentFace : t.front} top={accent2 ? t.accentTop : t.top} right={accent2 ? t.accentRight : t.right} ink={t.ink} />
    </g>
  );
  return (
    <svg viewBox="0 0 420 190" role={label ? 'img' : 'presentation'} aria-label={label} aria-hidden={label ? undefined : 'true'}
      style={{ width: '100%', height: 'auto', display: 'block', overflow: 'visible', ...style }}>
      {panel(4, 'Stand up alongside', 'Stands up next to what you run', cluster(4, true))}

      <Stroke pts={[[112, 66], [136, 66]]} seed={seed + 60} weight={1.6} ink={t.hair} />
      <Stroke pts={[[130, 60], [136, 66], [130, 72]]} seed={seed + 61} weight={1.6} ink={t.hair} />

      {panel(146, 'Validate side by side', 'Test before moving production', cluster(146, true))}
      {/* Mike, 15 Sept — Triq V2 walkthrough: "I'd like the check mark to be more prominent...
          I'm assuming you want our gut-level reaction — I look at this picture for a second,
          I lost the check mark there. That's why you looked at it for a few seconds." A small
          checkmark floating above-right of the panel didn't read as marking anything specific.
          A solid badge stamped right on the corner of the purple (accent) blocks — the ones this
          step is actually validating, per cluster(146, true) above — makes the association
          impossible to miss instead of asking a reader to infer it. */}
      {/* Mike, 16 Sept review: "the end of your check mark goes to the edge of the circle" — the
          long leg's own tip sat at distance ~12.7 from center, plus half the 2.6-weight stroke,
          landing right on the r=14 edge instead of inside it. Scaled the same checkmark shape
          down (~0.75x) so its farthest point clears the edge with real margin instead of kissing
          it. */}
      <circle cx={250} cy={40} r={14} fill={t.ok} />
      <Stroke pts={[[245, 40], [248, 45], [257, 33]]} seed={seed + 70} weight={2.6} ink="#fff" />

      <Stroke pts={[[254, 66], [278, 66]]} seed={seed + 80} weight={1.6} ink={t.hair} />
      <Stroke pts={[[272, 60], [278, 66], [272, 72]]} seed={seed + 81} weight={1.6} ink={t.hair} />

      {panel(288, 'Migrate in stages', 'Move when ready', (
        <g>
          <Block x={288} y={40} w={30} h={20} d={5} seed={seed + 90} front={t.front} top={t.top} right={t.right} ink={t.ink} />
          <Stroke pts={[[320, 50], [336, 50]]} seed={seed + 91} weight={1.4} ink={t.hair} />
          <Stroke pts={[[330, 46], [336, 50], [330, 54]]} seed={seed + 92} weight={1.4} ink={t.hair} />
          <Block x={340} y={40} w={30} h={20} d={5} seed={seed + 93} front={t.accentFace} top={t.accentTop} right={t.accentRight} ink={t.ink} />
          <Block x={288} y={68} w={30} h={20} d={5} seed={seed + 94} front={t.front} top={t.top} right={t.right} ink={t.ink} />
          <Stroke pts={[[320, 78], [336, 78]]} seed={seed + 95} weight={1.4} ink={t.hair} />
          <Stroke pts={[[330, 74], [336, 78], [330, 82]]} seed={seed + 96} weight={1.4} ink={t.hair} />
          <Block x={340} y={68} w={30} h={20} d={5} seed={seed + 97} front={t.accentFace} top={t.accentTop} right={t.accentRight} ink={t.ink} />
        </g>
      ))}
    </svg>
  );
}

/* -------------------------------------------------------------------- Compare pages — parity */

/* VirtualizationParity — Mike, wide-monitor review: every Compare page needs its own
   illustration, showing that Basalt does the same commodity job as the competitor — the same
   way, when both actually sit on the open-source KVM hypervisor (Proxmox, Nutanix's AHV, Scale
   Computing's HC3 and HPE's own VM Essentials all publicly document this themselves), or a
   different way that still lands at the same outcome (VMware's own ESXi kernel, Microsoft's
   Hyper-V — neither is KVM). This only draws what each vendor's own documentation already says
   the core actually is; it makes no claim about which migration is easier, which is the part
   review.jsx's own RB/PC notes flag as not yet confirmed. One component, six call sites, so the
   comparison reads identically everywhere instead of six hand-drawn variants. */
function VirtualizationParity({ tone = 'inverse', seed = 1, label, competitor, competitorCore, sameCore, note, style }) {
  const { Block, Face, Stroke, Cap, Sketch } = DS;
  const { diagramTone } = Sketch;
  const t = diagramTone(tone);
  const colA = 16, colB = 284, colW = 120;
  const coreY = 40, coreH = 40, vmY = 126, vmH = 46;
  const vmRow = (x) => {
    const innerW = (colW - 16) / 2 - 4;
    const innerH = vmH - 16;
    return (
      <g>
        <Face corners={[[x, vmY], [x + colW, vmY], [x + colW, vmY + vmH], [x, vmY + vmH]]}
          seed={seed + x + 300} fill="none" ink={t.hair} weight={1.2} />
        {vmBars(Face, x + 8, vmY + 8, innerW, innerH, seed + x + 320, t.ink)}
        {vmBars(Face, x + colW / 2 + 4, vmY + 8, innerW, innerH, seed + x + 340, t.ink)}
      </g>
    );
  };
  return (
    <svg viewBox="0 0 420 210" role={label ? 'img' : 'presentation'} aria-label={label} aria-hidden={label ? undefined : 'true'}
      style={{ width: '100%', height: 'auto', display: 'block', overflow: 'visible', ...style }}>
      <Cap x={colA} y={16} fill={t.muted} size={8}>{competitor}</Cap>
      <Block x={colA} y={coreY} w={colW} h={coreH} d={6} seed={seed} front={t.front} top={t.top} right={t.right} ink={t.ink} />
      <Cap x={colA + 10} y={coreY + 24} fill={t.text} size={8} bold>{competitorCore}</Cap>

      <Cap x={colB} y={16} fill={t.muted} size={8}>basalt</Cap>
      <Block x={colB} y={coreY} w={colW} h={coreH} d={6} seed={seed + 20} front={t.accentFace} top={t.accentTop} right={t.accentRight} ink={t.ink} />
      <Cap x={colB + 10} y={coreY + 24} fill="#F0F1FB" size={8} bold>KVM + Rust</Cap>

      {sameCore && (
        <g>
          <Stroke pts={[[colA + colW, coreY + coreH / 2], [colB, coreY + coreH / 2]]} seed={seed + 60} weight={1.4} ink={t.ok} />
          <Cap x={210} y={coreY + coreH / 2 - 8} anchor="middle" fill={t.ok} size={7}>both open-source KVM</Cap>
        </g>
      )}

      <Stroke pts={[[colA + 30, coreY + coreH], [colA + 30, vmY]]} seed={seed + 70} weight={1.4} ink={t.hair} />
      {arrowHead(Stroke, colA + 30, coreY + coreH, colA + 30, vmY, 7, seed + 71, t.hair)}
      <Stroke pts={[[colB + 30, coreY + coreH], [colB + 30, vmY]]} seed={seed + 72} weight={1.4} ink={t.hair} />
      {arrowHead(Stroke, colB + 30, coreY + coreH, colB + 30, vmY, 7, seed + 73, t.hair)}

      {vmRow(colA)}
      {vmRow(colB)}
      <Cap x={colA} y={vmY + vmH + 16} fill={t.muted} size={7}>vms, isolated</Cap>
      <Cap x={colB} y={vmY + vmH + 16} fill={t.muted} size={7}>vms, isolated</Cap>

      <Stroke pts={[[colA + colW, vmY + vmH / 2], [colB, vmY + vmH / 2]]} seed={seed + 80} weight={1.4} ink={t.accent} />
      <Cap x={210} y={vmY + vmH / 2 + 22} anchor="middle" fill={t.muted} size={7}>same commodity job either way</Cap>

      {note && <Cap x={210} y={202} anchor="middle" fill={t.muted} size={7}>{note}</Cap>}
    </svg>
  );
}

/* ---------------------------------------------------------------- KB — Federal / DDIL edge */

/* DdilResilience — rebuilt from Mike's own drawing (KBV, 23 Sept HourPlus call, live-walkthrough
   correction). The prior version drew the edge site and the control plane side by side with a
   horizontal arrow between them, which is exactly what Dylan spent several minutes on the call
   unwinding: "the control plane should probably be above the edge site... the edge site can see
   the control plane... it's not moving in the same direction as time, it's like a cartoon panel."
   His own sketch is a cloud (management) sitting above a box (the edge site), with only the
   connector between them changing per panel — normal (connected both ways), degraded (severed,
   edge keeps running on its own), reconnected (connected again, and synced). The edge box itself
   never changes state across the three panels, matching his correction: "this box stays green the
   entire time because it's operating... your blue box, it's fine." The "Recovery is easier" line
   is his own closing point on the call — recovering from a dropped link is simpler with Basalt
   than the admin work an ordinary vCenter-managed cluster requires once its own controller comes
   back, so it's stated directly rather than left implied by the three panels alone. */
function DdilResilience({ tone = 'inverse', seed = 1, label, style }) {
  const { Block, Face, Stroke, Cap, Sketch } = DS;
  const { diagramTone } = Sketch;
  const t = diagramTone(tone);

  /* Mike, 24 Sept: "your cloud icon, I think, is just a little bit too large, and it's also not
     hand-drawn. Why is that icon not hand-drawn yet? Everything else is hand-drawn." The prior
     pass fixed the cloud's proportions but left it as a plain smooth SVG <path> — the only shape
     in this entire file not built from the Stroke primitive, so it alone had no hand-wobble.
     First attempt traced it as a 12-point polygon; Mike, same day, on that result: "now that
     they're hand-drawn, they look goofy" — a dozen hand-picked vertices read as sharp corners
     once wobbled, not a rounded cloud. Rebuilt by sampling the ORIGINAL bezier curve's own six
     segments (via cubicPts, 6-7 points each) at ~68% of its former size, so the silhouette stays
     smooth while Stroke's jitter still gives it a sketched texture rather than a polygon's. */
  const CLOUD_SEG = [
    [[8.84, 26.52], [3.54, 26.52], [0, 22.98], [0, 17.68]],
    [[0, 17.68], [0, 13.26], [3.54, 9.72], [7.96, 8.84]],
    [[7.96, 8.84], [8.84, 3.54], [14.14, 0], [20.33, 0]],
    [[20.33, 0], [25.64, 0], [30.06, 2.65], [31.82, 7.07]],
    [[31.82, 7.07], [37.13, 7.07], [41.55, 11.49], [41.55, 16.80]],
    [[41.55, 16.80], [41.55, 22.10], [37.13, 26.52], [31.82, 26.52]],
  ];
  const cloudPts = CLOUD_SEG.flatMap(([p0, c1, c2, p1], i) => cubicPts(p0, c1, c2, p1, 6).slice(i === 0 ? 0 : 1))
    .concat([[8.84, 26.52]]);
  const cloud = (cx, cy) => (
    <Stroke pts={cloudPts.map(([px, py]) => [px + cx - 20.8, py + cy - 24])}
      seed={seed + cx + cy} weight={1.4} ink={t.ink} />
  );

  const edgeSite = (cx, cy) => (
    <g>
      <Block x={cx - 22} y={cy} w={44} h={30} d={6} seed={seed + cx}
        front={t.accentFace} top={t.accentTop} right={t.accentRight} ink={t.ink} />
      <Cap x={cx} y={cy + 18} anchor="middle" fill="#F0F1FB" size={7} bold>edge site</Cap>
      {/* Always-present check — the site is never in a bad state in any of the three panels,
          only its link to the cloud above changes. */}
      <circle cx={cx + 26} cy={cy - 6} r={9} fill={t.ok} />
      <Stroke pts={[[cx + 22, cy - 6], [cx + 25, cy - 2], [cx + 32, cy - 12]]} seed={seed + cx + 1} weight={1.8} ink="#fff" />
    </g>
  );

  /* Mike, 23 Sept: "the word management is up against the edge of the cloud icon" and "your arrows
     ... are behind the boxes, they're too low, they're not centered." Regrounded the whole panel's
     vertical rhythm off the bigger cloud above (cy 55 now, was 44) so "management" clears its
     bottom edge with real room instead of sitting on it; the edge-site block moved down to match
     (cy 100, was 92) so the connector between them actually spans the visual gap end-to-end
     instead of stopping short partway down it; and {connector} now renders AFTER {edgeSite}, not
     before, so its arrowhead paints on top of the block's own edge rather than underneath it.

     Mike, 24 Sept: "lower [the edge site boxes] a little bit and give a little bit of space
     between the... lines and arrows [and the box]." Moved the box down again (cy 112) and left
     the connector's own tip short of it (104, not 100) instead of nearly touching, so there is
     real air between the arrowhead and the block it points at. */
  const panel = (cx, title, sub, connector) => (
    <g>
      <Cap x={cx} y={14} anchor="middle" fill={t.text} size={9} bold>{title}</Cap>
      {cloud(cx, 55)}
      <Cap x={cx} y={71} anchor="middle" fill={t.muted} size={6}>management</Cap>
      {edgeSite(cx, 112)}
      {connector}
      <Cap x={cx} y={158} anchor="middle" fill={t.muted} size={8}>{sub}</Cap>
    </g>
  );

  const connectedLink = (cx, color) => (
    <g>
      <Stroke pts={[[cx, 77], [cx, 104]]} seed={seed + cx + 10} weight={1.6} ink={color} />
      {arrowHead(Stroke, cx, 104, cx, 77, 6, seed + cx + 11, color)}
      {arrowHead(Stroke, cx, 77, cx, 104, 6, seed + cx + 12, color)}
    </g>
  );

  const cx1 = 70, cx2 = 210, cx3 = 350;

  return (
    <svg viewBox="0 0 420 250" role={label ? 'img' : 'presentation'} aria-label={label} aria-hidden={label ? undefined : 'true'}
      style={{ width: '100%', height: 'auto', display: 'block', overflow: 'visible', ...style }}>
      {/* Mike, 23 Sept: "I want that [Recovery is easier] to be above the illustration, at the
          top." Moved from below the three panels to a boxed banner above them; the panels
          themselves are unchanged internally, just shifted down 44px as a group to make room. */}
      <Face corners={[[130, 6], [290, 6], [290, 32], [130, 32]]} seed={seed + 90} fill="none" ink={t.accent} weight={1.4} />
      <Cap x={210} y={23} anchor="middle" fill={t.accent} size={9} bold>Recovery is easier</Cap>

      <g transform="translate(0, 44)">
        {panel(cx1, 'Connected', 'Normal operation', connectedLink(cx1, t.ok))}

        {/* Dylan, 23 Sept: "in the connected state, things are normal. When your network is broken,
            your infrastructure is not broken... this box stays green the entire time." The link
            itself severs (dashed + ✕); the edge site's own box and check are untouched — the same
            edgeSite() call as every other panel, not a degraded variant of it. */}
        {panel(cx2, 'Management link unavailable', 'Workloads keep running', (
          <g>
            <line x1={cx2} y1={77} x2={cx2} y2={104} stroke={t.failed} strokeWidth={1.6} strokeDasharray="4 4" />
            <Cap x={cx2} y={90} anchor="middle" fill={t.failed} size={11} bold>✕</Cap>
          </g>
        ))}

        {/* Reconnected — the same two-way link as "Connected," plus a small synced badge, since the
            claim here (Dylan, 23 Sept: "basalt fixes itself... we do all that automatically") is
            specifically that resync needs no admin action, not just that the link came back.
            Mike, 24 Sept: "move the word synced down to the right of the green check mark." The
            always-present check now sits at (cx+26, 106) with r=9 (edge site cy 112), so "synced"
            moved down to sit beside it at the same height, clear of the circle's own right edge
            (cx+35), instead of floating above near the cloud. */}
        {panel(cx3, 'Reconnected', 'Central management resumes', (
          <g>
            {connectedLink(cx3, t.ok)}
            <Cap x={cx3 + 38} y={109} fill={t.ok} size={7} bold>synced</Cap>
          </g>
        ))}
      </g>

      {/* Dylan, 17 Sept (earlier pass): "the story it's trying to tell of a sequence of events is
          not clear" — the time axis that turns three snapshots into one sequence, kept from the
          prior version. No vertical divider between panels: Mike, 23 Sept, reversed himself on
          this explicitly on the call ("don't do the vertical line... no, no, no, don't do it") — a
          single shared time axis is the only cross-panel line this illustration should carry. */}
      <Stroke pts={[[4, 230], [410, 230]]} seed={seed + 91} weight={1.2} ink={t.hair} />
      {arrowHead(Stroke, 4, 230, 410, 230, 7, seed + 92, t.hair)}
      <Cap x={210} y={244} anchor="middle" fill={t.muted} size={7}>time →</Cap>
    </svg>
  );
}

/* ------------------------------------------------------------------- LB — remote and resilient edge */

/* RestartClassHA — see DdilResilience above for why this exists and what it deliberately does
   not claim. Draws exactly what the page's own copy states: synchronous replication, a restart
   on the surviving node rather than a hot-standby failover, and nothing about server count or an
   external witness — that specific architecture claim is still open per review.jsx's own LB
   note.

   Mike, 23 Sept, re-viewing his own reference (IMG_0037, LBV): "we gave you a very specific
   illustration to follow, and you did not do that... I have no idea why you did that." The prior
   version drew two separate 3D cubes per panel with a connecting arrow between them; his own
   drawing is ONE box per panel, split into an A half and a B half by a single internal vertical
   line — the physical pair of servers never separates or reconnects, only which half is purple
   (primary, holding the workload) and which is grey (standby) changes. Rebuilt from a single
   Face-built rectangle per panel instead of two Blocks, with the same purple/grey swap sequence
   Dylan specified ("purple, grey" running → "grey, purple" failed over → "purple, grey" restarted)
   now carried by the two halves of one box rather than by which of two boxes is filled in. Also
   added the time axis Mike asked for on the same call ("there's a timeline... same horizontal
   axis that says time" as DdilResilience's own), which this diagram never had. */
function RestartClassHA({ tone = 'inverse', seed = 1, label, style }) {
  const { Face, Stroke, Cap, Sketch } = DS;
  const { diagramTone } = Sketch;
  const t = diagramTone(tone);
  /* Mike, 25 Sept call: "I don't like these arrows pointing up at it, I'm gonna have it remove
     those." Dylan, same breath: "maybe drop it closer to time." The up-arrows below each box are
     gone outright (not replaced), and boxY moved down (40 -> 70) so the panels sit closer to the
     time axis instead of floating in the space the arrows used to occupy. */
  const boxY = 70, boxH = 34, boxW = 80;

  const splitBox = (x, aActive, bActive, seedBase) => {
    const midX = x + boxW / 2;
    return (
      <g>
        <Face corners={[[x, boxY], [midX, boxY], [midX, boxY + boxH], [x, boxY + boxH]]}
          seed={seedBase} fill={aActive ? t.accentFace : t.front} ink={t.ink} weight={1.6} />
        <Face corners={[[midX, boxY], [x + boxW, boxY], [x + boxW, boxY + boxH], [midX, boxY + boxH]]}
          seed={seedBase + 1} fill={bActive ? t.accentFace : t.front} ink={t.ink} weight={1.6} />
        <Cap x={x + boxW * 0.25} y={boxY + boxH / 2 + 3} anchor="middle" fill={aActive ? '#F0F1FB' : t.text} size={7} bold>node a</Cap>
        <Cap x={x + boxW * 0.75} y={boxY + boxH / 2 + 3} anchor="middle" fill={bActive ? '#F0F1FB' : t.text} size={7} bold>node b</Cap>
      </g>
    );
  };

  const panel = (x, title, sub, aActive, bActive, mark, seedBase) => (
    <g>
      <Cap x={x} y={16} fill={t.text} size={9} bold>{title}</Cap>
      {mark && (
        <Cap x={x + boxW * 0.25} y={boxY - 8} anchor="middle" fill={mark === '✕' ? t.failed : t.ok} size={12} bold>{mark}</Cap>
      )}
      {splitBox(x, aActive, bActive, seedBase)}
      <Cap x={x} y={boxY + boxH + 16} fill={t.muted} size={8}>{sub}</Cap>
    </g>
  );

  return (
    <svg viewBox="0 0 420 176" role={label ? 'img' : 'presentation'} aria-label={label} aria-hidden={label ? undefined : 'true'}
      style={{ width: '100%', height: 'auto', display: 'block', overflow: 'visible', ...style }}>
      {panel(4, 'Running', 'Synchronous replication', true, false, null, seed)}

      {/* Mike's own sketch (LBV, 23 Sept): "purple, grey, grey, purple" across the three panels —
          the color is the state, not a label to print. Failover means B becomes primary; the ✕
          sits over node a specifically, the half that just failed. */}
      {panel(152, 'Node fails', 'B takes ownership', false, true, '✕', seed + 30)}

      {/* Restarts = failback, not a new steady state. Dylan, 23 Sept, explicit on both the color
          and the direction: "it failed back over to node A... purple, and then a green check
          mark, and then B goes back to gray." A returns to purple/primary with its workload, B
          drops back to grey/standby — the same single box, just swapped back. */}
      {panel(300, 'Restarts', 'Restart-class, not lockstep', true, false, '✓', seed + 60)}

      {/* Mike, 23 Sept: "there is a timeline, sort of like our tactical and DDIL illustration...
          that same horizontal axis that says time." Matches DdilResilience's own axis exactly.
          Mike, 25 Sept, on the live result: "the 'time' line should be closer, right?" — moved up
          from y=196 (viewBox 220 tall) to y=148 (viewBox shrunk to 176) so it sits right under the
          sub-captions instead of floating in leftover space the arrows used to fill. */}
      <Stroke pts={[[4, 148], [410, 148]]} seed={seed + 91} weight={1.2} ink={t.hair} />
      {arrowHead(Stroke, 4, 148, 410, 148, 7, seed + 92, t.hair)}
      <Cap x={210} y={162} anchor="middle" fill={t.muted} size={7}>time →</Cap>
    </svg>
  );
}

/* ------------------------------------------------------------------ FB — Pricing & licensing */

/* Mike, 14 Sept: "Section FB on the pricing and licensing page should obviously have an
   illustration." The one claim that section makes — per-core pricing climbs as the estate grows,
   Basalt's own flat rate doesn't — is a line chart, not a hardware drawing, so this reuses the
   same Stroke/Cap primitives every other diagram here does rather than forcing a Block-based
   scene onto a concept that's really just two lines on an axis. The staircase's own step count is
   illustrative, not plotted from a real pricing table — it draws the SHAPE of metered-per-core
   pricing (it climbs in steps as more is added), not a specific vendor's actual curve. */
/* Mike, 16 Sept review: "your graph doesn't make any sense... you have basalt starting above
   the first step. Basalt is way underneath the first step, and it doesn't move up." SVG y grows
   downward, so a smaller y is HIGHER on the chart (more cost) — the flat line used to sit at
   y=166, above (in y-terms, below in value) the staircase's own lowest step at y=174, reading as
   MORE expensive than the cheapest point of per-core licensing, backwards from the claim. The
   flat line now sits close to the x-axis (y=182, cheap, unmoving) and the whole staircase is
   redrawn above it with real separation at every step, not just the first. Also moved the
   "annual cost" axis label from floating well left of the axis line it's supposed to name (old
   x=14 against the line's own x0=50) to sitting directly above that line instead — unambiguous
   about which line it labels, matching how the x-axis label already sits under its own line. */
function FlatVsMetered({ tone = 'paper', seed = 1, label, style }) {
  const { Stroke, Cap, Sketch } = DS;
  const { diagramTone } = Sketch;
  const t = diagramTone(tone);
  const x0 = 50, x1 = 400, yBase = 190, yTop = 20;
  const steps = [[60, 160], [140, 160], [140, 130], [220, 130], [220, 95], [300, 95], [300, 55], [380, 55]];
  const basaltY = 182;
  return (
    <svg viewBox="0 0 440 220" role={label ? 'img' : 'presentation'} aria-label={label} aria-hidden={label ? undefined : 'true'}
      style={{ width: '100%', height: 'auto', display: 'block', overflow: 'visible', ...style }}>
      <Stroke pts={[[x0, yTop], [x0, yBase]]} seed={seed} weight={1.6} ink={t.hair} />
      <Stroke pts={[[x0, yBase], [x1, yBase]]} seed={seed + 1} weight={1.6} ink={t.hair} />
      <Cap x={x0} y={yTop - 8} fill={t.muted} size={8}>annual cost</Cap>
      <Cap x={x1} y={yBase + 20} anchor="end" fill={t.muted} size={8}>more infrastructure, over time</Cap>

      <Stroke pts={steps} seed={seed + 2} weight={1.8} ink={t.muted} />
      <Cap x={382} y={49} fill={t.muted} size={8}>per-core licensing</Cap>

      <Stroke pts={[[60, basaltY], [380, basaltY]]} seed={seed + 3} weight={2.4} ink={t.accent} />
      <Cap x={382} y={basaltY - 4} fill={t.accent} size={8} bold>Basalt: flat</Cap>
    </svg>
  );
}

/* ------------------------------------------------------------- PB — VMware control-plane diagram */

/* Mike, 15 Sept — Triq V2 walkthrough. Donnie/Luigi were specific that the old VirtualizationParity
   drawing (same-core-different-kernel) understates the real architectural gap with VMware: "the
   big practical difference... is the fact that they have a control plane right next to every
   cluster, and they have to — they don't have an option." "This diagram has to capture the essence
   of distributed management complexity... a single basalt control plane, all of your clusters and
   hosts" (Luigi). Left: three clusters, each with its OWN vCenter stacked directly on top of it —
   the repetition is the point, not a coincidence of layout. Right: one basalt control plane, one
   set of diverging lines reaching three clusters at once. Used only on the VMware Compare page —
   the other five keep VirtualizationParity's same-or-different-kernel comparison, which is the
   actual question on those pages; VMware's is a control-plane question instead. */
function ControlPlaneComparison({ tone = 'inverse', seed = 1, label, style }) {
  const { Block, Cap, Stroke, Sketch } = DS;
  const { diagramTone } = Sketch;
  const t = diagramTone(tone);
  /* Mike, illustration audit: "cluster N" used to sit at y0+60, which lands inside the cluster
     block's own vertical span (y0+40 to y0+72), not below it — the label rendered stamped on top
     of the hatching instead of captioning it. Deriving the label from the block's own bottom edge
     (clusterBottom + labelGap) keeps it a real caption regardless of block height, the same
     pattern FleetTenancyMap already uses for its own per-region caption. */
  const clusterBottom = (y0) => y0 + 40 + 32;
  const labelGap = 16;
  const vClusterY = [20, 128, 236];
  const bClusterX = [286, 346, 406];
  const lastLabelY = clusterBottom(vClusterY[vClusterY.length - 1]) + labelGap;
  return (
    <svg viewBox={`0 0 460 ${lastLabelY + 32}`} role={label ? 'img' : 'presentation'} aria-label={label} aria-hidden={label ? undefined : 'true'}
      style={{ width: '100%', height: 'auto', display: 'block', overflow: 'visible', ...style }}>
      <Cap x={20} y={10} fill={t.muted} size={9} bold>VMware</Cap>
      {vClusterY.map((y0, i) => (
        <g key={i}>
          <Block x={20} y={y0} w={86} h={26} d={5} seed={seed + i * 10} front={t.front} top={t.top} right={t.right} ink={t.ink} />
          <Cap x={26} y={y0 + 17} fill={t.text} size={7}>vCenter</Cap>
          <Stroke pts={[[63, y0 + 26], [63, y0 + 40]]} seed={seed + i * 10 + 1} weight={1.4} ink={t.hair} />
          <Block x={20} y={y0 + 40} w={86} h={32} d={6} seed={seed + i * 10 + 2} front={t.front} top={t.top} right={t.right} ink={t.ink} hatchTone={t.hair} hatchGap={6} />
          <Cap x={26} y={clusterBottom(y0) + labelGap} fill={t.muted} size={7}>cluster {i + 1}</Cap>
        </g>
      ))}
      <Cap x={20} y={lastLabelY + 32} fill={t.muted} size={7}>a control plane per cluster, every time</Cap>

      <Cap x={286} y={10} fill={t.accent} size={9} bold>basalt</Cap>
      <Block x={280} y={20} w={150} h={28} d={6} seed={seed + 40} front={t.accentFace} top={t.accentTop} right={t.accentRight} ink={t.ink} />
      <Cap x={288} y={39} fill="#F0F1FB" size={7} bold>global control plane</Cap>
      {bClusterX.map((x0, i) => (
        <g key={i}>
          <Stroke pts={[[355, 48], [x0 + 20, 130]]} seed={seed + 50 + i} weight={1.4} ink={t.hair} />
          <Block x={x0} y={130} w={40} h={30} d={5} seed={seed + 60 + i} front={t.front} top={t.top} right={t.right} ink={t.ink} hatchTone={t.hair} hatchGap={5} />
        </g>
      ))}
      <Cap x={286} y={180} fill={t.muted} size={7}>three clusters, one control plane</Cap>
    </svg>
  );
}

/* -------------------------------------------------- NBV — Basalt controller, multiple clusters */

/* Dylan Conner, 21 Sept, on Enterprise virtualization Section NB: "Replace the current VMware
   illustration with a Basalt controller managing multiple clusters. The drawing should not assert
   that every VMware cluster requires its own vCenter." NB isn't a head-to-head VMware page — it's
   the generalized enterprise case — so ControlPlaneComparison's specific "vCenter, every time"
   claim didn't belong here even before this note. This is that diagram's own right half on its
   own: just Basalt's side, no competitor asserted at all. */
function BasaltMultiCluster({ tone = 'inverse', seed = 1, label, style }) {
  const { Block, Cap, Stroke, Sketch } = DS;
  const { diagramTone } = Sketch;
  const t = diagramTone(tone);
  {/* Mike, 23 Sept: "you centered the word basalt, you didn't center the word control plane, and
      then your three clusters should be centered — it feels like they're pulled over to the
      left." clusterX averaged to 180, not the viewBox's actual center (210), because the spacing
      was measured from the left edge instead of around the middle; shifted the whole set +30 so
      the three centers (90/210/330) land symmetrically around 210 with equal margin on both
      sides. */}
  const clusterX = [70, 190, 310];
  return (
    <svg viewBox="0 0 420 210" role={label ? 'img' : 'presentation'} aria-label={label} aria-hidden={label ? undefined : 'true'}
      style={{ width: '100%', height: 'auto', display: 'block', overflow: 'visible', ...style }}>
      <Cap x={210} y={12} anchor="middle" fill={t.accent} size={9} bold>basalt</Cap>
      <Block x={135} y={22} w={150} h={28} d={6} seed={seed} front={t.accentFace} top={t.accentTop} right={t.accentRight} ink={t.ink} />
      <Cap x={210} y={41} anchor="middle" fill="#F0F1FB" size={7} bold>global control plane</Cap>
      {clusterX.map((x0, i) => (
        <g key={i}>
          <Stroke pts={[[210, 50], [x0 + 20, 130]]} seed={seed + 10 + i} weight={1.4} ink={t.hair} />
          <Block x={x0} y={130} w={40} h={30} d={5} seed={seed + 20 + i} front={t.front} top={t.top} right={t.right} ink={t.ink} hatchTone={t.hair} hatchGap={5} />
          <Cap x={x0 + 20} y={176} anchor="middle" fill={t.muted} size={7}>cluster {i + 1}</Cap>
        </g>
      ))}
      <Cap x={210} y={198} anchor="middle" fill={t.muted} size={8}>one Basalt controller manages every cluster</Cap>
    </svg>
  );
}

/* ------------------------------------------------------------- PF — the low-cost alternatives */

/* Mike, 17 Sept, HourPlus call: "Proxmox, Morpheus, OLVM — and you can pick a dozen others — put
   them on one side of a firewall... and Basalt on the other side, and make it stand out that it's
   in a class of its own. This is not the same approach as the other ones, even though they're as
   inexpensive." The point isn't a price comparison (ALSO_CONSIDERING_POINTS/StatRow beneath this
   already makes that one in words) — it's that "cheap" and "different architecture" are two
   separate axes, and the low-cost incumbents only win the first one. Reuses the same wall styling
   as PerSiteControlPlanes for visual consistency, but as a category divider here rather than a
   labeled security boundary, so it isn't captioned "Firewall" the way that one is. */
function ClassOfItsOwn({ tone = 'inverse', seed = 1, label, style }) {
  const { Block, Face, Cap, Sketch } = DS;
  const { diagramTone } = Sketch;
  const t = diagramTone(tone);
  const names = ['Proxmox', 'Morpheus', 'OLVM', '+ a dozen others'];
  const rowY = [30, 74, 118, 162];
  return (
    <svg viewBox="0 0 460 250" role={label ? 'img' : 'presentation'} aria-label={label} aria-hidden={label ? undefined : 'true'}
      style={{ width: '100%', height: 'auto', display: 'block', overflow: 'visible', ...style }}>
      <Cap x={20} y={12} fill={t.muted} size={9} bold>Still doing it the old way</Cap>
      {names.map((name, i) => (
        <g key={name}>
          <Block x={20} y={rowY[i]} w={130} h={28} d={5} seed={seed + i * 10} front={t.front} top={t.top} right={t.right} ink={t.ink} hatchTone={t.hair} hatchGap={6} />
          <Cap x={28} y={rowY[i] + 18} fill={t.text} size={8}>{name}</Cap>
          {/* the same small per-cluster mark PerSiteControlPlanes uses for "its own control
              plane" — the point is that every name here still carries it. */}
          <Face corners={[[160, rowY[i] + 6], [174, rowY[i] + 6], [174, rowY[i] + 22], [160, rowY[i] + 22]]}
            seed={seed + 100 + i} fill="none" ink={t.ink} weight={1.4} hatchTone={t.hatch} hatchGap={5} />
        </g>
      ))}
      <Cap x={20} y={212} fill={t.muted} size={7}>Same low price. Same per-cluster control plane.</Cap>

      <Face corners={[[214, 10], [230, 10], [230, 220], [214, 220]]}
        seed={seed + 300} fill="none" ink={t.ink} weight={1.8} hatchTone={t.hatch} hatchGap={7} />

      <Cap x={340} y={12} anchor="middle" fill={t.accent} size={9} bold>A class of its own</Cap>
      <Block x={280} y={90} w={130} h={50} d={7} seed={seed + 200} front={t.accentFace} top={t.accentTop} right={t.accentRight} ink={t.ink} />
      <Cap x={290} y={119} fill="#F0F1FB" size={8} bold>Basalt</Cap>
      <Cap x={340} y={212} anchor="middle" fill={t.muted} size={7}>Same low price. A different architecture entirely.</Cap>
    </svg>
  );
}

/* --------------------------------------------------------------- JB — MSP multi-tenancy */

/* Mike, 16 Sept review: "you must create an illustration for multi-tenancy for managed service
   providers" — MSPClaims (pages.jsx) had a StatRow making the claim but no drawing at all. Donnie,
   15 Sept: "real multi-tenancy means you have a super admin that can't see tenants' information...
   click through their tenants, have one controller handle all of those individual clusters for
   their customers." One controller reaching every customer's own cluster (the solid lines down),
   and no line at all between customers (the red X in each gap) — the isolation claim is what's
   drawn, not just the access claim FleetTenancyMap already makes elsewhere on the site.

   Dylan Conner, 21 Sept: "The illustration should show provider administration across customer
   clusters, with clear tenant boundaries. Remove 'can't see inside': customer isolation and
   controller visibility are different concepts." The prior version marked every tenant box and
   every gap between customers with a red ✕, telling one story — negation, what the controller
   CAN'T do — when the actual claim is administration WITHIN a boundary. Dropped every ✕ and the
   "cannot see what runs inside" caption; the Face border around each customer's own cluster now
   carries the boundary claim by itself, with plain labels instead of a crossed-out one. */
function MSPTenancy({ tone = 'inverse', seed = 1, label, style }) {
  const { Block, Face, Stroke, Cap, Sketch } = DS;
  const { diagramTone } = Sketch;
  const t = diagramTone(tone);
  const tenants = [
    { x: 20, name: 'Customer A' },
    { x: 170, name: 'Customer B' },
    { x: 320, name: 'Customer C' },
  ];
  return (
    <svg viewBox="0 0 420 250" role={label ? 'img' : 'presentation'} aria-label={label} aria-hidden={label ? undefined : 'true'}
      style={{ width: '100%', height: 'auto', display: 'block', overflow: 'visible', ...style }}>
      {/* Mike, 23 Sept: "your text is not inside the bounding box of the one control plane,
          multiple tenants [block]." The full phrase never fit one line inside a 140-wide box at
          this size — widened the block (125-295, still centered on 210) and split the label
          across two lines, both comfortably inside it. */}
      <Block x={125} y={14} w={170} h={34} d={6} seed={seed} front={t.accentFace} top={t.accentTop} right={t.accentRight} ink={t.ink} />
      {/* Dylan Conner, 23 Sept call: "I don't think we need the word super admin or one controller.
         I think we need one control plane, multiple tenants." His own reasoning: a super admin
         label implies delegation-of-authority (an admin who automatically sees everything beneath
         them), which is the opposite of the true multi-tenancy claim this drawing exists to make. */}
      <Cap x={210} y={28} anchor="middle" fill="#F0F1FB" size={8} bold>one control plane,</Cap>
      <Cap x={210} y={40} anchor="middle" fill="#F0F1FB" size={8} bold>multiple tenants</Cap>
      {tenants.map((tn, i) => {
        return (
        <g key={tn.name}>
          {/* Dylan, 23 Sept: "we don't need the word provisions." Also drops the labeling math this
             line used to need (Mike, 21 Sept: "the word provisions is on top of a line") — with no
             label riding the stroke, the line itself needs nothing beyond what it already is. */}
          <Stroke pts={[[210, 50], [tn.x + 40, 88]]} seed={seed + 10 + i} weight={1.4} ink={t.hair} />
          <Face corners={[[tn.x, 88], [tn.x + 80, 88], [tn.x + 80, 172], [tn.x, 172]]}
            seed={seed + 20 + i} fill="none" ink={t.hair} weight={1.2} />
          <Cap x={tn.x + 40} y={104} anchor="middle" fill={t.text} size={8} bold>{tn.name}</Cap>
          <Block x={tn.x + 12} y={118} w={26} h={18} d={4} seed={seed + 30 + i} front={t.front} top={t.top} right={t.right} ink={t.ink} />
          <Block x={tn.x + 42} y={118} w={26} h={18} d={4} seed={seed + 40 + i} front={t.front} top={t.top} right={t.right} ink={t.ink} />
          <Cap x={tn.x + 40} y={150} anchor="middle" fill={t.text} size={7} bold>tenant boundary</Cap>
          <Cap x={tn.x + 40} y={190} anchor="middle" fill={t.muted} size={7}>customer environment</Cap>
        </g>
        );
      })}
      <Cap x={210} y={225} anchor="middle" fill={t.muted} size={8}>one controller administers every customer cluster, each within its own tenant boundary</Cap>
    </svg>
  );
}

/* ---------------------------------------------------- CBV / XBV — distributed site reach */

/* Mike, 16 Sept: oil & gas and telecommunications got real placeholder copy and "an accompanying
   illustration" per his own instruction, and Luigi gave both the same underlying shape on the
   call: oil & gas has "infrastructure all over the place" (the same story as Federal/DDIL, for a
   buyer with the budget to fix it) and telecommunications has "infrastructure everywhere [the
   network reaches]." One component, two site-label props, rather than two near-identical
   drawings — the same reuse pattern VirtualizationParity already uses across the Proxmox and
   Nutanix pages. Deliberately not MSPTenancy's shape reused verbatim: that one's ✕ marks are
   about tenant isolation, a claim that doesn't apply here — this is reach across distance, not
   isolation across customers, so the sites sit spread along a baseline instead of stacked under
   one controller.

   Dylan, 17 Sept, on Oil & Gas specifically: "I'd like the diagram here to reference making it
   more clear that these might be in severe environments... platform, pipeline station,
   refinery... floating oil platform or on a mountain or on the gulf away from town. Locations
   that would not have good IT." The optional `terrain` prop (an array parallel to `sites`, values
   'offshore' | 'mountain' | 'remote' | undefined per index) draws a small hand-drawn cue beneath
   the matching site block via the module-level terrainCue() helper above. It defaults to
   undefined — no cues at all — so Telecommunications' own call is unaffected unless another agent
   explicitly opts a site in; oil rigs don't belong on a telecom tower site. */
function DistributedSiteReach({ tone = 'inverse', seed = 1, label, siteLabel = 'site', sites = ['Site A', 'Site B', 'Site C', 'Site D'], terrain, icons, style }) {
  const { Block, Face, Stroke, Cap, Sketch } = DS;
  const { diagramTone } = Sketch;
  const t = diagramTone(tone);
  const baseY = 176;
  const n = sites.length;
  const spanX0 = 30, spanX1 = 390;
  const xs = sites.map((_, i) => spanX0 + (spanX1 - spanX0) * (n === 1 ? 0.5 : i / (n - 1)));
  const hubX = 210, hubY = 30;
  return (
    <svg viewBox="0 0 420 224" role={label ? 'img' : 'presentation'} aria-label={label} aria-hidden={label ? undefined : 'true'}
      style={{ width: '100%', height: 'auto', display: 'block', overflow: 'visible', ...style }}>
      <Block x={hubX - 45} y={hubY} w={90} h={26} d={6} seed={seed} front={t.accentFace} top={t.accentTop} right={t.accentRight} ink={t.ink} />
      <Cap x={hubX} y={hubY + 17} anchor="middle" fill="#F0F1FB" size={8} bold>one control plane</Cap>
      <Stroke pts={[[spanX0 + 6, baseY], [spanX1 - 6, baseY]]} seed={seed + 5} weight={1.2} ink={t.hair} />
      {/* Dylan Conner, 21 Sept, on the Telecom page's version of this drawing: "Arrows should
          show connections initiated from the sites toward the controller." These lines had no
          arrowhead at all before — added one pointing from each site up to the hub, matching the
          outbound-initiated management model his own copy describes. */}
      {xs.map((x, i) => {
        const hasIcon = icons && icons[i];
        /* Mike, 24 Sept: "the line that leads to the one control plane is going through the
           illustration... like in the pipeline station, it needs to start a little bit away from
           the illustration." siteIcon's shapes occupy baseY-44 to baseY-4; starting the line at
           baseY-34 put its own lower end inside that range — clear of the mountain's single thin
           peak stroke, but visibly cutting through the rig's denser lattice bracing. Icons now
           start their line 6px above their own top edge (baseY-50) so it can't overlap any of
           them; the plain fallback Block (no icon assigned) is unchanged; its own top already
           sits exactly at baseY-34, which the line already met cleanly. */
        const lineStartY = hasIcon ? baseY - 50 : baseY - 34;
        return (
        <g key={i}>
          <Stroke pts={[[x, lineStartY], [hubX, hubY + 26]]} seed={seed + 10 + i} weight={1.3} ink={t.hair} />
          {arrowHead(Stroke, x, lineStartY, hubX, hubY + 26, 6, seed + 15 + i, t.hair)}
          {(hasIcon && siteIcon(Stroke, Face, icons[i], x, baseY, seed + 800 + i * 20, t.ink, t.accent)) ||
            <Block x={x - 20} y={baseY - 34} w={40} h={28} d={5} seed={seed + 20 + i} front={t.front} top={t.top} right={t.right} ink={t.ink} />}
          {/* An earlier pass drew these in t.hair — the same faint hairline tone used for
              background connector lines — and an independent review confirmed they didn't
              register as terrain at normal size. Promoted to t.ink, the same solid tone the
              site blocks themselves are drawn in, so the rig/mountain/dots actually read. */}
          {terrain && terrain[i] && (
            <g>{terrainCue(Stroke, Face, Cap, terrain[i], x, baseY, seed + 700 + i * 5, t.ink)}</g>
          )}
          <Cap x={x} y={baseY + 14} anchor="middle" fill={t.muted} size={7}>{sites[i]}</Cap>
        </g>
        );
      })}
      {/* Dylan Conner, 21 Sept: "Remove... promises that technicians never need to visit." The old
          caption's absolute claim ("no site needs a technician") is gone — this states what's
          actually true (the connection direction) instead of a guarantee about site visits.

          Design/dev director review, 21 Sept: this caption sat at y=198, only 8 units below the
          per-site labels at y=190 (baseY+14) — since it's centered across the full viewBox width,
          it visually collided with the two inner sites' own labels on both pages that use this
          component (Oil & Gas and Telecom). Moved down to y=216 and the viewBox grown from 210 to
          224 tall to give it real clearance instead of just nudging it into the next collision. */}
      <Cap x={210} y={216} anchor="middle" fill={t.muted} size={8}>each {siteLabel} initiates its own management connection to the controller</Cap>
    </svg>
  );
}

/* ------------------------------------------------------------------------- MBV — data custody */

/* Mike, 16 Sept: regulated industries (healthcare, legal — Luigi: "you don't trust your
   infrastructure to someone else's care") also needed real copy and an illustration, but its
   claim is not about distance or tenancy — it's about custody. What's drawn is the thing that
   never happens rather than the thing that does: data crossing out to somebody else's
   infrastructure. The boundary is your own care; the only line crossing it is the same
   outbound-only management link every other page already establishes, and the crossed-out arrow
   outside marks the access that stays refused.

   Mike, 17 Sept: "illustration MBV makes no sense" — the original had one green arrow leaving
   the boundary toward nothing labeled (it was never clear what "management out" actually reached),
   crossed by a second, backwards, arrowless line sitting almost on top of it near a floating ✕
   with no box of its own. Rebuilt with two separate, non-overlapping destinations on the outside:
   a labeled "Basalt control plane" box the green arrow actually reaches, and a labeled "someone
   else's data center" box below it that the red, ✕-marked line never completes — so each line now
   has an actual place it's going (or not going) instead of ending in open space.

   Dylan Conner, 21 Sept: "The illustration should show workloads and Basalt hosts within the
   customer environment, with a clearly labeled management connection. Remove 'data never leaves
   the boundary,' which implies control over application data movement. Also make the controller's
   deployment location explicit so the drawing does not imply it must be hosted by Basalt." The
   inside block was labeled "your data" — a claim about application data this diagram can't back
   up — relabeled "workloads" to match what a virtualization platform actually manages. The bottom
   caption dropped the "data never leaves" line entirely for one scoped strictly to the management
   connection, and the outside box now states its own deployment is a customer choice, not a
   given. */
function DataCustody({ tone = 'inverse', seed = 1, label, style }) {
  const { Block, Face, Cap, Stroke, Sketch } = DS;
  const { diagramTone } = Sketch;
  const t = diagramTone(tone);
  /* Mike, 21 Sept: "your text is not inside of the box... 'someone else's data center' or
     'deployed wherever you choose' under the basalt control plane — those things are outside of
     the boxes." Both right-side boxes were only 90 units wide (x=350-440), sized for the original
     short labels this diagram shipped with; "deployed wherever you choose" and "someone else's
     data center" are both meaningfully longer strings added in later passes, and nobody rechecked
     them against the box width. Widened both boxes to 150 units and grew the viewBox to match, so
     the longest label (the 6px subtitle, ~104 units wide) fits with real margin instead of running
     out the right edge. */
  return (
    <svg viewBox="0 0 540 240" role={label ? 'img' : 'presentation'} aria-label={label} aria-hidden={label ? undefined : 'true'}
      style={{ width: '100%', height: 'auto', display: 'block', overflow: 'visible', ...style }}>
      <Face corners={[[40, 30], [300, 30], [300, 190], [40, 190]]} seed={seed} fill="none" ink={t.hair} weight={1.4} />
      <Cap x={50} y={48} fill={t.text} size={8} bold>your infrastructure, your control</Cap>
      <Block x={80} y={90} w={60} h={40} d={7} seed={seed + 10} front={t.accentFace} top={t.accentTop} right={t.accentRight} ink={t.ink} />
      <Cap x={110} y={112} anchor="middle" fill="#F0F1FB" size={7} bold>workloads</Cap>
      <Block x={170} y={100} w={56} h={34} d={6} seed={seed + 20} front={t.front} top={t.top} right={t.right} ink={t.ink} />
      <Cap x={198} y={120} anchor="middle" fill={t.text} size={7} bold>Basalt host</Cap>

      {/* the one thing that does leave — outbound management, and it goes somewhere named.

          Design/dev director review, 21 Sept: "outbound management connection," left-aligned
          (the default) from x=300, grew rightward straight into the "Basalt control plane" box
          label at x=358 — confirmed overlapping. Shortened and right-anchored to x=345 so it
          grows LEFTWARD, ending clear of the box regardless of exact text width. */}
      <Stroke pts={[[300, 90], [350, 85]]} seed={seed + 30} weight={1.6} ink={t.ok} />
      {arrowHead(Stroke, 300, 90, 350, 85, 7, seed + 31, t.ok)}
      <Cap x={345} y={78} anchor="end" fill={t.ok} size={7}>outbound management</Cap>
      <Face corners={[[350, 70], [500, 70], [500, 100], [350, 100]]} seed={seed + 40} fill="none" ink={t.ok} weight={1.4} />
      <Cap x={358} y={83} fill={t.text} size={7} bold>Basalt control plane</Cap>
      <Cap x={358} y={94} fill={t.muted} size={6}>deployed wherever you choose</Cap>

      {/* the thing that never happens — its own line, its own destination, well clear of the one
          above so the two don't read as the same arrow contradicting itself. */}
      <Stroke pts={[[300, 150], [350, 155]]} seed={seed + 50} weight={1.6} ink={t.failed} />
      <Cap x={318} y={148} fill={t.failed} size={13} bold>✕</Cap>
      <Face corners={[[350, 140], [500, 140], [500, 170], [350, 170]]} seed={seed + 60} fill="none" ink={t.failed} weight={1.4} />
      <Cap x={358} y={158} fill={t.text} size={7} bold>someone else's data center</Cap>

      {/* Found during this same review pass: this caption's text was lengthened earlier (dropping
          "data never leaves the boundary") without rechecking it against its own position — at
          x=170 (the boundary box's own center, not the SVG's), anchor="middle", the new longer
          string measured ~512 units wide and ran to x=-86, off the left edge of the viewBox.
          Shortened the wording and centered it on the SVG's own actual midpoint, recomputed again
          (230 -> 270) after the viewBox itself grew from 460 to 540 to fit the two boxes above. */}
      <Cap x={270} y={215} anchor="middle" fill={t.muted} size={7}>Only outbound management leaves your infrastructure, to a control plane deployed wherever you choose.</Cap>
    </svg>
  );
}

/* --------------------------------------------------------- MBV — one standard, both sides (new) */

/* SPEAKER_01 (Donnie), 23 Sept, on retitling Regulated industries to Critical Infrastructure and
   Medical Industries: "we're built from the ground up for the most regulated industry, right?
   That's the claim. Like good enough for government, good enough for you. That's the essential
   claim... we are built from the ground up to be run by people who have things besides money to
   worry about. You're also worried about meeting an objective standard of how you run your
   network. We know what that's like. That's where we grew up." Mike, same call: "I'll come up
   with an illustration... I'm gonna retitle regulated industries to critical infrastructure and
   medical industries."

   DataCustody above answers a different question ("does our data leave our own custody?") and
   still runs on the Migration/evaluation-adjacent pages that ask it; it was never built to carry
   this page's actual claim, which is about the standard itself being portable across sectors, not
   about data boundaries. One operating standard is drawn once at the top, then reaches two
   identically-drawn destinations below it — same box, same internal host block, same connector
   style — so the equivalence is what the shape itself asserts, not just the caption under it. */
function OneStandardBothSides({ tone = 'inverse', seed = 1, label, style }) {
  const { Block, Face, Cap, Stroke, Sketch } = DS;
  const { diagramTone } = Sketch;
  const t = diagramTone(tone);

  /* Mike, 24 Sept: "pull your illustrations down a little bit, where you have government missions,
     critical infrastructure, medical... the lines with the arrows that run from one operating
     standard are underneath the text and that makes it confusing." Two separate problems, one
     fix each: the whole branch (title, box, host block, caption) shifted down 14px for more air
     under the top block; and the arrows, which used to run all the way to y=96 — past the title
     text at y=82/92 — now stop at y=86, short of the title's new position (96) entirely, so the
     diagonal line can no longer cross through the letters at any point along its length. */
  const branch = (bx, titleLines, sub) => (
    <g>
      {titleLines.map((line, i) => (
        <Cap key={i} x={bx + 80} y={96 + i * 10} anchor="middle" fill={t.text} size={8} bold>{line}</Cap>
      ))}
      <Face corners={[[bx, 114], [bx + 160, 114], [bx + 160, 186], [bx, 186]]}
        seed={seed + bx} fill="none" ink={t.ink} weight={1.4} />
      <Block x={bx + 55} y={130} w={50} h={30} d={6} seed={seed + bx + 5}
        front={t.front} top={t.top} right={t.right} ink={t.ink} />
      <Cap x={bx + 80} y={149} anchor="middle" fill={t.text} size={6.5} bold>Basalt hosts</Cap>
      <Cap x={bx + 80} y={174} anchor="middle" fill={t.muted} size={6}>{sub}</Cap>
    </g>
  );

  return (
    <svg viewBox="0 0 420 236" role={label ? 'img' : 'presentation'} aria-label={label} aria-hidden={label ? undefined : 'true'}
      style={{ width: '100%', height: 'auto', display: 'block', overflow: 'visible', ...style }}>
      <Block x={150} y={16} w={120} h={34} d={6} seed={seed} front={t.accentFace} top={t.accentTop} right={t.accentRight} ink={t.ink} />
      <Cap x={210} y={38} anchor="middle" fill="#F0F1FB" size={8} bold>one operating standard</Cap>

      <Stroke pts={[[170, 50], [110, 86]]} seed={seed + 20} weight={1.5} ink={t.hair} />
      {arrowHead(Stroke, 170, 50, 110, 86, 6, seed + 21, t.hair)}
      <Stroke pts={[[250, 50], [310, 86]]} seed={seed + 22} weight={1.5} ink={t.hair} />
      {arrowHead(Stroke, 250, 50, 310, 86, 6, seed + 23, t.hair)}

      {branch(30, ['Government missions'], 'NIST-aligned, audited')}
      {branch(230, ['Critical infrastructure', 'and medical'], 'same standard, same controls')}

      <Cap x={210} y={154} anchor="middle" fill={t.accent} size={14} bold>=</Cap>
      {/* Dylan, 25 Sept call: "'Good enough' is never a claim you want to make — that's a
          sentiment, not a claim... purpose built for the regulated environment." Replaces the
          prior line, which stated the transcript's own framing almost verbatim but as a slogan
          rather than a claim. */}
      <Cap x={210} y={214} anchor="middle" fill={t.accent} size={8} bold>Purpose-built for the most demanding regulated environments.</Cap>
    </svg>
  );
}

/* ------------------------------------------------------------------- YB — enterprise compute scale */

/* Mike, 16 Sept, second pass: "you're going to have to go write the enterprise compute [...]
   government page holder placeholder copy, and it's going to have to match [...] the page
   structure of tactical DDIL and regional" — both of which pair their own claim with a purpose-
   built illustration. Luigi's own description of this one: "true data center, big, lots of
   racks." Deliberately not DistributedSiteReach (already carries the "many remote sites, one
   control plane" idea for Oil & gas and Telecommunications): this is the opposite shape — one
   facility, not many sites, so the racks sit tightly grouped under one roofline instead of spread
   across a baseline standing in for distance, and one line reaches the whole row rather than
   fanning out to each site individually.

   Dylan Conner, 21 Sept: "Remove descriptions such as 'a real data center,' 'a closet with some
   switches,' and 'the scale end of the same architecture.' This page should address enterprise
   operational needs without restricting the customer to one facility. Group the illustration into
   two labeled data centers with managed clusters beneath the Basalt controller. Avoid unqualified
   'any scale' claims." The single-facility rack row is now two separate, independently labeled
   data centers, each with its own small cluster of racks, both reaching the same controller —
   showing multiple facilities instead of implying one big one is the ceiling. */
/* Mike, 21 Sept: "the rectangles that are underneath the words data center one and data center
   two... a little bit offset to the left. Same with the lines above it." Block (design system)
   draws a 3D box whose visual right edge extends past x+w by its own depth `d` — the floor plate
   and the roofline strokes below were centered on `cx` using only the racks' front-face width
   (ignoring that extra depth on the rightmost rack), so the racks' TRUE rendered footprint sat
   noticeably right of where the floor and roof lines assumed center was, reading as everything
   else being shifted left relative to the racks. rackXs is now generated from the group's actual
   visual width (n racks + gaps + one rack's worth of depth on the right end) so it's centered on
   `cx` by construction, and the floor/roofline width is derived from the same number instead of a
   separately hand-picked ±55. */
/* Mike/Dylan, 23 Sept call: "you could even have data center one, two, and three... just to make
   it more impressive... you could have the basalt controller go across the entire top." Two data
   centers already made the "multiple facilities, one controller" point; a third plus a controller
   bar spanning the full width of all three (instead of just sitting centered over two) makes the
   same point read as scale rather than a minimum viable pair. */
function EnterpriseComputeScale({ tone = 'inverse', seed = 1, label, style }) {
  const { Block, Face, Stroke, Cap, Sketch } = DS;
  const { diagramTone } = Sketch;
  const t = diagramTone(tone);
  const rackW = 30, rackGap = 5, rackDepth = 6, rackCount = 3;
  const groupW = rackCount * rackW + (rackCount - 1) * rackGap + rackDepth;
  const rackXsFor = (cx) => {
    const start = cx - groupW / 2;
    return [0, 1, 2].map(i => start + i * (rackW + rackGap));
  };
  const dcCenters = [80, 210, 340];
  const centers = dcCenters.map((cx, i) => ({ cx, name: `Data center ${i + 1}`, rackXs: rackXsFor(cx) }));
  return (
    <svg viewBox="0 0 420 230" role={label ? 'img' : 'presentation'} aria-label={label} aria-hidden={label ? undefined : 'true'}
      style={{ width: '100%', height: 'auto', display: 'block', overflow: 'visible', ...style }}>
      <Block x={60} y={10} w={300} h={26} d={6} seed={seed} front={t.accentFace} top={t.accentTop} right={t.accentRight} ink={t.ink} />
      <Cap x={210} y={27} anchor="middle" fill="#F0F1FB" size={8} bold>Basalt controller</Cap>
      {centers.map((dc, ci) => (
        <g key={ci}>
          <Stroke pts={[[210, 36], [dc.cx, 68]]} seed={seed + 2 + ci} weight={1.4} ink={t.hair} />
          <Stroke pts={[[dc.cx - groupW / 2, 70], [dc.cx + groupW / 2, 70]]} seed={seed + 4 + ci} weight={1.2} ink={t.hair} />
          {dc.rackXs.map((x, i) => (
            <g key={i}>
              <Stroke pts={[[x + 15, 70], [x + 15, 78]]} seed={seed + 10 + ci * 10 + i} weight={1.2} ink={t.hair} />
              <Block x={x} y={78} w={rackW} h={88} d={rackDepth} seed={seed + 20 + ci * 10 + i}
                front={t.front} top={t.top} right={t.right} ink={t.ink} hatchTone={t.hair} hatchGap={6} />
            </g>
          ))}
          <Face corners={[[dc.cx - groupW / 2, 168], [dc.cx + groupW / 2, 168], [dc.cx + groupW / 2, 178], [dc.cx - groupW / 2, 178]]} seed={seed + 40 + ci} fill={t.hair} ink={t.hair} weight={1} />
          <Cap x={dc.cx} y={198} anchor="middle" fill={t.text} size={8} bold>{dc.name}</Cap>
        </g>
      ))}
      <Cap x={210} y={218} anchor="middle" fill={t.muted} size={8}>one Basalt controller manages clusters across every data center</Cap>
    </svg>
  );
}
