/* Shared figures. Every one is drawn from window.SX_DATA — nothing is typed twice.
   Chrome (title, legend, note) comes from ChartFrame wherever a figure is a chart. */
const { Tag: FTag, Card: FCard, Button: FButton, ChartFrame, Plot, DataTable: FTable, GlobalDelivery: FGlobe } = window.SoftVerxDesignSystem_6fd95b;
const D = window.SX_DATA;

/* ── the six stages, as a chain ────────────────────────────────────
   Circular nodes on one rail with the flow drawn between them. Each stage owns
   a hue and lights on hover; the icons are hairline schematics, not pictograms. */
const STAGE_ICON = {
  Sense: (<><path d="M12 5.5h8l2 2v11H10v-11z" /><path d="M13 9h4M13 12h6M13 15h3" /><circle cx="21.5" cy="16.5" r="4" /><path d="M24.4 19.4l2.6 2.6" /></>),
  Stream: (<><path d="M6 10h9M6 16h13M6 22h9" /><path d="M17 7l4 3-4 3M21 13l4 3-4 3M17 19l4 3-4 3" /></>),
  Store: (<><ellipse cx="16" cy="9" rx="9" ry="3.4" /><path d="M7 9v6c0 1.9 4 3.4 9 3.4s9-1.5 9-3.4V9" /><path d="M7 15v6c0 1.9 4 3.4 9 3.4s9-1.5 9-3.4v-6" /></>),
  Learn: (<><circle cx="8" cy="10" r="2" /><circle cx="8" cy="22" r="2" /><circle cx="16" cy="16" r="2.4" /><circle cx="24" cy="10" r="2" /><circle cx="24" cy="22" r="2" /><path d="M10 11l4 3.5M10 21l4-3.5M18 14.5l4-3.5M18 17.5l4 3.5" /></>),
  Predict: (<><path d="M6 24V7M6 24h20" /><path d="M9 20l4-5 3 3 4-7" /><path d="M20 11l3.5 7" strokeDasharray="2.5 2.5" /><circle cx="20" cy="11" r="1.6" fill="currentColor" stroke="none" /></>),
  Act: (<><circle cx="16" cy="16" r="9" /><path d="M16 3v4M16 25v4M3 16h4M25 16h4" /><path d="M12 16.4l3 3 5.5-6" /></>),
};
function StageIcon({ title, size }) {
  return <svg viewBox="0 0 32 32" width={size} height={size} fill="none" stroke="currentColor" strokeWidth="1.4" strokeLinecap="round" strokeLinejoin="round" aria-hidden>{STAGE_ICON[title]}</svg>;
}
const STAGE_HUE = ["var(--sx-accent)", "color-mix(in oklab, var(--sx-accent) 55%, var(--sx-field))", "var(--sx-field)", "var(--sx-signal)", "var(--sx-amber)", "var(--sx-accent)"];

/* The chain is drawn on an arc rather than a rule: six nodes sampled off one
   cubic, solid arrowheads set on the tangent, labels on a common baseline. */
const bez = (t, p0, c1, c2, p3) => {
  const u = 1 - t;
  return [u * u * u * p0[0] + 3 * u * u * t * c1[0] + 3 * u * t * t * c2[0] + t * t * t * p3[0],
    u * u * u * p0[1] + 3 * u * u * t * c1[1] + 3 * u * t * t * c2[1] + t * t * t * p3[1]];
};

function PipelineFigure({ mobile }) {
  const s = D.pipeline;
  const wrap = React.useRef(null);
  const [w, setW] = React.useState(1120);
  React.useEffect(() => {
    const el = wrap.current;
    if (!el) return;
    const ro = new ResizeObserver(() => setW(el.clientWidth || 1120));
    ro.observe(el);
    setW(el.clientWidth || 1120);
    return () => ro.disconnect();
  }, []);

  if (mobile) {
    return (
      <div className="sx-chain is-mobile">
        {s.map((st, i) => (
          <React.Fragment key={st.title}>
            {i > 0 && <span className="sx-chain-link" aria-hidden><svg viewBox="0 0 14 26" width="14" height="26"><path d="M7 1v15" stroke={STAGE_HUE[i]} strokeWidth="2" strokeLinecap="round" fill="none" opacity="0.75" /><path d="M2.6 15.5h8.8L7 24.5z" fill={STAGE_HUE[i]} /></svg></span>}
            <div className="sx-chain-node" style={{ "--hue": STAGE_HUE[i] }}>
              <span className="sx-chain-disc"><StageIcon title={st.title} size={24} /><span className="sx-chain-n sx-micro sx-num">{st.n}</span></span>
              <div className="sx-chain-copy">
                <p className="sx-small sx-chain-title">{st.title}</p>
                <p className="sx-caption sx-chain-detail">{st.detail}</p>
              </div>
            </div>
          </React.Fragment>
        ))}
      </div>
    );
  }

  const R = 50, pad = R + 34, H = 232;
  const P0 = [pad, H - 46], C1 = [w * 0.28, 14], C2 = [w * 0.72, 14], P3 = [w - pad, H - 46];
  const pts = s.map((_, i) => bez(i / (s.length - 1), P0, C1, C2, P3));
  const mids = pts.slice(0, -1).map((p, i) => {
    const t = (i + 0.5) / (s.length - 1);
    const a = bez(t - 0.012, P0, C1, C2, P3), b = bez(t + 0.012, P0, C1, C2, P3);
    return { m: bez(t, P0, C1, C2, P3), deg: (Math.atan2(b[1] - a[1], b[0] - a[0]) * 180) / Math.PI };
  });
  const boxH = Math.max(...pts.map((p) => p[1])) + R + 148;
  /* The label can never be wider than its own slot on the arc, or apex neighbours collide. */
  const slot = Math.max(96, (w - pad * 2) / (s.length - 1) - 14);
  return (
    <div>
      <div ref={wrap} className="sx-arc" style={{ height: boxH }}>
        <svg width={w} height={H} viewBox={"0 0 " + w + " " + H} aria-hidden style={{ display: "block" }}>
          <defs>
            <linearGradient id="sx-arc-g" x1="0" y1="0" x2="1" y2="0">
              {STAGE_HUE.map((c, i) => <stop key={i} offset={(i / (STAGE_HUE.length - 1)) * 100 + "%"} stopColor={c} />)}
            </linearGradient>
          </defs>
          <path d={"M" + P0[0] + " " + P0[1] + " C" + C1[0] + " " + C1[1] + " " + C2[0] + " " + C2[1] + " " + P3[0] + " " + P3[1]}
            fill="none" stroke="url(#sx-arc-g)" strokeWidth="2.5" strokeLinecap="round" opacity="0.6" />
          {mids.map((a, i) => (
            <g key={i} transform={"translate(" + a.m[0] + "," + a.m[1] + ") rotate(" + a.deg + ")"}>
              <path d="M-8 -7.5L8.5 0L-8 7.5L-4.5 0Z" fill={STAGE_HUE[i + 1]} />
            </g>
          ))}
        </svg>
        {pts.map((p, i) => (
          <div key={s[i].title} className="sx-arc-node" style={{ "--hue": STAGE_HUE[i], left: p[0], top: p[1] }}>
            <span className="sx-chain-disc"><StageIcon title={s[i].title} size={40} /><span className="sx-chain-n sx-micro sx-num">{s[i].n}</span></span>
            <div className="sx-arc-label" style={{ width: slot }}>
              <p className="sx-chain-title">{s[i].title}</p>
              <p className="sx-caption sx-chain-detail">{s[i].detail}</p>
            </div>
          </div>
        ))}
      </div>
    </div>
  );
}

/* ── capability accumulation, 1999 → 2026 ───────────────────────────────── */
const T0 = 1999, T1 = 2026;
const PRACTICE_LAYER_ = { "ERP & billing": "core", "Data platforms": "data", "Cloud & DevOps": "apps", "Industrial IoT & edge": "edge", "Applied ML": "ml", "Computer vision": "ml", "AI agents": "agents", "Document intelligence": "agents", "Energy-tech": "edge", "Agri-tech": "edge" };
const yearOf = (p) => +String(p.year || "").slice(0, 4) || null;
function CapabilityTimeline({ mobile }) {
  const w = 1000, rowH = mobile ? 15 : 19, gap = 3;
  const layers = D.layers;
  const h = layers.length * (rowH + gap);
  const x = (y) => ((y - T0) / (T1 - T0)) * w;
  /* Each layer opens in the year its earliest delivered programme falls in — read
     from the record, never authored twice. */
  const start = {};
  layers.forEach((l) => {
    const years = D.projects.filter((p) => PRACTICE_LAYER_[p.practice] === l.id).map(yearOf).filter(Boolean);
    start[l.id] = years.length ? Math.min(...years) : T1;
  });
  const anchors = D.projects.filter((p) => p.tier === "flagship" && yearOf(p)).map((p) => ({ year: yearOf(p), label: p.short, slug: p.slug })).sort((a, b) => a.year - b.year)
    .filter((a, i, arr) => i === 0 || a.year - arr[i - 1].year >= (mobile ? 6 : 3));
  const [hover, setHover] = React.useState(null);
  return (
    <div>
      <div style={{ position: "relative" }}>
        <svg viewBox={`0 0 ${w} ${h + 74}`} width="100%" height={mobile ? 240 : 300} role="img" aria-label="Capability layers accumulating from 1999 to 2026" style={{ overflow: "visible" }}>
          {[2000, 2005, 2010, 2015, 2020, 2025].map((y) => (
            <g key={y}>
              <line x1={x(y)} y1="0" x2={x(y)} y2={h + 30} stroke="var(--border-default)" strokeWidth="1" />
              <text x={x(y)} y={h + 48} textAnchor="middle" fill="var(--text-quiet)" style={{ font: "500 13px var(--font-mono)" }}>{y}</text>
            </g>
          ))}
          {layers.map((l, i) => {
            const y = i * (rowH + gap);
            const lit = !hover || hover === l.id;
            return (
              <g key={l.id} onPointerEnter={() => setHover(l.id)} onPointerLeave={() => setHover(null)} style={{ cursor: "default" }}>
                <rect x="0" y={y} width={w} height={rowH} fill="none" stroke="var(--border-default)" strokeDasharray="2 4" />
                <rect x={x(start[l.id])} y={y} width={w - x(start[l.id])} height={rowH}
                  fill={`color-mix(in oklab, var(--sx-accent) ${18 + i * 9}%, var(--surface-raised))`}
                  opacity={lit ? 1 : 0.28} />
                <text x={x(start[l.id]) + 8} y={y + rowH / 2 + 4} fill="var(--text-strong)" opacity={lit ? 1 : 0.4} style={{ font: `500 ${mobile ? 10 : 12}px var(--font-mono)` }}>{l.code} {l.label.toLowerCase()}</text>
                {!mobile && <text x={w - 6} y={y + rowH / 2 + 4} textAnchor="end" fill="var(--text-quiet)" opacity={lit ? 1 : 0.3} style={{ font: "400 11px var(--font-mono)" }}>{l.note.toLowerCase()}</text>}
              </g>
            );
          })}
          <line x1="0" y1={h + 30} x2={w} y2={h + 30} stroke="var(--border-strong)" strokeWidth="1" />
          {D.eras.map((e) => {
            const [a, b] = e.label.split("–").map(Number);
            return (
              <g key={e.id}>
                <line x1={x(a) + 2} y1={h + 12} x2={x(Math.min(b, T1)) - 2} y2={h + 12} stroke="var(--border-strong)" />
                {!mobile && <text x={(x(a) + x(Math.min(b, T1))) / 2} y={h + 7} textAnchor="middle" fill="var(--text-body)" style={{ font: "400 11px var(--font-mono)" }}>{e.title.toLowerCase()}</text>}
              </g>
            );
          })}
          {D.projects.filter(yearOf).map((p) => (
            <line key={p.slug} x1={x(yearOf(p))} y1={h + 26} x2={x(yearOf(p))} y2={h + 34} stroke="var(--text-quiet)" strokeWidth="1" opacity="0.8" />
          ))}
          {anchors.map((a) => (
            <g key={a.slug}>
              <circle cx={x(a.year)} cy={h + 30} r="4.5" fill="var(--sx-accent)" />
              <text x={x(a.year)} y={h + 66} textAnchor="middle" fill="var(--text-accent)" style={{ font: "400 11px var(--font-mono)" }}>{a.label.toLowerCase()}</text>
            </g>
          ))}
        </svg>
      </div>
    </div>
  );
}

/* ── sector × capability layer ──────────────────────────────────────────── */
const PRACTICE_LAYER = { "ERP & billing": "core", "Data platforms": "data", "Cloud & DevOps": "apps", "Industrial IoT & edge": "edge", "Applied ML": "ml", "Computer vision": "ml", "AI agents": "agents", "Document intelligence": "agents", "Energy-tech": "edge", "Agri-tech": "edge" };
function SectorLayerHeatmap({ mobile, wide }) {
  const sectors = D.sectors.map((s) => s.label);
  const layers = D.layers;
  const counts = {};
  D.projects.forEach((p) => {
    const l = PRACTICE_LAYER[p.practice];
    counts[p.sector + "|" + l] = (counts[p.sector + "|" + l] || 0) + 1;
  });
  const max = Math.max(...Object.values(counts));
  const [tip, setTip] = React.useState(null);
  const cell = (s, l, h) => {
    const n = counts[s + "|" + l.id] || 0;
    return (
      <div onPointerEnter={() => setTip(`${s.toLowerCase()} · ${l.label.toLowerCase()} · ${n}`)} onPointerLeave={() => setTip(null)}
        style={{ height: h, display: "grid", placeItems: "center", border: "1px solid var(--border-default)", borderRadius: 4, background: n ? `color-mix(in oklab, var(--sx-accent) ${18 + (n / max) * 62}%, var(--surface-card))` : "transparent" }}>
        <span className="sx-micro sx-num" style={{ color: n ? "var(--text-strong)" : "var(--text-quiet)" }}>{n || "·"}</span>
      </div>
    );
  };
  if (wide && !mobile) {
    /* Fourteen sector names cannot sit horizontally at this column width, so the
       heads run at 45° — full names, ending at the column they label. */
    return (
      <div style={{ paddingRight: 104 }}>
        <table style={{ borderCollapse: "collapse", width: "100%", tableLayout: "fixed" }}>
          <thead>
            <tr>
              <th style={{ width: 168 }} />
              {sectors.map((s) => (
                <th key={s} style={{ padding: 0, verticalAlign: "bottom" }}>
                  <div style={{ height: 116, position: "relative" }}>
                    <span className="sx-caption" style={{ position: "absolute", left: "50%", bottom: 6, transformOrigin: "left bottom", transform: "rotate(-45deg)", whiteSpace: "nowrap", color: "var(--text-body)", textTransform: "none", letterSpacing: 0, fontFamily: "var(--font-body)" }}>{s.toLowerCase()}</span>
                  </div>
                </th>
              ))}
            </tr>
          </thead>
          <tbody>
            {layers.map((l) => (
              <tr key={l.id}>
                <th className="sx-small" style={{ textAlign: "left", fontWeight: 400, color: "var(--text-body)", padding: "0 14px 0 0", whiteSpace: "nowrap" }}>
                  <span className="sx-micro sx-num" style={{ color: "var(--text-quiet)", marginRight: 8 }}>{l.code}</span>{l.label.toLowerCase()}
                </th>
                {sectors.map((s) => <td key={s} style={{ padding: 2 }}>{cell(s, l, 32)}</td>)}
              </tr>
            ))}
          </tbody>
        </table>
        <p className="sx-caption" style={{ marginTop: 12, minHeight: "1.4em", color: "var(--text-accent)", textTransform: "none" }}>{tip || ""}</p>
      </div>
    );
  }
  return (
    <div style={{ overflowX: "auto" }}>
      <table style={{ borderCollapse: "collapse", width: "100%", minWidth: mobile ? 320 : 520 }}>
        <thead>
          <tr>
            <th />
            {layers.map((l) => (
              <th key={l.id} className="sx-caption" style={{ padding: "0 0 10px", color: "var(--text-quiet)", fontWeight: 400, textAlign: "center", writingMode: mobile ? "vertical-rl" : undefined }}>{l.code}</th>
            ))}
          </tr>
        </thead>
        <tbody>
          {sectors.map((s) => (
            <tr key={s}>
              <th className="sx-small" style={{ textAlign: "left", fontWeight: 400, color: "var(--text-body)", padding: "0 14px 0 0", whiteSpace: "nowrap" }}>{s}</th>
              {layers.map((l) => {
                const n = counts[s + "|" + l.id] || 0;
                return (
                  <td key={l.id} style={{ padding: 2 }}>
                    <div onPointerEnter={() => setTip(`${s} · ${l.label.toLowerCase()} · ${n}`)} onPointerLeave={() => setTip(null)}
                      style={{ height: mobile ? 30 : 38, display: "grid", placeItems: "center", border: "1px solid var(--border-default)", borderRadius: 4, background: n ? `color-mix(in oklab, var(--sx-accent) ${18 + (n / max) * 62}%, var(--surface-card))` : "transparent" }}>
                      <span className="sx-micro sx-num" style={{ color: n ? "var(--text-strong)" : "var(--text-quiet)" }}>{n || "·"}</span>
                    </div>
                  </td>
                );
              })}
            </tr>
          ))}
        </tbody>
      </table>
      <div style={{ display: "flex", gap: 16, flexWrap: "wrap", marginTop: 12 }}>
        {D.layers.map((l) => <span key={l.id} className="sx-micro" style={{ color: "var(--text-quiet)" }}>{l.code} {l.label.toLowerCase()}</span>)}
      </div>
      <p className="sx-caption" style={{ marginTop: 10, minHeight: "1.4em", color: "var(--text-accent)", textTransform: "none" }}>{tip || ""}</p>
    </div>
  );
}

/* ── solution reuse ─────────────────────────────────────────────────────── */
function SolutionReuse({ mobile, limit }) {
  const proven = D.solutions.map((s) => ({ ...s, n: (s.proof || []).length })).filter((s) => s.n > 1).sort((a, b) => b.n - a.n);
  const rows = proven.slice(0, limit || 99);
  const max = Math.max(...proven.map((r) => r.n));
  return (
    <div>
      <ul style={{ listStyle: "none", margin: 0, padding: 0, display: "grid", gap: 0, gridTemplateColumns: mobile ? "1fr" : "1fr 1fr", columnGap: 32 }}>
        {rows.map((r) => (
          <li key={r.id} style={{ display: "grid", gridTemplateColumns: "1fr auto auto", gap: 10, alignItems: "center", padding: mobile ? "7px 0" : "8px 0", borderBottom: "1px solid var(--border-default)" }}>
            <span className="sx-small" style={{ color: "var(--text-strong)", fontSize: mobile ? 13 : 13.5, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{r.name}</span>
            <span aria-hidden style={{ display: "flex", gap: 3, alignItems: "center" }}>
              {Array.from({ length: max }).map((_, i) => (
                <span key={i} style={{ width: 6, height: 6, borderRadius: 999, background: i < r.n ? "var(--sx-accent)" : "transparent", border: i < r.n ? "none" : "1px solid var(--border-default)" }} />
              ))}
            </span>
            <span className="sx-small" style={{ color: "var(--text-accent)", fontSize: 12.5, width: 12, textAlign: "right" }}>{r.n}</span>
          </li>
        ))}
      </ul>
      {rows.length < proven.length && (
        <p className="sx-small" style={{ marginTop: 12, color: "var(--text-quiet)" }}>{proven.length - rows.length} further solutions carry more than one deployment — the full list is on the solutions page.</p>
      )}
    </div>
  );
}

/* ── honest comparison ──────────────────────────────────────────────────── */
function ComparisonMatrix({ mobile }) {
  const { columns, rows } = D.comparison;
  if (mobile) {
    return (
      <div style={{ display: "grid", gap: 12 }}>
        {rows.map((r) => (
          <div key={r.criterion} style={{ border: "1px solid var(--border-default)", borderRadius: "var(--r-card)", padding: 16 }}>
            <p className="sx-small" style={{ color: "var(--text-strong)", fontWeight: 500 }}>{r.criterion}</p>
            <p className="sx-caption" style={{ marginTop: 6, color: "var(--text-quiet)", textTransform: "none", letterSpacing: 0, fontFamily: "var(--font-body)" }}>{r.detail}</p>
            <dl style={{ margin: "12px 0 0", display: "grid", gridTemplateColumns: "1fr auto", gap: "6px 10px" }}>
              {columns.map((c, i) => (
                <React.Fragment key={c}>
                  <dt className="sx-micro" style={{ color: i === 0 ? "var(--text-accent)" : "var(--text-quiet)" }}>{c.toLowerCase()}</dt>
                  <dd className="sx-micro" style={{ margin: 0, textAlign: "right", color: i === 0 ? "var(--text-strong)" : "var(--text-body)" }}>{r.cells[i]}</dd>
                </React.Fragment>
              ))}
            </dl>
          </div>
        ))}
      </div>
    );
  }
  const col = "minmax(0,1.5fr) repeat(4, minmax(0,0.85fr))";
  return (
    <div style={{ border: "1px solid var(--border-default)", borderRadius: "var(--r-card)", overflow: "hidden" }}>
      <div style={{ display: "grid", gridTemplateColumns: col, borderBottom: "1px solid var(--border-default)", background: "var(--surface-card)" }}>
        <div className="sx-caption" style={{ padding: "14px 18px", color: "var(--text-quiet)" }}>what you are weighing</div>
        {columns.map((c, i) => (
          <div key={c} className="sx-caption" style={{ padding: "14px 18px", color: i === 0 ? "var(--text-accent)" : "var(--text-quiet)", borderLeft: "1px solid var(--border-default)", background: i === 0 ? "color-mix(in oklab, var(--sx-accent) 8%, transparent)" : undefined }}>{c.toLowerCase()}</div>
        ))}
      </div>
      {rows.map((r, ri) => (
        <div key={r.criterion} style={{ display: "grid", gridTemplateColumns: col, borderTop: ri ? "1px solid var(--border-default)" : undefined }}>
          <div style={{ padding: "18px" }}>
            <p className="sx-small" style={{ color: "var(--text-strong)" }}>{r.criterion}</p>
            <p className="sx-caption" style={{ marginTop: 5, color: "var(--text-quiet)", textTransform: "none", letterSpacing: 0, fontFamily: "var(--font-body)", textWrap: "pretty" }}>{r.detail}</p>
          </div>
          {r.cells.map((cell, i) => (
            <div key={i} className="sx-small" style={{ padding: "18px", borderLeft: "1px solid var(--border-default)", color: i === 0 ? "var(--text-strong)" : "var(--text-body)", background: i === 0 ? "color-mix(in oklab, var(--sx-accent) 8%, transparent)" : undefined }}>{cell}</div>
          ))}
        </div>
      ))}
    </div>
  );
}

/* ── engagement ladder ──────────────────────────────────────────────────── */
function EngagementLadder({ mobile }) {
  const [picked, setPicked] = React.useState(1);
  return (
    <div role="radiogroup" aria-label="Ways to start" style={{ display: "grid", gap: 16, gridTemplateColumns: mobile ? "1fr" : "repeat(3, minmax(0,1fr))", alignItems: "stretch" }}>
      {D.engagements.map((e, i) => (
        <button key={e.id} type="button" role="radio" aria-checked={picked === i} onClick={() => setPicked(i)}
          className={"sx-eng-a" + (picked === i ? " is-picked" : "")}>
        <FCard padding="var(--sp-6)" elevation={picked === i ? 2 : 1} style={{ height: "100%", display: "flex", flexDirection: "column", background: "transparent", borderColor: "transparent" }}>
          <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
            <span aria-hidden style={{ display: "flex", gap: 2, alignItems: "flex-end", height: 14 }}>
              {[0, 1, 2].map((k) => <span key={k} style={{ width: 5, height: 4 + k * 5, background: k <= i ? "var(--sx-accent)" : "var(--border-strong)" }} />)}
            </span>
            <span className="sx-micro" style={{ color: "var(--text-quiet)" }}>step {i + 1} of 3</span>
            {e.badge && <FTag tone="accent" style={{ marginLeft: "auto" }}>{e.badge.toLowerCase()}</FTag>}
          </div>
          <h3 className="sx-h3" style={{ marginTop: 16 }}>{e.name}</h3>
          <p className="sx-small" style={{ marginTop: 10, color: "var(--text-body)" }}>{e.tagline}</p>
          <p className="sx-micro" style={{ marginTop: 16, color: "var(--text-accent)" }}>{e.terms}</p>
          <p className="sx-caption" style={{ marginTop: 14, color: "var(--text-quiet)", textTransform: "none", letterSpacing: 0, fontFamily: "var(--font-body)" }}>Best for — {e.best}</p>
          <ul className="sx-small" style={{ margin: "16px 0 0", padding: 0, listStyle: "none", display: "grid", gap: 8, borderTop: "1px solid var(--border-default)", paddingTop: 16 }}>
            {e.includes.map((it) => (
              <li key={it} style={{ display: "grid", gridTemplateColumns: "14px 1fr", gap: 8, color: "var(--text-body)" }}>
                <span aria-hidden className="sx-micro" style={{ color: "var(--sx-accent)" }}>—</span>{it}
              </li>
            ))}
          </ul>
          <p className="sx-caption" style={{ marginTop: 18, padding: 14, background: "var(--surface-raised)", borderRadius: "var(--r-control)", color: "var(--text-body)", textTransform: "none", letterSpacing: 0, fontFamily: "var(--font-body)", textWrap: "pretty" }}>
            <span style={{ color: "var(--text-strong)" }}>You end up with — </span>{e.outcome}
          </p>
          <span className="sx-eng-ctawrap"><span className="sx-eng-cta">{picked === i ? "Selected" : e.cta}</span></span>
        </FCard>
        </button>
      ))}
    </div>
  );
}

/* ── four tiers we build, as a table view companion ─────────────────────── */
/* A pipeline is a sequence, so the colour is a journey, not a set of labels:
   accent ("detected") resolving into field ("measured, good") step by step. */
const PROC_STEPS = 6;
const PROC_HUE = Array.from({ length: PROC_STEPS }, (_, i) =>
  `color-mix(in oklab, var(--sx-accent) ${100 - Math.round((i * 100) / (PROC_STEPS - 1))}%, var(--sx-field))`);

/* The engagement as a track, not a grid: six nodes on one rail, a pulse running
   the length of it, and each stage hanging off its own node. */
function ProcessSteps({ mobile }) {
  const steps = D.process;
  if (mobile) {
    return (
      <ol className="sx-proc-m" style={{ listStyle: "none", margin: 0, padding: 0, display: "grid", gap: 0 }}>
        {steps.map((p, i) => (
          <li key={p.step} style={{ "--hue": PROC_HUE[i % 6], display: "grid", gridTemplateColumns: "26px minmax(0,1fr)", gap: 12, paddingBottom: i < steps.length - 1 ? 20 : 0 }}>
            <span className="sx-proc-mrail">
              <span className="sx-proc-node" />
            </span>
            <div>
              <p className="sx-num" style={{ fontFamily: "var(--font-mono)", fontSize: "var(--t-caption)", color: PROC_HUE[i % 6] }}>{p.step}</p>
              <h3 className="sx-h3" style={{ marginTop: 6, fontSize: "var(--t-body)" }}>{p.title}</h3>
              <p className="sx-small" style={{ marginTop: 6, color: "var(--text-body)" }}>{p.description}</p>
            </div>
          </li>
        ))}
      </ol>
    );
  }
  return (
    <div>
      <div className="sx-proc-rail" aria-hidden>
        <span className="sx-proc-pulse" />
      </div>
      <ol style={{ listStyle: "none", margin: 0, padding: 0, display: "grid", gridTemplateColumns: "repeat(6, minmax(0,1fr))", gap: 18 }}>
        {steps.map((p, i) => (
          <li key={p.step} style={{ "--hue": PROC_HUE[i % 6], position: "relative", paddingTop: 26 }}>
            <span className="sx-proc-node" aria-hidden style={{ position: "absolute", top: -7, left: 0 }} />
            <span className="sx-proc-drop" aria-hidden />
            <p className="sx-num" style={{ fontFamily: "var(--font-mono)", fontSize: "var(--t-caption)", color: PROC_HUE[i % 6] }}>{p.step}</p>
            <h3 className="sx-h3" style={{ marginTop: 8, fontSize: 18, lineHeight: 1.2 }}>{p.title}</h3>
            <p className="sx-small" style={{ marginTop: 8, color: "var(--text-body)" }}>{p.description}</p>
          </li>
        ))}
      </ol>
    </div>
  );
}

Object.assign(window, { PipelineFigure, CapabilityTimeline, SectorLayerHeatmap, SolutionReuse, ComparisonMatrix, EngagementLadder, ProcessSteps, PRACTICE_LAYER });

/* ── the globe, without its ranked bar list ─────────────────────────────── */
function GlobeOnly({ mobile, height }) {
  const ref = React.useRef(null);
  React.useEffect(() => {
    const root = ref.current?.firstElementChild;
    if (!root) return;
    const hide = () => {
      const ul = root.querySelector("ul");
      if (!ul) return;
      let el = ul;
      while (el.parentElement && el.parentElement !== root) el = el.parentElement;
      el.style.display = "none";
    };
    hide();
    const t = setTimeout(hide, 500);
    return () => clearTimeout(t);
  }, []);
  return (
    <div ref={ref}>
      <FGlobe countries={D.countries} height={height || (mobile ? 240 : 380)} mobile={mobile} />
      <ul style={{ listStyle: "none", margin: "18px 0 0", padding: 0, display: "flex", flexWrap: "wrap", gap: 10 }}>
        {D.countries.map((c) => (
          <li key={c.name} className="sx-caption" style={{ display: "inline-flex", alignItems: "center", gap: 8, padding: "4px 10px 4px 6px", border: "1px solid var(--border-default)", borderRadius: "var(--r-control)", color: "var(--text-body)", whiteSpace: "nowrap" }}>
            {c.flag && <img src={c.flag} alt="" width="18" height="13" style={{ display: "block", borderRadius: 2, objectFit: "cover", opacity: 0.92 }} />}
            {c.name}<span className="sx-num" style={{ color: "var(--text-accent)" }}>{c.total}</span>
          </li>
        ))}
      </ul>
    </div>
  );
}
Object.assign(window, { GlobeOnly });

/* ── the stack as a core sample ─────────────────────────────────────────── */
const LAYER_TECH = {
  agents: ["LangChain", "LangGraph", "LangSmith", "LlamaIndex", "vLLM", "Ollama", "Model Context Protocol", "Claude API", "OpenAI API", "Tesseract", "PaddleOCR", "Azure Document Intelligence", "pgvector"],
  ml: ["PyTorch", "TensorFlow", "scikit-learn", "Hugging Face Transformers", "Ultralytics YOLO", "OpenCV", "ONNX Runtime", "OpenVINO", "XGBoost", "pandas", "NumPy"],
  edge: ["ESP32", "STM32", "Raspberry Pi (through Pi 5)", "ESP-IDF", "FreeRTOS", "MQTT", "Modbus RTU/TCP", "BLE", "LoRa", "ThingsBoard", "AWS IoT Core"],
  apps: ["React", "Next.js", "Tailwind CSS", "TypeScript", "TanStack Query", "Recharts", "React Native", "Flutter", "Expo"],
  data: ["PostgreSQL", "Oracle", "SQL Server", "MySQL", "MongoDB", "DynamoDB", "Redis", "Kafka", "RabbitMQ", "Celery"],
  core: ["Python", "Java", "C#", "C", "C++", "FastAPI", "Django", "Spring Boot", "ASP.NET Core", "Node.js", "REST", "gRPC"],
};
/* Layers inherit the three family hues, so a layer is the same colour here as
   it is in the practice dome and the solutions register. */
const LAYER_HUE = { core: "var(--sx-layer-core)", data: "var(--sx-layer-core)", apps: "var(--sx-layer-connected)", edge: "var(--sx-layer-connected)", ml: "var(--sx-layer-intelligence)", agents: "var(--sx-layer-intelligence)" };
const LAYER_ORDER = ["core", "data", "apps", "edge", "ml", "agents"];

/* Six layers as a numbered chain, oldest first: each one is built on the one
   before it, which is the argument the figure has to make. The technologies
   belong to the open step — six lists at once is a wall, not a diagram. */
function StrataFigure({ mobile }) {
  const byId = {};
  D.layers.forEach((l) => { byId[l.id] = l; });
  const steps = LAYER_ORDER.map((id) => byId[id]).filter(Boolean);
  const [open, setOpen] = React.useState(steps[steps.length - 1].id);
  const g = steps.find((s) => s.id === open) || steps[0];
  const hue = LAYER_HUE[g.id];
  return (
    <div>
      <div style={{ display: "grid", gridTemplateColumns: mobile ? "1fr 1fr" : "minmax(0,1fr) 26px minmax(0,1fr) 26px minmax(0,1fr) 26px minmax(0,1fr) 26px minmax(0,1fr) 26px minmax(0,1fr)", gap: mobile ? 8 : 0, alignItems: "stretch" }}>
        {steps.map((l, i) => {
          const on = open === l.id;
          const h = LAYER_HUE[l.id];
          return (
            <React.Fragment key={l.id}>
              <button type="button" onClick={() => setOpen(l.id)} aria-pressed={on}
                style={{ appearance: "none", fontFamily: "var(--font-body)", cursor: "pointer", textAlign: "left", display: "grid", gap: 12, alignContent: "start",
                  padding: mobile ? "14px 13px 15px" : "16px 15px 18px", borderRadius: "var(--r-card)",
                  border: `1px solid ${on ? `color-mix(in oklab, ${h} 62%, transparent)` : "var(--border-default)"}`,
                  background: on ? `color-mix(in oklab, ${h} 12%, var(--surface-card))` : "var(--surface-card)",
                  transition: "background 150ms linear, border-color 150ms linear" }}>
                <span className="sx-num" style={{ fontFamily: "var(--font-mono)", fontSize: "var(--t-caption)", color: h }}>{i + 1}</span>
                <span className="sx-h3" style={{ fontSize: mobile ? "var(--t-body)" : 17, lineHeight: 1.15, color: on ? "var(--text-strong)" : "var(--text-body)" }}>{l.label}</span>
              </button>
              {!mobile && i < steps.length - 1 && (
                <span aria-hidden style={{ display: "grid", placeItems: "center", width: 26, color: "var(--text-quiet)" }}>
                  <svg width="13" height="13" viewBox="0 0 20 20" fill="none" stroke="currentColor" strokeWidth="1.75" strokeLinecap="round" strokeLinejoin="round"><path d="M4 10h11M11 6l4 4-4 4" /></svg>
                </span>
              )}
            </React.Fragment>
          );
        })}
      </div>
      <div style={{ marginTop: mobile ? 16 : 22, borderTop: `2px solid ${hue}`, paddingTop: mobile ? 16 : 20, display: "grid", gap: mobile ? 12 : 20, gridTemplateColumns: mobile ? "1fr" : "minmax(0,3fr) minmax(0,9fr)" }}>
        <p className="sx-h3" style={{ fontSize: mobile ? "var(--t-body)" : "var(--t-h3)" }}>{g.label}</p>
        <ul style={{ listStyle: "none", margin: 0, padding: 0, display: "flex", flexWrap: "wrap", gap: 8 }}>
          {(LAYER_TECH[g.id] || []).map((it) => (
            <li key={it} className="sx-small" style={{ whiteSpace: "nowrap", padding: "6px 12px", borderRadius: "var(--r-control)", color: "var(--text-strong)", border: `1px solid color-mix(in oklab, ${hue} 34%, transparent)`, background: `color-mix(in oklab, ${hue} 10%, transparent)` }}>{it}</li>
          ))}
        </ul>
      </div>
      <p className="sx-caption" style={{ marginTop: 16, color: "var(--text-quiet)", textTransform: "none" }}>Read left to right: 01 is the layer everything else writes to, 06 is the newest work. Pick a step to see what we run in it.</p>
    </div>
  );
}
Object.assign(window, { StrataFigure, LAYER_TECH });
