(function(){
/* FORGE · mittelstand tenant — Act 4 (production floor / build mode + line readiness)
   3 screens registered at end of file. No imports / exports. Babel-standalone.

   Screens
     S-MS-21  /build/routing  — 8-station routing canvas, granite re-grind cell highlighted
     S-MS-22  /build/gates    — 5-gate quality flow editor (Design Review → Production Release)
     S-MS-23  /line/readiness — granite cell shortage, GMN spindle / Heidenhain ETA, dual-source risk panel

   Globals expected at runtime:
     React, getActiveTenant(), useActiveTenant(), navigate(),
     registerMittelstandRoute()  (created by agent #3, registry-router)
     MSCard / MSPill / MSBtn     (created by agent #8, cross-cutting)
     Btn / Pill / StatPill        (existing pump atoms, fallback)

   Style — cool gray palette per spec §10. Mono is privileged: every µm,
   day, euro and part number renders mono with explicit units. No emoji.
   No warm tones. No paper ochre.
*/

const { useState: uSMA4, useEffect: uEMA4, useMemo: uMMA4, useRef: uRMA4 } = React;

/* ════════════════════════════════════════════════════════════════════
   §0 — local cool palette + atoms
   The cross-cutting file (agent #8) will define MSCard / MSPill / MSBtn
   on window. We use them when available, otherwise fall back to local
   inline styles using the §10 oklch tokens directly.
   ──────────────────────────────────────────────────────────────────── */

const _MS_COL = {
  bg:        "oklch(0.97 0.003 250)",
  bg2:       "oklch(0.92 0.004 250)",
  bg3:       "oklch(0.95 0.003 250)",
  ink:       "oklch(0.18 0.01 250)",
  ink2:      "oklch(0.32 0.01 250)",
  ink3:      "oklch(0.48 0.01 250)",
  ink4:      "oklch(0.62 0.005 250)",
  line:      "oklch(0.82 0.005 250)",
  lineSoft:  "oklch(0.88 0.004 250)",
  accent:    "oklch(0.55 0.02  250)",
  warn:      "oklch(0.62 0.13  60)",
  bad:       "oklch(0.55 0.18  25)",
  ok:        "oklch(0.58 0.12  155)",
  info:      "oklch(0.55 0.10  245)",
};

/* Extracted styles (react-doctor: no-inline-exhaustive-style). */
function _msA4PillStyle(c) {
  return {
    display: "inline-flex", alignItems: "center", gap: 4,
    height: 16, padding: "0 6px", borderRadius: 2,
    fontFamily: "var(--font-mono)", fontSize: 12, letterSpacing: "0.05em",
    textTransform: "uppercase",
    color: c,
    background: "color-mix(in oklch, " + c + " 12%, transparent)",
    border: "1px solid color-mix(in oklch, " + c + " 30%, " + _MS_COL.line + ")",
  };
}
function _msA4BtnStyle(isPrimary, disabled) {
  return {
    height: 24,
    padding: "0 10px",
    background: isPrimary ? _MS_COL.ink : _MS_COL.bg3,
    color: isPrimary ? _MS_COL.bg : _MS_COL.ink2,
    border: "1px solid " + (isPrimary ? _MS_COL.ink : _MS_COL.line),
    borderRadius: 2,
    fontFamily: "var(--font-ui)",
    fontSize: 12,
    cursor: disabled ? "default" : "pointer",
    opacity: disabled ? 0.45 : 1,
    letterSpacing: "0.01em",
    display: "inline-flex", alignItems: "center", gap: 5,
  };
}
function _msA4AvatarStyle(s) {
  return {
    display: "inline-flex", alignItems: "center", justifyContent: "center",
    width: s, height: s, borderRadius: "50%",
    background: "color-mix(in oklch, " + _MS_COL.accent + " 12%, " + _MS_COL.bg2 + ")",
    color: _MS_COL.accent,
    border: "1px solid color-mix(in oklch, " + _MS_COL.accent + " 30%, " + _MS_COL.line + ")",
    fontFamily: "var(--font-mono)", fontSize: 12, letterSpacing: "0.04em", fontWeight: 600,
  };
}
function _msA4ToolbarStyle(height) {
  return {
    display: "flex", alignItems: "center", justifyContent: "space-between", gap: 8,
    padding: "6px 12px",
    background: _MS_COL.bg2,
    borderBottom: "1px solid " + _MS_COL.line,
    height: height || 38,
    flexShrink: 0,
  };
}
const _MS_A4_EDIT_STATION_STYLE = {
  display: "grid",
  gridTemplateColumns: "repeat(2, 1fr)",
  gap: 10,
  marginTop: 8,
  padding: 14,
  border: "1px solid " + _MS_COL.line,
  borderRadius: 3,
  background: _MS_COL.bg2,
};
const _MS_A4_TOOL_HEADER_STYLE = {
  display: "grid",
  gridTemplateColumns: "120px 1fr 80px 1fr",
  padding: "6px 12px",
  background: _MS_COL.bg2,
  borderBottom: "1px solid " + _MS_COL.lineSoft,
  fontFamily: "var(--font-mono)", fontSize: 12, letterSpacing: "0.06em",
  color: _MS_COL.ink4, textTransform: "uppercase",
};
const _MS_A4_FIND_BAR_STYLE = {
  display: "flex", alignItems: "center", gap: 6,
  padding: "4px 8px", border: "1px solid " + _MS_COL.line,
  background: _MS_COL.bg, borderRadius: 2, minWidth: 280,
};
function _msA4GateGridHeaderStyle(colTpl) {
  return {
    display: "grid", gridTemplateColumns: colTpl,
    position: "sticky", top: 0, zIndex: 3,
    background: _MS_COL.bg2, borderBottom: "1px solid " + _MS_COL.line,
    height: 30, alignItems: "center",
    fontFamily: "var(--font-mono)", fontSize: 12, letterSpacing: "0.08em",
    color: _MS_COL.ink3, textTransform: "uppercase",
  };
}
const _MS_A4_PHASE_HEADER_STYLE = {
  display: "flex", alignItems: "center", gap: 10,
  padding: "6px 14px",
  background: _MS_COL.bg3,
  borderTop: "1px solid " + _MS_COL.line,
  borderBottom: "1px solid " + _MS_COL.lineSoft,
  fontFamily: "var(--font-mono)", fontSize: 12,
  position: "sticky", top: 30, zIndex: 2,
  cursor: "pointer",
};
const _MS_A4_TOAST_STYLE = {
  position: "fixed", bottom: 24, right: 24,
  background: _MS_COL.ink, color: _MS_COL.bg,
  padding: "8px 14px", borderRadius: 3,
  fontSize: 12,
  boxShadow: "0 6px 20px rgba(20,28,40,0.18)",
  zIndex: 60,
};
const _MS_A4_RISK_BOX_STYLE = {
  marginTop: 10,
  padding: 10, background: _MS_COL.bg2, border: "1px solid " + _MS_COL.line, borderRadius: 2,
  fontSize: 12, color: _MS_COL.ink2, lineHeight: 1.55,
};

function _ms_pill(tone, children) {
  // Use MSPill if cross-cutting provided one
  if (typeof MSPill === "function") return React.createElement(MSPill, { tone }, children);
  if (typeof Pill === "function") return React.createElement(Pill, { tone }, children);
  const map = {
    ok:    _MS_COL.ok,
    warn:  _MS_COL.warn,
    err:   _MS_COL.bad,
    info:  _MS_COL.info,
    mute:  _MS_COL.ink4,
  };
  const c = map[tone] || _MS_COL.ink3;
  return (
    <span style={_msA4PillStyle(c)}>{children}</span>
  );
}

function _ms_btn(props) {
  const { variant, icon, onClick, title, children, disabled } = props || {};
  if (typeof MSBtn === "function") return React.createElement(MSBtn, props);
  if (typeof Btn === "function") return React.createElement(Btn, props);
  const isPrimary = variant === "primary";
  return (
    <button
      onClick={onClick}
      title={title}
      disabled={disabled}
      style={_msA4BtnStyle(isPrimary, disabled)}
    >
      {icon ? <span style={{ fontSize: 12, color: _MS_COL.ink4, letterSpacing: "0.06em", textTransform: "uppercase" }}>{icon}</span> : null}
      {children}
    </button>
  );
}

function _ms_card({ children, padding, style, title }) {
  if (typeof MSCard === "function") return React.createElement(MSCard, { padding, style, title }, children);
  return (
    <div style={{
      background: _MS_COL.bg,
      border: "1px solid " + _MS_COL.line,
      borderRadius: 3,
      padding: padding == null ? 12 : padding,
      ...(style || {}),
    }}>
      {title ? <div style={{
        fontFamily: "var(--font-mono)", fontSize: 12, letterSpacing: "0.08em", textTransform: "uppercase",
        color: _MS_COL.ink3, marginBottom: 8,
      }}>{title}</div> : null}
      {children}
    </div>
  );
}

/* ────────────────────────────────────────────────────────────────────
   §0.1 — small helpers
   ──────────────────────────────────────────────────────────────────── */

function useMsTenant() {
  return useActiveTenant();
}

function _ms_initials(n) {
  if (!n) return "—";
  const parts = String(n).replace(/[^A-Za-zÄÖÜäöüß. ]/g, "").split(/\s+/).filter(Boolean);
  if (!parts.length) return "—";
  const a = parts[0][0] || "";
  const b = parts[1] ? parts[1][0] : (parts[0][1] || "");
  return (a + b).toUpperCase();
}

function _ms_avatar(name, size) {
  const s = size || 22;
  return (
    <span style={_msA4AvatarStyle(s)}>{_ms_initials(name)}</span>
  );
}

function _ms_dot(tone) {
  const map = {
    ok:   _MS_COL.ok,
    warn: _MS_COL.warn,
    err:  _MS_COL.bad,
    info: _MS_COL.info,
    mute: _MS_COL.ink4,
  };
  const c = map[tone] || tone || _MS_COL.ink4;
  return (
    <span style={{
      display: "inline-block", width: 7, height: 7, borderRadius: "50%",
      background: c,
      boxShadow: "0 0 0 2px color-mix(in oklch, " + c + " 18%, transparent)",
      flexShrink: 0,
    }} />
  );
}

function _ms_label(text, color) {
  return (
    <div style={{
      fontFamily: "var(--font-mono)", fontSize: 12, letterSpacing: "0.08em",
      textTransform: "uppercase", color: color || _MS_COL.ink3,
    }}>{text}</div>
  );
}

function _ms_kvRow(k, v, mono) {
  return (
    <div style={{
      display: "flex", justifyContent: "space-between", alignItems: "baseline",
      padding: "4px 10px",
      borderBottom: "1px dashed " + _MS_COL.lineSoft,
      fontSize: 12,
    }}>
      <span style={{ color: _MS_COL.ink4, fontFamily: "var(--font-mono)", fontSize: 12, letterSpacing: "0.05em", textTransform: "uppercase" }}>{k}</span>
      <span style={mono ? { color: _MS_COL.ink2, fontFamily: "var(--font-mono)" } : { color: _MS_COL.ink2 }}>{v}</span>
    </div>
  );
}

function _ms_severityTone(s) {
  if (s === "critical") return "err";
  if (s === "high")     return "warn";
  if (s === "med")      return "info";
  return "mute";
}

function _ms_severityRank(s) {
  if (s === "critical") return 4;
  if (s === "high")     return 3;
  if (s === "med")      return 2;
  if (s === "low")      return 1;
  return 0;
}

/* Toolbar — narrow grey bar of buttons / chips, cool palette */
function _MSToolbar({ children, right, height }) {
  return (
    <div style={_msA4ToolbarStyle(height)}>
      <div style={{ display: "flex", alignItems: "center", gap: 6, flexWrap: "wrap" }}>{children}</div>
      <div style={{ display: "flex", alignItems: "center", gap: 6 }}>{right}</div>
    </div>
  );
}

/* Confirm modal (cool palette overlay) */
function _MSModal({ title, body, onCancel, onConfirm, confirmLabel, danger }) {
  uEMA4(() => {
    const onKey = (e) => { if (e.key === "Escape" && typeof onCancel === "function") onCancel(); };
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, [onCancel]);
  return (
    <div
      role="button"
      tabIndex={0}
      onClick={() => { if (typeof onCancel === "function") onCancel(); }}
      onKeyDown={(e) => { if (e.key === "Enter" || e.key === " ") { e.preventDefault(); if (typeof onCancel === "function") onCancel(); } }}
      style={{
        position: "fixed", inset: 0,
        background: "color-mix(in oklch, " + _MS_COL.ink + " 38%, transparent)",
        display: "flex", alignItems: "center", justifyContent: "center", zIndex: 50,
      }}
    >
      <div
        role="dialog"
        aria-label={title}
        tabIndex={-1}
        onClick={e => e.stopPropagation()}
        onKeyDown={e => e.stopPropagation()}
        style={{
          background: _MS_COL.bg,
          border: "1px solid " + _MS_COL.line,
          borderRadius: 3,
          boxShadow: "0 18px 48px rgba(20,28,40,0.22)",
          width: 480, padding: 18,
        }}
      >
        {_ms_label(title)}
        <div style={{
          marginTop: 8, marginBottom: 16,
          fontSize: 12.5, color: _MS_COL.ink, lineHeight: 1.5,
        }}>{body}</div>
        <div style={{ display: "flex", justifyContent: "flex-end", gap: 6 }}>
          {_ms_btn({ onClick: onCancel, children: "Cancel" })}
          {_ms_btn({
            variant: "primary",
            onClick: onConfirm,
            children: confirmLabel || "Confirm",
          })}
        </div>
      </div>
    </div>
  );
}

/* mono inline input style */
function _ms_inputCell(font) {
  return {
    width: "100%",
    background: "transparent",
    border: "1px solid transparent",
    padding: "4px 6px",
    color: _MS_COL.ink2,
    fontSize: 12,
    fontFamily: font || "inherit",
    outline: 0,
  };
}

function _ms_inputBox(font) {
  return {
    width: "100%",
    padding: "5px 8px",
    border: "1px solid " + _MS_COL.line,
    background: _MS_COL.bg,
    color: _MS_COL.ink,
    borderRadius: 2,
    fontSize: 12,
    fontFamily: font || "inherit",
    outline: 0,
  };
}

/* statpill local — fall back if ui.jsx atom missing */
function _MSStatPill({ label, value, delta, trend, mono }) {
  if (typeof StatPill === "function") {
    return React.createElement(StatPill, { label, value, delta, trend });
  }
  const tone = trend === "down" ? _MS_COL.bad : trend === "up" ? _MS_COL.ok : _MS_COL.ink3;
  return (
    <div style={{
      padding: "8px 10px",
      borderRight: "1px solid " + _MS_COL.lineSoft,
      borderBottom: "1px solid " + _MS_COL.lineSoft,
      background: _MS_COL.bg,
      display: "flex", flexDirection: "column", gap: 2,
    }}>
      {_ms_label(label, _MS_COL.ink4)}
      <div style={{ fontSize: 16, color: _MS_COL.ink, fontFamily: mono ? "var(--font-mono)" : "inherit" }}>{value}</div>
      <div style={{ fontSize: 12, color: tone, fontFamily: "var(--font-mono)", letterSpacing: "0.04em" }}>{delta || ""}</div>
    </div>
  );
}

/* tiny gauge bar */
function _MSGauge({ v, label, target, ok }) {
  const pct = Math.max(0, Math.min(1, v));
  const tone = ok ? _MS_COL.ok : pct > 0.85 ? _MS_COL.ok : pct > 0.65 ? _MS_COL.warn : _MS_COL.bad;
  return (
    <div style={{ display: "flex", flexDirection: "column", gap: 4, minWidth: 0 }}>
      {label && _ms_label(label, _MS_COL.ink4)}
      <div style={{ height: 7, background: _MS_COL.bg2, borderRadius: 2, overflow: "hidden", border: "1px solid " + _MS_COL.lineSoft }}>
        <div style={{ width: (pct * 100).toFixed(1) + "%", height: "100%", background: tone }} />
      </div>
      <div style={{ fontFamily: "var(--font-mono)", fontSize: 12, color: _MS_COL.ink3, display: "flex", justifyContent: "space-between" }}>
        <span>{(pct * 100).toFixed(1)}%</span>
        {target ? <span style={{ color: _MS_COL.ink4 }}>target {target}</span> : null}
      </div>
    </div>
  );
}

/* ════════════════════════════════════════════════════════════════════
   §1 — S-MS-21 · Routing canvas  /build/routing
   8 stations: Receiving → CMM Inspect → Granite Re-grind → Subassy
              → Spindle Align → CMM Final → FAI Test → Pack
   Granite Re-grind highlighted as the new ECO-MS-0017 op.
   ──────────────────────────────────────────────────────────────────── */

function ScreenMittelstandRouting() {
  const T = useMsTenant() || {};

  const baseRouting = uMMA4(() => {
    if (T.routing && T.routing.length) return T.routing;
    // fallback fixture for stub render
    return [
      { id: "ms-s1", seq: 1, name: "Receiving",          owner: "K. Müller",  cycle_min: 14, station_type: "inbound",     bay: "WE-01", takt: 18 },
      { id: "ms-s2", seq: 2, name: "CMM Inspect",        owner: "S. Klein",   cycle_min: 22, station_type: "qa-inbound",  bay: "QC-Z1", takt: 18 },
      { id: "ms-s3", seq: 3, name: "Granite Re-grind",   owner: "D. Becker",  cycle_min: 95, station_type: "machining",   bay: "GR-04", takt: 18, eco: true },
      { id: "ms-s4", seq: 4, name: "Subassy",            owner: "T. Hoffmann",cycle_min: 65, station_type: "assembly",    bay: "AS-12", takt: 18 },
      { id: "ms-s5", seq: 5, name: "Spindle Align",      owner: "F. Weber",   cycle_min: 48, station_type: "alignment",   bay: "AL-03", takt: 18 },
      { id: "ms-s6", seq: 6, name: "CMM Final",          owner: "S. Klein",   cycle_min: 38, station_type: "qa-final",    bay: "QC-Z2", takt: 18 },
      { id: "ms-s7", seq: 7, name: "FAI Test",           owner: "R. Vogt",    cycle_min: 72, station_type: "test",        bay: "TS-01", takt: 18 },
      { id: "ms-s8", seq: 8, name: "Pack",               owner: "L. Schmidt", cycle_min: 18, station_type: "outbound",    bay: "SH-01", takt: 18 },
    ];
  }, [T.routing]);

  // station health: granite re-grind is warn (new op qualifying), others ok except CMM Final has cal due
  const [stations, setStations] = uSMA4(() => baseRouting.map(s => ({
    ...s,
    health: s.id === "ms-s3" ? "warn" : s.id === "ms-s6" ? "warn" : "ok",
  })));
  const [selectedId, setSelectedId] = uSMA4("ms-s3"); // start on granite re-grind, the hero op
  const [edit, setEdit] = uSMA4(() => baseRouting.find(s => s.id === "ms-s3") || baseRouting[0]);
  const [showRelease, setShowRelease] = uSMA4(false);
  const [revName, setRevName] = uSMA4("rev D");

  const [revisions, setRevisions] = uSMA4([
    { id: "rev-A", label: "rev A · 2025-09-12", note: "lift from MTL-220 Rev B routing baseline",                  author: "D. Becker", current: false },
    { id: "rev-B", label: "rev B · 2025-11-04", note: "added incoming CMM gate after granite blank vendor change", author: "D. Becker", current: false },
    { id: "rev-C", label: "rev C · 2026-01-22", note: "Rev C release; flatness ±5 µm, single lap pass",            author: "D. Becker", current: false },
    { id: "rev-D-draft", label: "rev D · DRAFT 2026-03-03", note: "ECO-MS-0017 — granite re-grind op inserted s3, flatness ±3 µm", author: "D. Becker", current: true },
  ]);

  uEMA4(() => {
    const s = stations.find(x => x.id === selectedId);
    if (s) setEdit({ ...s });
  }, [selectedId, stations]);

  uEMA4(() => {
    const onTenant = () => setShowRelease(false);
    window.addEventListener("forge:tenant-change", onTenant);
    return () => window.removeEventListener("forge:tenant-change", onTenant);
  }, []);

  function applyEdit() {
    setStations(prev => prev.map(s => s.id === edit.id ? { ...s, ...edit } : s));
  }

  function releaseRevision() {
    setRevisions(prev => [
      ...prev.map(r => ({ ...r, current: false })),
      {
        id: revName.toLowerCase().replace(/\s+/g, "-"),
        label: revName + " · " + new Date().toISOString().slice(0, 10),
        note: "release via routing canvas — ECO-MS-0017 frozen",
        author: "D. Becker",
        current: true,
      },
    ]);
    setShowRelease(false);
  }

  const totalCycle = stations.reduce((a, s) => a + (Number(s.cycle_min) || 0), 0);
  const taktMin = 18; // 22 mills/shift target → calculated takt anchor for the chart
  const totalTakt = stations.length * taktMin;

  // SVG canvas constants — 8 stations, wider than pump
  const boxW = 132, boxH = 100, gap = 24;
  const canvasW = stations.length * boxW + (stations.length - 1) * gap + 40;
  const canvasH = 230;

  return (
    <div style={{ display: "flex", flexDirection: "column", height: "100%", minHeight: 0, background: _MS_COL.bg }}>

      <_MSToolbar
        right={
          <>
            {_ms_btn({ icon: "Diff", children: "Compare to rev C" })}
            {_ms_btn({ icon: "File", children: "Save as template" })}
            {_ms_btn({ variant: "primary", icon: "Git", onClick: () => setShowRelease(true), children: "Release routing " + revName })}
          </>
        }
      >
        {_ms_btn({ icon: "Plus", children: "Add station" })}
        {_ms_btn({ icon: "Flow", children: "Insert split / merge" })}
        {_ms_btn({ icon: "Sparkle", children: "Auto-balance cycle" })}
        <span style={{ color: _MS_COL.ink4, fontSize: 12, marginLeft: 8 }}>
          ROUT-MTL-220-D ·{" "}
          <b style={{ color: _MS_COL.ink2 }}>{revisions.find(r => r.current)?.label || "rev D · DRAFT"}</b>
          &nbsp;·&nbsp;cycle <span style={{ fontFamily: "var(--font-mono)" }}>{totalCycle} min</span>
          &nbsp;·&nbsp;takt <span style={{ fontFamily: "var(--font-mono)" }}>{taktMin} min</span>
          &nbsp;·&nbsp;<span style={{ color: _MS_COL.ink3 }}>{stations.length} stations</span>
        </span>
      </_MSToolbar>

      {/* Body */}
      <div style={{ flex: 1, display: "grid", gridTemplateColumns: "1fr 340px", minHeight: 0 }}>

        {/* Canvas + edit panel */}
        <div style={{ display: "flex", flexDirection: "column", minHeight: 0, overflow: "auto" }}>

          <_MSRoutingCanvas stations={stations} selectedId={selectedId} setSelectedId={setSelectedId} canvasW={canvasW} canvasH={canvasH} boxW={boxW} boxH={boxH} gap={gap} totalCycle={totalCycle} taktMin={taktMin} />

          {/* Edit panel for selected station */}
          <div style={{ padding: 16, flex: 1, overflow: "auto", background: _MS_COL.bg }}>
            {_ms_label("EDIT STATION · " + (edit.id || "—"))}
            <div style={_MS_A4_EDIT_STATION_STYLE}>
              <div>
                {_ms_label("Station name", _MS_COL.ink4)}
                <input id="ms-act4-f1" name="ms-act4-f1"
                  value={edit.name || ""}
                  onChange={e => setEdit(prev => ({ ...prev, name: e.target.value }))}
                  style={{ ..._ms_inputBox(), marginTop: 4 }}
                />
              </div>
              <div>
                {_ms_label("Owner", _MS_COL.ink4)}
                <input id="ms-act4-f2" name="ms-act4-f2"
                  value={edit.owner || ""}
                  onChange={e => setEdit(prev => ({ ...prev, owner: e.target.value }))}
                  style={{ ..._ms_inputBox(), marginTop: 4 }}
                />
              </div>
              <div>
                {_ms_label("Cycle (min)", _MS_COL.ink4)}
                <input id="ms-act4-f3" name="ms-act4-f3"
                  type="number"
                  value={edit.cycle_min || 0}
                  onChange={e => setEdit(prev => ({ ...prev, cycle_min: Number(e.target.value) || 0 }))}
                  style={{ ..._ms_inputBox("var(--font-mono)"), marginTop: 4 }}
                />
              </div>
              <div>
                {_ms_label("Takt (min)", _MS_COL.ink4)}
                <input id="ms-act4-f4" name="ms-act4-f4"
                  type="number"
                  value={edit.takt || taktMin}
                  onChange={e => setEdit(prev => ({ ...prev, takt: Number(e.target.value) || 0 }))}
                  style={{ ..._ms_inputBox("var(--font-mono)"), marginTop: 4 }}
                />
              </div>
              <div>
                {_ms_label("Bay", _MS_COL.ink4)}
                <input id="ms-act4-f5" name="ms-act4-f5"
                  value={edit.bay || ""}
                  onChange={e => setEdit(prev => ({ ...prev, bay: e.target.value }))}
                  style={{ ..._ms_inputBox("var(--font-mono)"), marginTop: 4 }}
                />
              </div>
              <div>
                {_ms_label("Station type", _MS_COL.ink4)}
                <select id="ms-act4-f6" name="ms-act4-f6"
                  value={edit.station_type || "machining"}
                  onChange={e => setEdit(prev => ({ ...prev, station_type: e.target.value }))}
                  style={{ ..._ms_inputBox(), marginTop: 4 }}
                >
                  <option value="inbound">inbound</option>
                  <option value="qa-inbound">qa-inbound</option>
                  <option value="machining">machining</option>
                  <option value="assembly">assembly</option>
                  <option value="alignment">alignment</option>
                  <option value="qa-final">qa-final</option>
                  <option value="test">test</option>
                  <option value="outbound">outbound</option>
                </select>
              </div>
              <div style={{ gridColumn: "1 / span 2", display: "flex", justifyContent: "space-between", alignItems: "center", marginTop: 4 }}>
                <span style={{ fontSize: 12, color: _MS_COL.ink4 }}>
                  Linked CTQ gates:{" "}
                  <b style={{ color: _MS_COL.ink2, fontFamily: "var(--font-mono)" }}>
                    {(T.quality_gates || []).filter(g => g.station === edit.id).length}
                  </b>
                </span>
                <div style={{ display: "flex", gap: 6 }}>
                  {_ms_btn({
                    onClick: () => {
                      const s = stations.find(x => x.id === selectedId);
                      if (s) setEdit({ ...s });
                    },
                    children: "Discard",
                  })}
                  {_ms_btn({
                    variant: "primary",
                    onClick: applyEdit,
                    children: "Save · bumps to " + revName,
                  })}
                </div>
              </div>
            </div>

            {/* tooling + setup detail for selected station */}
            <div style={{ marginTop: 18 }}>
              {_ms_label("STATION TOOLING & SETUP")}
              <div style={{
                marginTop: 6,
                border: "1px solid " + _MS_COL.line, borderRadius: 3,
                background: _MS_COL.bg, overflow: "hidden",
              }}>
                {_renderStationTooling(edit.id)}
              </div>
            </div>

            {/* Station metrics */}
            <div style={{ marginTop: 18 }}>
              {_ms_label("STATION METRICS · LAST 7 D")}
              <div style={{
                marginTop: 6,
                display: "grid",
                gridTemplateColumns: "repeat(4, 1fr)",
                border: "1px solid " + _MS_COL.line, borderRadius: 3, overflow: "hidden",
                background: _MS_COL.bg,
              }}>
                <_MSStatPill label="actual cycle" value={(edit.cycle_min * 1.06).toFixed(0) + " min"} delta="+6%"   trend="up" mono />
                <_MSStatPill label="first-pass yield" value="92.4%"                                   delta="−1.6 pt" trend="down" mono />
                <_MSStatPill label="ncr count" value="2"                                              delta="+1 wk"   trend="up" mono />
                <_MSStatPill label="utilization" value="0.74"                                         delta="+0.04"   trend="up" mono />
              </div>
            </div>

            {/* Downstream impact panel */}
            <div style={{ marginTop: 18 }}>
              {_ms_label("DOWNSTREAM IMPACT IF EDITED")}
              <ul style={{
                margin: "6px 0 0 0", padding: 0, listStyle: "none",
                border: "1px solid " + _MS_COL.line, borderRadius: 3, background: _MS_COL.bg,
              }}>
                {[
                  { tone: "warn", text: "WO-MTL-2401 · MAHLE batch-1 · 12 units · in-progress · re-fixturing required" },
                  { tone: "info", text: "WO-MTL-2402..2412 · scheduled batch-1 · 11 units · shift A queue" },
                  { tone: "info", text: "WO-MTL-2413..2424 · batch-2 release · pending FY split" },
                  { tone: "warn", text: "Control plan CP-MTL-220-D needs re-validation against rev D" },
                  { tone: "info", text: "PFMEA · granite-flatness branch updated to severity 8 (was 6)" },
                ].map((t) => (
                  <li key={t.text} style={{
                    padding: "8px 12px",
                    borderBottom: "1px dashed " + _MS_COL.lineSoft,
                    fontSize: 12, color: _MS_COL.ink2,
                    display: "flex", alignItems: "center", gap: 8,
                  }}>
                    {_ms_dot(t.tone)}
                    {t.text}
                  </li>
                ))}
              </ul>
            </div>
          </div>
        </div>

        <_MSRoutingRail revisions={revisions} revName={revName} setRevName={setRevName} setShowRelease={setShowRelease} />
      </div>

      {showRelease && (
        <_MSModal
          title="Release routing"
          body={
            <span>
              Affects <b>WO-MTL-2401</b> and <b>11 others</b> currently scheduled on rev C.
              New WOs after release will use <b>{revName}</b>. Existing WOs continue on rev C unless re-pegged.
              Granite cell rerouting required for the re-grind op. Continue?
            </span>
          }
          onCancel={() => setShowRelease(false)}
          onConfirm={releaseRevision}
          confirmLabel={"Release " + revName}
        />
      )}
    </div>
  );
}

function _MSRoutingCanvas({ stations, selectedId, setSelectedId, canvasW, canvasH, boxW, boxH, gap, totalCycle, taktMin }) {
  return (
    <div style={{ padding: 18, background: _MS_COL.bg2, borderBottom: "1px solid " + _MS_COL.line }}>
      <svg
        viewBox={"0 0 " + canvasW + " " + canvasH}
        width="100%"
        height={canvasH}
        style={{ display: "block" }}
      >
        <defs>
          <pattern id="msrcg" width="20" height="20" patternUnits="userSpaceOnUse">
            <path d="M 20 0 L 0 0 0 20" fill="none" stroke={_MS_COL.lineSoft} strokeWidth="0.5" />
          </pattern>
          <marker id="msrc-arrow" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto">
            <path d="M0,0 L10,5 L0,10 Z" fill={_MS_COL.ink3} />
          </marker>
          <pattern id="msrcg-eco" width="6" height="6" patternUnits="userSpaceOnUse" patternTransform="rotate(35)">
            <line x1="0" y1="0" x2="0" y2="6" stroke={_MS_COL.warn} strokeWidth="1" opacity="0.4" />
          </pattern>
        </defs>
        <rect x="0" y="0" width={canvasW} height={canvasH} fill="url(#msrcg)" />
        {stations.map((s, i) => {
          if (i === stations.length - 1) return null;
          const x1 = 20 + (i + 1) * boxW + i * gap;
          const x2 = x1 + gap;
          const y = 60 + boxH / 2;
          return (
            <line key={"msconn-" + i} x1={x1} y1={y} x2={x2 - 4} y2={y}
                  stroke={_MS_COL.ink3} strokeWidth="1.2" markerEnd="url(#msrc-arrow)" />
          );
        })}
        {stations.map((s, i) => {
          const x = 20 + i * (boxW + gap);
          const y = 60;
          const sel = s.id === selectedId;
          const tone = s.health === "warn" ? _MS_COL.warn : s.health === "err" ? _MS_COL.bad : _MS_COL.ok;
          const isEco = !!s.eco;
          return (
            <g key={s.id} style={{ cursor: "pointer" }} onClick={() => setSelectedId(s.id)}>
              {isEco && (
                <rect
                  x={x - 2} y={y - 2}
                  width={boxW + 4} height={boxH + 4}
                  rx="4"
                  fill="url(#msrcg-eco)"
                />
              )}
              <rect
                x={x} y={y}
                width={boxW} height={boxH}
                rx="3"
                fill={_MS_COL.bg}
                stroke={sel ? _MS_COL.accent : isEco ? _MS_COL.warn : _MS_COL.line}
                strokeWidth={sel ? "1.6" : isEco ? "1.4" : "1"}
              />
              <text x={x + 8} y={y + 16} fontSize="9.5" fontFamily="var(--font-mono)" fill={_MS_COL.ink4} letterSpacing="0.06em">
                {("S" + s.seq).toUpperCase()} · {s.station_type}
              </text>
              <text x={x + 8} y={y + 36} fontSize="11.5" fontWeight="600" fill={_MS_COL.ink}>
                {s.name.length > 18 ? s.name.slice(0, 17) + "…" : s.name}
              </text>
              {isEco && (
                <text x={x + boxW - 8} y={y + 16} fontSize="8.5" textAnchor="end" fontFamily="var(--font-mono)" fill={_MS_COL.warn} letterSpacing="0.08em">
                  ECO-MS-0017
                </text>
              )}
              <circle cx={x + boxW - 14} cy={y + 30} r="4" fill={tone} />
              <circle cx={x + 16} cy={y + boxH - 22} r="9"
                fill={"color-mix(in oklch, " + _MS_COL.accent + " 14%, " + _MS_COL.bg2 + ")"}
                stroke={"color-mix(in oklch, " + _MS_COL.accent + " 32%, " + _MS_COL.line + ")"}
              />
              <text x={x + 16} y={y + boxH - 18} fontSize="8.5" textAnchor="middle"
                fontFamily="var(--font-mono)" fill={_MS_COL.accent} fontWeight="600">
                {_ms_initials(s.owner)}
              </text>
              <text x={x + 30} y={y + boxH - 26} fontSize="10" fill={_MS_COL.ink3}>{s.owner}</text>
              <text x={x + 30} y={y + boxH - 14} fontSize="10" fontFamily="var(--font-mono)" fill={_MS_COL.ink2}>
                {s.cycle_min} min
              </text>
              <text x={x + 30} y={y + boxH - 4} fontSize="9" fontFamily="var(--font-mono)" fill={_MS_COL.ink4} letterSpacing="0.04em">
                bay {s.bay}
              </text>
            </g>
          );
        })}
        <text x="20" y="208" fontSize="10" fill={_MS_COL.ink4} fontFamily="var(--font-mono)" letterSpacing="0.06em">
          CYCLE {totalCycle} MIN · TAKT {taktMin} MIN · CRITICAL PATH s3 GRANITE RE-GRIND ({Math.round(95 / taktMin * 10) / 10}× TAKT)
        </text>
        <text x="20" y="222" fontSize="10" fill={_MS_COL.warn} fontFamily="var(--font-mono)" letterSpacing="0.06em">
          ECO-MS-0017 · GRANITE BASE 10.01 + CROSS-BEAM 10.02 · ±5 µm → ±3 µm · TWO-PASS LAP + RE-GRIND
        </text>
      </svg>
    </div>
  );
}

function _MSRoutingRail({ revisions, revName, setRevName, setShowRelease }) {
  return (
    <div style={{
      borderLeft: "1px solid " + _MS_COL.line,
      background: _MS_COL.bg2,
      display: "flex", flexDirection: "column", minHeight: 0,
    }}>
      <div style={{ padding: "12px 14px", borderBottom: "1px solid " + _MS_COL.line }}>
        {_ms_label("VERSION HISTORY")}
        <div style={{ display: "flex", alignItems: "center", gap: 6, marginTop: 6 }}>
          <input id="ms-act4-f7" name="ms-act4-f7"
            value={revName}
            onChange={e => setRevName(e.target.value)}
            style={{ ..._ms_inputBox("var(--font-mono)"), flex: 1 }}
          />
          {_ms_btn({ variant: "primary", onClick: () => setShowRelease(true), children: "Release" })}
        </div>
      </div>

      <div style={{ flex: 1, overflow: "auto" }}>
        {revisions.slice().reverse().map(r => (
          <div key={r.id} style={{
            padding: "10px 14px",
            borderBottom: "1px solid " + _MS_COL.lineSoft,
            background: r.current ? "color-mix(in oklch, " + _MS_COL.accent + " 6%, transparent)" : "transparent",
          }}>
            <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center" }}>
              <span style={{ fontFamily: "var(--font-mono)", fontSize: 12, color: _MS_COL.ink }}>{r.label}</span>
              {r.current && _ms_pill("ok", "current")}
            </div>
            <div style={{ fontSize: 12, color: _MS_COL.ink3, marginTop: 4 }}>{r.note}</div>
            <div style={{ fontSize: 12, color: _MS_COL.ink4, marginTop: 4, fontFamily: "var(--font-mono)", letterSpacing: "0.05em" }}>by {r.author}</div>
          </div>
        ))}
      </div>

      <div style={{ padding: "12px 14px", borderTop: "1px solid " + _MS_COL.line, background: _MS_COL.bg3 }}>
        {_ms_label("RELEASE NOTES")}
        <ul style={{ margin: "6px 0 0 0", padding: "0 0 0 14px", fontSize: 12, color: _MS_COL.ink3, lineHeight: 1.6 }}>
          <li>Release locks the routing for new WO-MTL-* scheduling.</li>
          <li>Active WOs continue against the rev they were started on.</li>
          <li>Control plan CP-MTL-220-D & PFMEA links auto-revalidate.</li>
          <li>IATF 16949 PPAP Level 3 re-submission triggered for {"±"}3 µm change.</li>
        </ul>
      </div>
    </div>
  );
}

/* per-station tooling + setup detail. Real-feel mil-shop fixture content. */
function _renderStationTooling(stationId) {
  const map = {
    "ms-s1": [
      { tag: "TLG-WE-01", desc: "Surface-plate · granite class 0 · 1000×630 mm",     status: "ready",   cal: "2026-04-10 · DAkkS cert" },
      { tag: "MTL-WE-02", desc: "Mahr Millimar C1216 dial gauge · resolution 0.1 µm", status: "ready",   cal: "2026-04-22" },
      { tag: "MTL-WE-03", desc: "Granite-blank tilt cradle · 200 kg payload",          status: "ready",   cal: "n/a · structural" },
    ],
    "ms-s2": [
      { tag: "CMM-Z1-A",  desc: "Zeiss UPMC Carat · 850 × 700 × 600 mm · MPE 0.6 µm", status: "ready",   cal: "2026-04-15 · ISO 10360-2" },
      { tag: "PRB-Z1-01", desc: "VAST XT gold probe · stylus M5 · 50 mm",              status: "ready",   cal: "2026-04-15" },
      { tag: "PRG-Z1-G",  desc: "DMIS plan INS-MTL-220-D-01 · 27 features",            status: "active",  cal: "rev D · 2026-03-04" },
    ],
    "ms-s3": [
      { tag: "GR-04-LAP", desc: "Lapmaster 36-DR rotary lap · cast-iron plate",         status: "ready",   cal: "2026-04-19 · plate flatness 1.5 µm" },
      { tag: "GR-04-RGD", desc: "Re-grind diamond wheel D-126 · binder MD8",            status: "in-prep", cal: "fitted 2026-03-01 · 1.4 / 8 h dressed" },
      { tag: "GR-04-LST", desc: "Microabrasive lap stones · grade 600 · qty 24",        status: "short",   cal: "consumable · reorder open" },
      { tag: "GR-04-CMM", desc: "Portable CMM · API Radian Pro tracker",                status: "ready",   cal: "2026-04-21 · ASME B89.4.19" },
    ],
    "ms-s4": [
      { tag: "AS-12-FXT", desc: "Bridge-mill subassy fixture · 1.4-tonne",              status: "ready",   cal: "2026-04-09 · annual" },
      { tag: "AS-12-TRQ", desc: "Hydraulic torque wrench 50–500 Nm · 4 ×",              status: "ready",   cal: "2026-04-12" },
      { tag: "AS-12-SLG", desc: "Spreader sling 2 t · 3-leg",                            status: "ready",   cal: "2026-03-28 · LOLER" },
    ],
    "ms-s5": [
      { tag: "AL-03-FRO", desc: "FARO Vantage Max laser tracker · range 80 m",           status: "ready",   cal: "2026-04-04 · ASME B89.4.19" },
      { tag: "AL-03-CRY", desc: "Renishaw QC20-W ballbar · 100 / 150 / 300 mm",          status: "ready",   cal: "2026-04-02" },
      { tag: "AL-03-RNT", desc: "Heidenhain LC 415 reference encoder · linked",          status: "ready",   cal: "rev controller · 2026-03-12" },
    ],
    "ms-s6": [
      { tag: "CMM-Z2-A",  desc: "Zeiss Prismo Navigator · 1200 × 1000 × 800 mm",         status: "ready",   cal: "2026-04-18" },
      { tag: "PRB-Z2-01", desc: "Probehead RDS rotary · A0/B0 to A105/B180",              status: "warn",    cal: "due 2026-05-03 — 8 d to expiry" },
      { tag: "PRG-Z2-G",  desc: "DMIS plan INS-MTL-220-D-02 · 41 features",               status: "active",  cal: "rev D · 2026-03-04" },
    ],
    "ms-s7": [
      { tag: "TS-01-BBR", desc: "Renishaw QC20-W ballbar · contouring test",              status: "ready",   cal: "2026-04-02" },
      { tag: "TS-01-VIB", desc: "PCB 356A16 tri-axial accel · 12 k rpm spindle test",      status: "ready",   cal: "2026-03-30" },
      { tag: "TS-01-LCK", desc: "Heidenhain LC 415 linear encoder reference · X/Y/Z",      status: "ready",   cal: "2026-03-12" },
      { tag: "TS-01-LOG", desc: "TNC 640 FAT log capture script · ISO 230-2 § 6",          status: "active",  cal: "rev D" },
    ],
    "ms-s8": [
      { tag: "SH-01-CRT", desc: "Plywood seaworthy crate · 4 × 2.5 × 2.8 m",               status: "ready",   cal: "ISPM-15 stamp current" },
      { tag: "SH-01-DSC", desc: "Desiccant + VCI · 24-month coverage",                      status: "ready",   cal: "stock 14 sets" },
      { tag: "SH-01-SHK", desc: "ShockWatch 25g indicator · qty 4 / unit",                  status: "ready",   cal: "stock 96" },
    ],
  };
  const items = map[stationId] || [];
  if (!items.length) {
    return (
      <div style={{ padding: 14, fontSize: 12, color: _MS_COL.ink4 }}>
        No tooling registered yet for this station.
      </div>
    );
  }
  return (
    <>
      <div style={_MS_A4_TOOL_HEADER_STYLE}>
        <div>Tag</div>
        <div>Description</div>
        <div>Status</div>
        <div>Calibration</div>
      </div>
      {items.map(t => (
        <div key={t.tag} style={{
          display: "grid",
          gridTemplateColumns: "120px 1fr 80px 1fr",
          padding: "7px 12px",
          borderBottom: "1px solid " + _MS_COL.lineSoft,
          alignItems: "center",
          fontSize: 12,
        }}>
          <div style={{ fontFamily: "var(--font-mono)", color: _MS_COL.ink3, fontSize: 12 }}>{t.tag}</div>
          <div style={{ color: _MS_COL.ink2 }}>{t.desc}</div>
          <div>
            {t.status === "ready"   && _ms_pill("ok",   "ready")}
            {t.status === "active"  && _ms_pill("info", "active")}
            {t.status === "in-prep" && _ms_pill("warn", "in-prep")}
            {t.status === "warn"    && _ms_pill("warn", "due")}
            {t.status === "short"   && _ms_pill("err",  "short")}
          </div>
          <div style={{ fontFamily: "var(--font-mono)", color: _MS_COL.ink3, fontSize: 12 }}>{t.cal}</div>
        </div>
      ))}
    </>
  );
}

/* ════════════════════════════════════════════════════════════════════
   §2 — S-MS-22 · Quality gates editor  /build/gates
   5-gate sequence per onboarding.jsx:447 :
     Design Review → Prototype Approval → Validation Test → FAI → Production Release
   Each gate carries CTQ rows with µm specs, instruments, ref docs, severity.
   Bulk edit, add new gate, save commits state.
   ──────────────────────────────────────────────────────────────────── */

const MS_GATE_PHASES = [
  {
    phase_id: "g1-design-review",
    name: "Design Review",
    seq: 1,
    desc: "Engineering CAD release · drawing pack frozen · DFMEA closed.",
    chair: "R. Vogt",
    target_date: "2025-11-04",
    state: "passed",
    standards: ["ISO 9001 §8.3", "IATF 16949 §8.3"],
    artifacts: ["3D PMI pack v.D", "DFMEA-MTL-220-D", "Drawing index DRW-MTL-220-D"],
  },
  {
    phase_id: "g2-prototype-approval",
    name: "Prototype Approval",
    seq: 2,
    desc: "First-build prototype validated against design intent on a representative cell.",
    chair: "D. Becker",
    target_date: "2026-02-12",
    state: "passed",
    standards: ["ISO 9001 §8.3.4", "EN ISO 230-1"],
    artifacts: ["Prototype-1 build report", "Geometric pre-acceptance ISO 230-1", "ECO-MS-0017 issuance"],
  },
  {
    phase_id: "g3-validation-test",
    name: "Validation Test",
    seq: 3,
    desc: "Cell-level validation · process capability Cp/Cpk · vibration trial run.",
    chair: "S. Klein",
    target_date: "2026-04-30",
    state: "in-progress",
    standards: ["ISO 9001 §8.5.1", "EN ISO 230-2", "EN ISO 230-4"],
    artifacts: ["Cp/Cpk study granite re-grind", "12 k rpm vibration log", "PFMEA rev D"],
  },
  {
    phase_id: "g4-fai",
    name: "FAI",
    seq: 4,
    desc: "First Article Inspection · IATF/AS9102 form set · CMM dimensional report · ballbar.",
    chair: "S. Klein",
    target_date: "2026-08-14",
    state: "scheduled",
    standards: ["IATF 16949 PPAP Level 3", "AS9102 (adapted)", "EN ISO 230-2"],
    artifacts: ["AS9102 forms 1/2/3", "Zeiss UPMC dimensional report", "Renishaw ballbar trace", "TNC 640 FAT log"],
  },
  {
    phase_id: "g5-production-release",
    name: "Production Release",
    seq: 5,
    desc: "Series-production release · control plan locked · serial run authorisation.",
    chair: "R. Vogt",
    target_date: "2026-09-02",
    state: "scheduled",
    standards: ["ISO 9001 §8.5.6", "IATF 16949 §8.5.6", "CE / Machinery Directive 2006/42/EC"],
    artifacts: ["CP-MTL-220-D control plan", "CE Declaration of Conformity", "Serial-run authorisation memo"],
  },
];

const MS_GATE_CTQS_BASE = [
  // Gate 1 — Design Review
  { gate_id: "G1-DR-01", phase: "g1-design-review",     station: "ms-s2", ctq_param: "Granite base flatness — drawing call-out", instrument: "Drawing review · GD&T A|B|C", spec: "±3 µm over 1.0 m", ref_doc: "DRW-MTL-220-D-001 r.D", effect_if_failed: "Vibration > 0.8 mm/s RMS at 12 k rpm",     severity: "critical" },
  { gate_id: "G1-DR-02", phase: "g1-design-review",     station: "ms-s2", ctq_param: "Cross-beam flatness — drawing call-out",   instrument: "Drawing review · GD&T A|B|C", spec: "±3 µm over 1.4 m", ref_doc: "DRW-MTL-220-D-002 r.D", effect_if_failed: "Bridge twist couples into Y-axis straightness",  severity: "critical" },
  { gate_id: "G1-DR-03", phase: "g1-design-review",     station: "ms-s5", ctq_param: "Spindle-to-C-axis alignment tolerance",     instrument: "Drawing review · concentric Ø",      spec: "0.005° / Ø ≤ 4 µm TIR",  ref_doc: "DRW-MTL-220-D-050 r.D", effect_if_failed: "5-axis centring drift on multi-face parts",       severity: "high"     },
  { gate_id: "G1-DR-04", phase: "g1-design-review",     station: "ms-s7", ctq_param: "Vibration acceptance limit at contouring",  instrument: "Drawing review · spec table",         spec: "≤ 0.8 mm/s RMS · 12 k rpm", ref_doc: "SPC-MTL-220-D-VIB",  effect_if_failed: "Customer rejects unit at acceptance",            severity: "critical" },

  // Gate 2 — Prototype Approval
  { gate_id: "G2-PA-01", phase: "g2-prototype-approval", station: "ms-s2", ctq_param: "Incoming granite blank flatness",          instrument: "Surface plate · Mahr C1216",          spec: "≤ 5 µm over 1.0 m",      ref_doc: "INS-MTL-220-D-IN",  effect_if_failed: "Reject blank · NCR + RTV to foundry",            severity: "high"     },
  { gate_id: "G2-PA-02", phase: "g2-prototype-approval", station: "ms-s3", ctq_param: "Granite re-grind plate parallelism",        instrument: "Lapmaster 36-DR feedback",            spec: "≤ 2 µm parallel · 1.0 m", ref_doc: "PRC-MTL-220-D-LAP", effect_if_failed: "Two-pass lap fails to converge",                  severity: "high"     },
  { gate_id: "G2-PA-03", phase: "g2-prototype-approval", station: "ms-s3", ctq_param: "Lap-stone grade qualification",             instrument: "Surface roughness Ra · Mitutoyo SJ-410", spec: "Ra ≤ 0.6 µm",         ref_doc: "PRC-MTL-220-D-LAP", effect_if_failed: "Surface scoring · re-lap required",               severity: "med"      },
  { gate_id: "G2-PA-04", phase: "g2-prototype-approval", station: "ms-s4", ctq_param: "Bridge subassy bolt torque",                 instrument: "Hydraulic torque wrench 500 Nm",       spec: "420 ± 8 Nm · 16 bolts", ref_doc: "PRC-MTL-220-D-AS",  effect_if_failed: "Bridge pre-load drift over thermal cycle",        severity: "med"      },

  // Gate 3 — Validation Test
  { gate_id: "G3-VT-01", phase: "g3-validation-test",    station: "ms-s3", ctq_param: "Granite finish-lap flatness measured",      instrument: "API Radian Pro tracker",              spec: "≤ 3 µm over 1.0 m",      ref_doc: "INS-MTL-220-D-02", effect_if_failed: "Auto-NCR · re-lap or scrap blank",                severity: "critical" },
  { gate_id: "G3-VT-02", phase: "g3-validation-test",    station: "ms-s5", ctq_param: "Spindle radial run-out at 24 k rpm",        instrument: "FARO Vantage Max + capacitive probe", spec: "≤ 4 µm TIR",             ref_doc: "INS-MTL-220-D-50", effect_if_failed: "Auto-NCR · spindle reseat",                       severity: "critical" },
  { gate_id: "G3-VT-03", phase: "g3-validation-test",    station: "ms-s5", ctq_param: "C-axis to spindle nose alignment",          instrument: "Renishaw QC20-W ballbar",             spec: "≤ 0.005° / Ø ≤ 4 µm TIR", ref_doc: "INS-MTL-220-D-50", effect_if_failed: "Multi-face job centring loss",                    severity: "high"     },
  { gate_id: "G3-VT-04", phase: "g3-validation-test",    station: "ms-s7", ctq_param: "Vibration RMS at high-feed contouring",     instrument: "PCB 356A16 tri-axial accel",          spec: "≤ 0.8 mm/s RMS",         ref_doc: "SPC-MTL-220-D-VIB", effect_if_failed: "Hold for ship · customer-reportable",            severity: "critical" },
  { gate_id: "G3-VT-05", phase: "g3-validation-test",    station: "ms-s7", ctq_param: "Cp/Cpk granite flatness over 6 builds",      instrument: "SPC chart from CMM final pass",       spec: "Cpk ≥ 1.33",             ref_doc: "SPC-MTL-220-D-CPK", effect_if_failed: "Process not capable · halt release",             severity: "high"     },

  // Gate 4 — FAI
  { gate_id: "G4-FAI-01", phase: "g4-fai",                station: "ms-s6", ctq_param: "Full dimensional CMM (41 features)",         instrument: "Zeiss Prismo Navigator",              spec: "all features within ±tol", ref_doc: "AS9102 form 3 + INS-MTL-220-D-02", effect_if_failed: "FAI fail · re-cut + re-inspect",        severity: "critical" },
  { gate_id: "G4-FAI-02", phase: "g4-fai",                station: "ms-s7", ctq_param: "Geometric performance test ISO 230-2",      instrument: "Heidenhain LC 415 + ballbar",         spec: "all axes within tol",     ref_doc: "ISO 230-2 § 6 report", effect_if_failed: "FAI fail · realign axis",                            severity: "critical" },
  { gate_id: "G4-FAI-03", phase: "g4-fai",                station: "ms-s7", ctq_param: "Control-system FAT (Heidenhain TNC 640)",   instrument: "TNC 640 FAT log capture",             spec: "0 critical alarms",       ref_doc: "FAT-MTL-220-D",   effect_if_failed: "FAI fail · controller re-config",                  severity: "high"     },
  { gate_id: "G4-FAI-04", phase: "g4-fai",                station: "ms-s7", ctq_param: "Customer witness signature (MAHLE)",        instrument: "Traveler sign-off page",              spec: "rep present · signed",    ref_doc: "TRV-MS-0244",     effect_if_failed: "Re-schedule witness · 2-week slip",                severity: "med"      },

  // Gate 5 — Production Release
  { gate_id: "G5-PR-01", phase: "g5-production-release",  station: "ms-s8", ctq_param: "Control plan release (CP-MTL-220-D)",       instrument: "CP review meeting",                   spec: "all CTQs frozen",         ref_doc: "CP-MTL-220-D",    effect_if_failed: "Production held · open CAPA against CP",          severity: "high"     },
  { gate_id: "G5-PR-02", phase: "g5-production-release",  station: "ms-s8", ctq_param: "CE Declaration of Conformity",              instrument: "Document review",                     spec: "issued + signed",         ref_doc: "CE-DOC-MTL-220-D", effect_if_failed: "Cannot ship to EU customers",                     severity: "critical" },
  { gate_id: "G5-PR-03", phase: "g5-production-release",  station: "ms-s8", ctq_param: "Serial-run authorisation memo",             instrument: "Document review",                     spec: "signed by R. Vogt",       ref_doc: "MEMO-SR-MTL-220-D", effect_if_failed: "Series production blocked",                       severity: "med"      },
];

function _MSQualityGatesPhaseStrip({ phaseSummary, phaseFilter, setPhaseFilter }) {
  return (
    <div style={{
      display: "grid", gridTemplateColumns: "repeat(5, 1fr)",
      background: _MS_COL.bg2,
      borderBottom: "1px solid " + _MS_COL.line,
    }}>
      {phaseSummary.map((p, i) => {
        const isActive = phaseFilter === "all" || phaseFilter === p.phase_id;
        const stateTone = p.state === "passed" ? "ok" : p.state === "in-progress" ? "warn" : "mute";
        return (
          <div
            key={p.phase_id}
            role="button"
            tabIndex={0}
            onClick={() => setPhaseFilter(prev => prev === p.phase_id ? "all" : p.phase_id)}
            onKeyDown={(e) => { if (e.key === "Enter" || e.key === " ") { e.preventDefault(); setPhaseFilter(prev => prev === p.phase_id ? "all" : p.phase_id); } }}
            style={{
              padding: "10px 14px",
              borderRight: i < 4 ? "1px solid " + _MS_COL.line : 0,
              cursor: "pointer",
              background: phaseFilter === p.phase_id ? "color-mix(in oklch, " + _MS_COL.accent + " 8%, transparent)" : "transparent",
              opacity: isActive ? 1 : 0.55,
            }}
          >
            <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: 4 }}>
              <span style={{ fontFamily: "var(--font-mono)", fontSize: 12, letterSpacing: "0.04em", color: _MS_COL.ink4 }}>
                GATE {p.seq}
              </span>
              {_ms_pill(stateTone, p.state)}
            </div>
            <div style={{ fontSize: 12.5, color: _MS_COL.ink, fontWeight: 500 }}>{p.name}</div>
            <div style={{ fontSize: 12, color: _MS_COL.ink3, marginTop: 4 }}>
              {p.count} CTQ{p.count === 1 ? "" : "s"}
              {p.critical > 0 && (
                <span style={{ color: _MS_COL.bad, marginLeft: 6, fontFamily: "var(--font-mono)" }}>
                  {p.critical} critical
                </span>
              )}
            </div>
            <div style={{ fontSize: 12, color: _MS_COL.ink4, marginTop: 3, fontFamily: "var(--font-mono)", letterSpacing: "0.04em" }}>
              chair {p.chair} · {p.target_date}
            </div>
          </div>
        );
      })}
    </div>
  );
}

function ScreenMittelstandQualityGates() {
  const T = useMsTenant() || {};
  const stations = T.routing && T.routing.length ? T.routing : [
    { id: "ms-s1", name: "Receiving" },
    { id: "ms-s2", name: "CMM Inspect" },
    { id: "ms-s3", name: "Granite Re-grind" },
    { id: "ms-s4", name: "Subassy" },
    { id: "ms-s5", name: "Spindle Align" },
    { id: "ms-s6", name: "CMM Final" },
    { id: "ms-s7", name: "FAI Test" },
    { id: "ms-s8", name: "Pack" },
  ];

  // Tenant gates from fixtures (when wired by agent #1) override base
  const sourceCtqs = (T.quality_gates && T.quality_gates.length) ? T.quality_gates : MS_GATE_CTQS_BASE;

  const [gates, setGates] = uSMA4(sourceCtqs.slice());
  const [phaseFilter, setPhaseFilter] = uSMA4("all");
  const [stationFilter, setStationFilter] = uSMA4("all");
  const [instrumentFilter, setInstrumentFilter] = uSMA4("all");
  const [onlyHighSev, setOnlyHighSev] = uSMA4(false);
  const [search, setSearch] = uSMA4("");
  const [selected, setSelected] = uSMA4({});
  const [edits, setEdits] = uSMA4({});
  const [adding, setAdding] = uSMA4(false);
  const [draft, setDraft] = uSMA4({
    gate_id: "", phase: "g3-validation-test", station: "ms-s3", ctq_param: "", instrument: "",
    spec: "", ref_doc: "", effect_if_failed: "", severity: "med",
  });
  const [bulkOpen, setBulkOpen] = uSMA4(false);
  const [bulkAction, setBulkAction] = uSMA4("tighten");
  const [savedToast, setSavedToast] = uSMA4(null);
  const [collapsed, setCollapsed] = uSMA4({});
  const _toastTimerRef = uRMA4(null);

  // unique instruments (first word as a chip)
  const instrSet = uMMA4(() => {
    const s = new Set();
    sourceCtqs.forEach(g => s.add((g.instrument || "").split(" ")[0]));
    return Array.from(s).filter(Boolean);
  }, [sourceCtqs]);

  uEMA4(() => {
    const onTenant = () => {
      const T2 = (typeof getActiveTenant === "function" ? getActiveTenant() : null) || {};
      const fresh = (T2.quality_gates && T2.quality_gates.length) ? T2.quality_gates : MS_GATE_CTQS_BASE;
      setGates(fresh.slice());
      setEdits({}); setSelected({}); setAdding(false); setBulkOpen(false); setSavedToast(null);
      setSearch(""); setPhaseFilter("all"); setStationFilter("all"); setInstrumentFilter("all"); setOnlyHighSev(false);
      if (_toastTimerRef.current) { clearTimeout(_toastTimerRef.current); _toastTimerRef.current = null; }
    };
    window.addEventListener("forge:tenant-change", onTenant);
    return () => {
      window.removeEventListener("forge:tenant-change", onTenant);
      if (_toastTimerRef.current) clearTimeout(_toastTimerRef.current);
    };
  }, []);

  const visible = uMMA4(() => {
    return gates.filter(g => {
      if (phaseFilter !== "all" && g.phase !== phaseFilter) return false;
      if (stationFilter !== "all" && g.station !== stationFilter) return false;
      if (onlyHighSev && _ms_severityRank(g.severity) < 3) return false;
      if (instrumentFilter !== "all" && !((g.instrument || "").toLowerCase().includes(instrumentFilter.toLowerCase()))) return false;
      if (search.trim()) {
        const q = search.toLowerCase();
        if (!(
          (g.ctq_param || "").toLowerCase().includes(q) ||
          (g.gate_id || "").toLowerCase().includes(q) ||
          (g.ref_doc || "").toLowerCase().includes(q)
        )) return false;
      }
      return true;
    });
  }, [gates, phaseFilter, stationFilter, onlyHighSev, instrumentFilter, search]);

  const grouped = uMMA4(() => {
    const m = {};
    visible.forEach(g => { (m[g.phase] = m[g.phase] || []).push(g); });
    return m;
  }, [visible]);

  function patchGate(id, patch) {
    setEdits(prev => ({ ...prev, [id]: { ...(prev[id] || {}), ...patch } }));
  }

  function commit() {
    const editCount = Object.keys(edits).length;
    setGates(prev => prev.map(g => edits[g.gate_id] ? { ...g, ...edits[g.gate_id] } : g));
    setEdits({});
    setSavedToast("Saved " + editCount + " gate edit" + (editCount === 1 ? "" : "s"));
    if (_toastTimerRef.current) clearTimeout(_toastTimerRef.current);
    _toastTimerRef.current = setTimeout(() => setSavedToast(null), 2400);
  }

  function bulkApply() {
    const ids = Object.keys(selected).filter(k => selected[k]);
    setGates(prev => prev.map(g => {
      if (!selected[g.gate_id]) return g;
      if (bulkAction === "tighten") {
        // Crude tighten heuristic — turn ±5 µm into ±3 µm style edit, otherwise append note
        const next = String(g.spec || "").replace(/(±|±)?\s*5\s*µm/g, (m) => "±3 µm");
        return { ...g, spec: next === g.spec ? (g.spec + " · ±tightened 20%") : next };
      }
      if (bulkAction === "critical")  return { ...g, severity: "critical" };
      if (bulkAction === "instr-cal") return { ...g, instrument: g.instrument + " · re-cal due" };
      return g;
    }));
    setSelected({});
    setBulkOpen(false);
    setSavedToast("Applied to " + ids.length + " gate" + (ids.length === 1 ? "" : "s"));
    if (_toastTimerRef.current) clearTimeout(_toastTimerRef.current);
    _toastTimerRef.current = setTimeout(() => setSavedToast(null), 2400);
  }

  function addGate() {
    if (!draft.gate_id || !draft.ctq_param) return;
    setGates(prev => [...prev, { ...draft }]);
    setAdding(false);
    setDraft({
      gate_id: "", phase: "g3-validation-test", station: "ms-s3", ctq_param: "", instrument: "",
      spec: "", ref_doc: "", effect_if_failed: "", severity: "med",
    });
    setSavedToast("Added gate " + draft.gate_id);
    if (_toastTimerRef.current) clearTimeout(_toastTimerRef.current);
    _toastTimerRef.current = setTimeout(() => setSavedToast(null), 2400);
  }

  const valOf = (g, k) => (edits[g.gate_id] && (k in edits[g.gate_id])) ? edits[g.gate_id][k] : g[k];

  // 8-column grid: checkbox, gate id, ctq, instrument, spec, ref_doc, effect, severity
  const colTpl = "26px 90px 1.4fr 1.1fr 1fr 1fr 1.4fr 80px";

  const selCount   = Object.keys(selected).filter(k => selected[k]).length;
  const dirtyCount = Object.keys(edits).length;

  // Phase summary chips at the top
  const phaseSummary = uMMA4(() => {
    return MS_GATE_PHASES.map(p => ({
      ...p,
      count:    gates.filter(g => g.phase === p.phase_id).length,
      critical: gates.filter(g => g.phase === p.phase_id && g.severity === "critical").length,
    }));
  }, [gates]);

  return (
    <div style={{ display: "flex", flexDirection: "column", height: "100%", minHeight: 0, background: _MS_COL.bg }}>

      <_MSToolbar
        right={
          <>
            {_ms_btn({ icon: "Diff", onClick: () => setBulkOpen(true), title: "Apply edit to all selected", children: "Bulk apply (" + selCount + ")" })}
            {_ms_btn({ icon: "Plus", onClick: () => setAdding(a => !a), children: adding ? "Close add" : "Add new gate" })}
            {_ms_btn({ variant: "primary", icon: "Check", onClick: commit, title: "Commit pending edits", children: "Save edits (" + dirtyCount + ")" })}
          </>
        }
      >
        <_MSQualityGatesFilters search={search} setSearch={setSearch} phaseFilter={phaseFilter} setPhaseFilter={setPhaseFilter} stationFilter={stationFilter} setStationFilter={setStationFilter} instrumentFilter={instrumentFilter} setInstrumentFilter={setInstrumentFilter} instrSet={instrSet} onlyHighSev={onlyHighSev} setOnlyHighSev={setOnlyHighSev} visible={visible} gates={gates} stations={stations} />
      </_MSToolbar>

      <_MSQualityGatesPhaseStrip phaseSummary={phaseSummary} phaseFilter={phaseFilter} setPhaseFilter={setPhaseFilter} />

      <div style={{ flex: 1, display: "grid", gridTemplateColumns: adding ? "1fr 340px" : "1fr", minHeight: 0 }}>

        {/* Main grid */}
        <div style={{ overflow: "auto", display: "flex", flexDirection: "column", minHeight: 0 }}>

          <div style={_msA4GateGridHeaderStyle(colTpl)}>
            <div style={{ paddingLeft: 8 }}>
              <input id="ms-act4-f8" name="ms-act4-f8"
                type="checkbox"
                checked={visible.length > 0 && visible.every(g => selected[g.gate_id])}
                onChange={e => {
                  const sel = { ...selected };
                  visible.forEach(g => { if (e.target.checked) sel[g.gate_id] = true; else delete sel[g.gate_id]; });
                  setSelected(sel);
                }}
              />
            </div>
            <div>Gate ID</div>
            <div>CTQ parameter</div>
            <div>Instrument</div>
            <div>Spec</div>
            <div>Ref doc</div>
            <div>Effect if failed</div>
            <div>Sev</div>
          </div>

          <_MSQualityGatesTable grouped={grouped} collapsed={collapsed} setCollapsed={setCollapsed} colTpl={colTpl} edits={edits} selected={selected} setSelected={setSelected} valOf={valOf} patchGate={patchGate} />

          {visible.length === 0 && (
            <div style={{ padding: 32, textAlign: "center", color: _MS_COL.ink4, fontSize: 12 }}>
              No CTQs match the current filters.
            </div>
          )}
        </div>

        {adding && <_MSQualityGatesAddPanel draft={draft} setDraft={setDraft} setAdding={setAdding} addGate={addGate} stations={stations} />}
      </div>

      {bulkOpen && (
        <_MSModal
          title="Bulk apply"
          body={
            <div style={{ display: "flex", flexDirection: "column", gap: 8 }}>
              <span>Apply action to <b>{selCount}</b> selected CTQ{selCount === 1 ? "" : "s"}.</span>
              <select id="ms-act4-f9" name="ms-act4-f9"
                value={bulkAction}
                onChange={e => setBulkAction(e.target.value)}
                style={_ms_inputBox()}
              >
                <option value="tighten">Tighten spec by 20% (e.g. ±5 µm → ±3 µm)</option>
                <option value="critical">Mark severity = critical</option>
                <option value="instr-cal">Flag instrument re-calibration</option>
              </select>
            </div>
          }
          onCancel={() => setBulkOpen(false)}
          onConfirm={bulkApply}
          confirmLabel="Apply"
        />
      )}

      {savedToast && (
        <div style={_MS_A4_TOAST_STYLE}>
          {savedToast}
        </div>
      )}
    </div>
  );
}

function _MSQualityGatesTable({ grouped, collapsed, setCollapsed, colTpl, edits, selected, setSelected, valOf, patchGate }) {
  return MS_GATE_PHASES.reduce((acc, p) => { if (grouped[p.phase_id] && grouped[p.phase_id].length) acc.push(p); return acc; }, []).map(p => {
    const isCollapsed = collapsed[p.phase_id];
    return (
      <div key={p.phase_id}>
        <div
          role="button"
          tabIndex={0}
          onClick={() => setCollapsed(prev => ({ ...prev, [p.phase_id]: !prev[p.phase_id] }))}
          onKeyDown={(e) => { if (e.key === "Enter" || e.key === " ") { e.preventDefault(); setCollapsed(prev => ({ ...prev, [p.phase_id]: !prev[p.phase_id] })); } }}
          style={_MS_A4_PHASE_HEADER_STYLE}
        >
          <span style={{ color: _MS_COL.ink4, width: 12 }}>{isCollapsed ? "▸" : "▾"}</span>
          <span style={{ color: _MS_COL.ink4 }}>GATE {p.seq}</span>
          <span style={{ color: _MS_COL.ink, fontWeight: 600 }}>{p.name}</span>
          <span style={{ color: _MS_COL.ink4 }}>·</span>
          <span style={{ color: _MS_COL.ink3 }}>{grouped[p.phase_id].length} CTQs</span>
          <span style={{ color: _MS_COL.ink4 }}>·</span>
          <span style={{ color: _MS_COL.ink3 }}>chair {p.chair}</span>
          <span style={{ color: _MS_COL.ink4 }}>·</span>
          <span style={{ color: _MS_COL.ink3 }}>{p.target_date}</span>
          <span style={{ marginLeft: "auto" }}>
            {_ms_pill(p.state === "passed" ? "ok" : p.state === "in-progress" ? "warn" : "mute", p.state)}
          </span>
        </div>

        {!isCollapsed && grouped[p.phase_id].map(g => (
          <div key={g.gate_id} style={{
            display: "grid", gridTemplateColumns: colTpl,
            alignItems: "center",
            borderBottom: "1px solid " + _MS_COL.lineSoft,
            fontSize: 12,
            background: edits[g.gate_id] ? "color-mix(in oklch, " + _MS_COL.warn + " 7%, transparent)" : "transparent",
            height: 32,
          }}>
            <div style={{ paddingLeft: 8 }}>
              <input id="ms-act4-f10" name="ms-act4-f10"
                type="checkbox"
                checked={!!selected[g.gate_id]}
                onChange={e => setSelected(prev => ({ ...prev, [g.gate_id]: e.target.checked }))}
              />
            </div>
            <div style={{ fontFamily: "var(--font-mono)", color: _MS_COL.ink3, fontSize: 12 }}>{g.gate_id}</div>
            <input id="ms-act4-f11" name="ms-act4-f11"
              value={valOf(g, "ctq_param") || ""}
              onChange={e => patchGate(g.gate_id, { ctq_param: e.target.value })}
              style={_ms_inputCell()}
            />
            <input id="ms-act4-f12" name="ms-act4-f12"
              value={valOf(g, "instrument") || ""}
              onChange={e => patchGate(g.gate_id, { instrument: e.target.value })}
              style={_ms_inputCell()}
            />
            <input id="ms-act4-f13" name="ms-act4-f13"
              value={valOf(g, "spec") || ""}
              onChange={e => patchGate(g.gate_id, { spec: e.target.value })}
              style={_ms_inputCell("var(--font-mono)")}
            />
            <input id="ms-act4-f14" name="ms-act4-f14"
              value={valOf(g, "ref_doc") || ""}
              onChange={e => patchGate(g.gate_id, { ref_doc: e.target.value })}
              style={_ms_inputCell("var(--font-mono)")}
            />
            <input id="ms-act4-f15" name="ms-act4-f15"
              value={valOf(g, "effect_if_failed") || ""}
              onChange={e => patchGate(g.gate_id, { effect_if_failed: e.target.value })}
              style={_ms_inputCell()}
            />
            <div>
              <select id="ms-act4-f16" name="ms-act4-f16"
                value={valOf(g, "severity") || "med"}
                onChange={e => patchGate(g.gate_id, { severity: e.target.value })}
                style={{
                  background: "transparent",
                  border: "1px solid transparent",
                  color: _MS_COL.ink2,
                  fontSize: 12,
                  padding: "2px 4px",
                  fontFamily: "var(--font-mono)",
                }}
              >
                <option value="low">low</option>
                <option value="med">med</option>
                <option value="high">high</option>
                <option value="critical">critical</option>
              </select>
            </div>
          </div>
        ))}

        {!isCollapsed && (
          <div style={{
            padding: "8px 14px 12px 38px",
            background: _MS_COL.bg,
            borderBottom: "1px solid " + _MS_COL.lineSoft,
          }}>
            <div style={{ fontSize: 12, color: _MS_COL.ink3, marginBottom: 4 }}>{p.desc}</div>
            <div style={{ display: "flex", flexWrap: "wrap", gap: 6, alignItems: "center" }}>
              <span style={{ fontFamily: "var(--font-mono)", fontSize: 12, color: _MS_COL.ink4, letterSpacing: "0.06em", textTransform: "uppercase" }}>standards</span>
              {p.standards.map(s => (
                <span key={s} style={{
                  fontFamily: "var(--font-mono)", fontSize: 12,
                  padding: "2px 6px", border: "1px solid " + _MS_COL.line,
                  color: _MS_COL.ink3, borderRadius: 2, background: _MS_COL.bg3,
                }}>{s}</span>
              ))}
            </div>
            <div style={{ display: "flex", flexWrap: "wrap", gap: 6, alignItems: "center", marginTop: 4 }}>
              <span style={{ fontFamily: "var(--font-mono)", fontSize: 12, color: _MS_COL.ink4, letterSpacing: "0.06em", textTransform: "uppercase" }}>artifacts</span>
              {p.artifacts.map(a => (
                <span key={a} style={{
                  fontFamily: "var(--font-mono)", fontSize: 12,
                  padding: "2px 6px", border: "1px dashed " + _MS_COL.line,
                  color: _MS_COL.ink3, borderRadius: 2,
                }}>{a}</span>
              ))}
            </div>
          </div>
        )}
      </div>
    );
  });
}

function _MSQualityGatesFilters({ search, setSearch, phaseFilter, setPhaseFilter, stationFilter, setStationFilter, instrumentFilter, setInstrumentFilter, instrSet, onlyHighSev, setOnlyHighSev, visible, gates, stations }) {
  return (
    <>
      <div style={_MS_A4_FIND_BAR_STYLE}>
        <span style={{ fontFamily: "var(--font-mono)", fontSize: 12, color: _MS_COL.ink4, letterSpacing: "0.04em" }}>FIND</span>
        <input id="ms-act4-f17" name="ms-act4-f17" aria-label="Search gates / CTQs / ref docs"
          placeholder="Search gates / CTQs / ref docs"
          value={search}
          onChange={e => setSearch(e.target.value)}
          style={{ flex: 1, background: "transparent", border: 0, outline: "0 solid transparent", color: _MS_COL.ink, font: "inherit", fontSize: 12 }}
        />
      </div>
      <select id="ms-act4-f18" name="ms-act4-f18"
        value={phaseFilter}
        onChange={e => setPhaseFilter(e.target.value)}
        style={{ padding: "4px 6px", border: "1px solid " + _MS_COL.line, background: _MS_COL.bg, color: _MS_COL.ink, borderRadius: 2, fontSize: 12 }}
      >
        <option value="all">All phases</option>
        {MS_GATE_PHASES.map(p => <option key={p.phase_id} value={p.phase_id}>{p.seq}. {p.name}</option>)}
      </select>
      <select id="ms-act4-f19" name="ms-act4-f19"
        value={stationFilter}
        onChange={e => setStationFilter(e.target.value)}
        style={{ padding: "4px 6px", border: "1px solid " + _MS_COL.line, background: _MS_COL.bg, color: _MS_COL.ink, borderRadius: 2, fontSize: 12 }}
      >
        <option value="all">All stations</option>
        {stations.map(s => <option key={s.id} value={s.id}>{s.id} · {s.name}</option>)}
      </select>
      <select id="ms-act4-f20" name="ms-act4-f20"
        value={instrumentFilter}
        onChange={e => setInstrumentFilter(e.target.value)}
        style={{ padding: "4px 6px", border: "1px solid " + _MS_COL.line, background: _MS_COL.bg, color: _MS_COL.ink, borderRadius: 2, fontSize: 12 }}
      >
        <option value="all">Any instrument</option>
        {instrSet.map(s => <option key={s} value={s}>{s}</option>)}
      </select>
      <label style={{ display: "inline-flex", alignItems: "center", gap: 6, fontSize: 12, color: _MS_COL.ink3 }}>
        <input id="ms-act4-f21" name="ms-act4-f21" type="checkbox" checked={onlyHighSev} onChange={e => setOnlyHighSev(e.target.checked)} />
        severity ≥ 3
      </label>
      <span style={{ fontSize: 12, color: _MS_COL.ink4, marginLeft: 6 }}>
        showing <b style={{ color: _MS_COL.ink2, fontFamily: "var(--font-mono)" }}>{visible.length}</b> / {gates.length} CTQs
      </span>
    </>
  );
}

function _MSQualityGatesAddPanel({ draft, setDraft, setAdding, addGate, stations }) {
  return (
    <div style={{
      borderLeft: "1px solid " + _MS_COL.line,
      background: _MS_COL.bg2,
      padding: 14, overflow: "auto",
    }}>
      {_ms_label("NEW QUALITY GATE")}
      <div style={{ marginTop: 6, marginBottom: 12 }}>
        <div style={{ marginBottom: 8 }}>
          {_ms_label("Gate ID", _MS_COL.ink4)}
          <input id="ms-act4-f22" name="ms-act4-f22"
            value={draft.gate_id}
            onChange={e => setDraft(prev => ({ ...prev, gate_id: e.target.value }))}
            placeholder="G3-VT-06"
            style={{ ..._ms_inputBox("var(--font-mono)"), marginTop: 4 }}
          />
        </div>
        <div style={{ marginBottom: 8 }}>
          {_ms_label("Phase", _MS_COL.ink4)}
          <select id="ms-act4-f23" name="ms-act4-f23"
            value={draft.phase}
            onChange={e => setDraft(prev => ({ ...prev, phase: e.target.value }))}
            style={{ ..._ms_inputBox(), marginTop: 4 }}
          >
            {MS_GATE_PHASES.map(p => <option key={p.phase_id} value={p.phase_id}>{p.seq}. {p.name}</option>)}
          </select>
        </div>
        <div style={{ marginBottom: 8 }}>
          {_ms_label("Station", _MS_COL.ink4)}
          <select id="ms-act4-f24" name="ms-act4-f24"
            value={draft.station}
            onChange={e => setDraft(prev => ({ ...prev, station: e.target.value }))}
            style={{ ..._ms_inputBox(), marginTop: 4 }}
          >
            {stations.map(s => <option key={s.id} value={s.id}>{s.id} · {s.name}</option>)}
          </select>
        </div>
        {[
          { k: "ctq_param",        lbl: "CTQ parameter" },
          { k: "instrument",       lbl: "Instrument" },
          { k: "spec",             lbl: "Spec",      mono: true },
          { k: "ref_doc",          lbl: "Ref doc",   mono: true },
          { k: "effect_if_failed", lbl: "Effect if failed" },
        ].map(f => (
          <div key={f.k} style={{ marginBottom: 8 }}>
            {_ms_label(f.lbl, _MS_COL.ink4)}
            <input id="ms-act4-f25" name="ms-act4-f25"
              value={draft[f.k] || ""}
              onChange={e => setDraft(prev => ({ ...prev, [f.k]: e.target.value }))}
              style={{ ..._ms_inputBox(f.mono ? "var(--font-mono)" : ""), marginTop: 4 }}
            />
          </div>
        ))}
        <div style={{ marginBottom: 8 }}>
          {_ms_label("Severity", _MS_COL.ink4)}
          <select id="ms-act4-f26" name="ms-act4-f26"
            value={draft.severity}
            onChange={e => setDraft(prev => ({ ...prev, severity: e.target.value }))}
            style={{ ..._ms_inputBox(), marginTop: 4 }}
          >
            <option value="low">low</option>
            <option value="med">med</option>
            <option value="high">high</option>
            <option value="critical">critical</option>
          </select>
        </div>
        <div style={{ display: "flex", justifyContent: "flex-end", gap: 6, marginTop: 12 }}>
          {_ms_btn({ onClick: () => setAdding(false), children: "Cancel" })}
          {_ms_btn({ variant: "primary", onClick: addGate, children: "Add CTQ" })}
        </div>
      </div>
      <div style={{ fontSize: 12, color: _MS_COL.ink4, lineHeight: 1.6, borderTop: "1px solid " + _MS_COL.lineSoft, paddingTop: 10 }}>
        {_ms_label("NOTES")}
        <ul style={{ margin: "4px 0 0 0", padding: "0 0 0 14px" }}>
          <li>New CTQs are created in <i>draft</i>.</li>
          <li>They become enforceable only after the next CP-MTL-220-D release.</li>
          <li>µm specs require Cp/Cpk re-baseline at validation gate.</li>
        </ul>
      </div>
    </div>
  );
}

/* ════════════════════════════════════════════════════════════════════
   §3 — S-MS-23 · Line readiness  /line/readiness
   Granite cell shortage (lap stones), spindle ETA from GMN (180d),
   control cabinet ETA from Heidenhain (45d).
   Risk panel: "no real dual-source for GMN" — calculated risk per spec §16.
   ──────────────────────────────────────────────────────────────────── */

function ScreenMittelstandLineReadiness() {
  const T = useMsTenant() || {};

  const [showSpindleRisk, setShowSpindleRisk] = uSMA4(false);
  const [showStoneReorder, setShowStoneReorder] = uSMA4(false);
  const [stoneEtaDays, setStoneEtaDays] = uSMA4(9);
  const [savedToast, setSavedToast] = uSMA4(null);
  const _toastTimerRef = uRMA4(null);

  uEMA4(() => {
    const onTenant = () => {
      setShowSpindleRisk(false);
      setShowStoneReorder(false);
      setSavedToast(null);
      if (_toastTimerRef.current) { clearTimeout(_toastTimerRef.current); _toastTimerRef.current = null; }
    };
    window.addEventListener("forge:tenant-change", onTenant);
    return () => {
      window.removeEventListener("forge:tenant-change", onTenant);
      if (_toastTimerRef.current) clearTimeout(_toastTimerRef.current);
    };
  }, []);

  function flashToast(msg) {
    setSavedToast(msg);
    if (_toastTimerRef.current) clearTimeout(_toastTimerRef.current);
    _toastTimerRef.current = setTimeout(() => setSavedToast(null), 2400);
  }

  // Long-lead PO state — anchor of the readiness story for the MTL-220
  const longLeads = [
    {
      tag: "PO-MTL-LL-001",
      part_num: "50.01",
      part_name: "Main spindle · HSK-A63 · 24 k rpm",
      supplier: "GMN Paul Müller Industrie",
      released: "2026-01-08",
      eta: "2026-07-07",
      lead_days: 180,
      pct: 0.62,
      status: "in-build",
      risk: "high",
      note: "GMN sole-source. No qualified alternate. See risk panel.",
    },
    {
      tag: "PO-MTL-LL-002",
      part_num: "70.00",
      part_name: "Control cabinet · Heidenhain TNC 640",
      supplier: "Heidenhain DR. JOHANNES HEIDENHAIN GmbH",
      released: "2026-01-12",
      eta: "2026-02-26",
      lead_days: 45,
      pct: 1.00,
      status: "received",
      risk: "low",
      note: "Cabinet received 2026-02-26 · LC 415 encoder pack included.",
    },
    {
      tag: "PO-MTL-LL-003",
      part_num: "50.00",
      part_name: "A/C tilting head (spindle module)",
      supplier: "Kessler Maschinenbau",
      released: "2026-01-08",
      eta: "2026-04-08",
      lead_days: 90,
      pct: 0.78,
      status: "in-build",
      risk: "med",
      note: "Kessler · second source Weiss Spindeltechnologie qualified for this spec.",
    },
    {
      tag: "PO-MTL-LL-004",
      part_num: "60.00",
      part_name: "ATC carousel (24-pocket)",
      supplier: "DMG Mori Spare Parts",
      released: "2026-02-04",
      eta: "2026-03-31",
      lead_days: 55,
      pct: 1.00,
      status: "received",
      risk: "low",
      note: "Received 2026-03-31 · 0 NCR.",
    },
  ];

  // Granite cell consumables — the actual blocking item
  const graniteCell = [
    {
      sku: "LST-600-G",
      name: "Lap stones · grade 600 · cast-iron carrier",
      vendor: "Lapmaster Wolters EU",
      need: 24, on_hand: 6, reorder: 18,
      lead_days: stoneEtaDays,
      blocks: "Granite re-grind (s3) · ECO-MS-0017 two-pass lap",
      severity: "critical",
    },
    {
      sku: "DIA-D126",
      name: "Diamond wheel D-126 · binder MD8",
      vendor: "Asahi Diamond Europe",
      need: 4, on_hand: 4, reorder: 0,
      lead_days: 0,
      blocks: null,
      severity: "ok",
    },
    {
      sku: "COOL-WGL",
      name: "Water-glycol cutting fluid · 200 L",
      vendor: "Blaser Swisslube",
      need: 2, on_hand: 5, reorder: 0,
      lead_days: 0,
      blocks: null,
      severity: "ok",
    },
    {
      sku: "MAG-CHK-300",
      name: "Magnetic chuck 300 mm · re-magnetized",
      vendor: "Schunk Magnos",
      need: 1, on_hand: 1, reorder: 0,
      lead_days: 0,
      blocks: null,
      severity: "ok",
    },
  ];

  // Tooling readiness across all 8 stations
  const tooling = [
    { id: "MTL-WE-02", name: "Mahr C1216 dial gauge",                  station: "ms-s1", status: "ready",   calib: "2026-04-22" },
    { id: "CMM-Z1-A",  name: "Zeiss UPMC Carat",                       station: "ms-s2", status: "ready",   calib: "2026-04-15" },
    { id: "GR-04-LAP", name: "Lapmaster 36-DR rotary lap",              station: "ms-s3", status: "ready",   calib: "2026-04-19" },
    { id: "GR-04-RGD", name: "Re-grind diamond wheel D-126",            station: "ms-s3", status: "in-prep", calib: "fitted 2026-03-01 · re-dressing" },
    { id: "GR-04-LST", name: "Lap stones (grade 600)",                  station: "ms-s3", status: "short",   calib: "consumable · eta " + stoneEtaDays + " d" },
    { id: "AS-12-FXT", name: "Bridge-mill subassy fixture",             station: "ms-s4", status: "ready",   calib: "2026-04-09" },
    { id: "AL-03-FRO", name: "FARO Vantage Max laser tracker",          station: "ms-s5", status: "ready",   calib: "2026-04-04" },
    { id: "AL-03-CRY", name: "Renishaw QC20-W ballbar",                 station: "ms-s5", status: "ready",   calib: "2026-04-02" },
    { id: "CMM-Z2-A",  name: "Zeiss Prismo Navigator",                  station: "ms-s6", status: "ready",   calib: "2026-04-18" },
    { id: "PRB-Z2-01", name: "Renishaw RDS rotary probe",               station: "ms-s6", status: "warn",    calib: "due 2026-05-03" },
    { id: "TS-01-VIB", name: "PCB 356A16 tri-axial accel",              station: "ms-s7", status: "ready",   calib: "2026-03-30" },
    { id: "TS-01-LCK", name: "Heidenhain LC 415 reference",             station: "ms-s7", status: "ready",   calib: "2026-03-12" },
    { id: "SH-01-CRT", name: "Sea-worthy crate ISPM-15",                station: "ms-s8", status: "ready",   calib: "stamp current" },
  ];

  const operators = [
    { name: "K. Müller",   role: "Receiving + Granite-blank QC (s1)",      shift: "A", skills: { recv: 1, cmm: 0.6, granite: 0.3, subassy: 0.4, align: 0.2, fai: 0.3 } },
    { name: "S. Klein",    role: "CMM Inspect + CMM Final (s2, s6)",       shift: "A", skills: { recv: 0.6, cmm: 1, granite: 0.4, subassy: 0.3, align: 0.5, fai: 0.7 } },
    { name: "D. Becker",   role: "Granite Re-grind cell lead (s3)",        shift: "A", skills: { recv: 0.4, cmm: 0.5, granite: 1, subassy: 0.6, align: 0.4, fai: 0.5 } },
    { name: "T. Hoffmann", role: "Subassembly + bridge build (s4)",        shift: "A", skills: { recv: 0.4, cmm: 0.4, granite: 0.5, subassy: 1, align: 0.6, fai: 0.5 } },
    { name: "F. Weber",    role: "Spindle alignment + tracker (s5)",       shift: "A", skills: { recv: 0.3, cmm: 0.6, granite: 0.3, subassy: 0.5, align: 1, fai: 0.7 } },
    { name: "R. Vogt",     role: "FAI test + customer witness (s7)",       shift: "B", skills: { recv: 0.3, cmm: 0.7, granite: 0.4, subassy: 0.5, align: 0.7, fai: 1 } },
    { name: "L. Schmidt",  role: "Pack & ship (s8)",                       shift: "A", skills: { recv: 0.6, cmm: 0.3, granite: 0.2, subassy: 0.3, align: 0.2, fai: 0.4 } },
  ];

  const ncrs = [
    {
      id:       "NCR-MTL-2026-0007",
      title:    "Granite blank · cross-beam · flatness 5.4 µm at incoming",
      supplier: "Diabas Stein KG (Sebnitz)",
      lot:      "GR-LOT-2026-0218",
      age_days: 4,
      severity: "high",
      status:   "open · requested re-survey from foundry · awaiting cert v.2",
      action:   "Hold blank · re-issue COC · re-grind required if accepted",
    },
    {
      id:       "NCR-MTL-2026-0008",
      title:    "Renishaw RDS probe · cal expires in 8 d",
      supplier: "—",
      lot:      "—",
      age_days: 1,
      severity: "med",
      status:   "open · DAkkS appointment booked 2026-04-30",
      action:   "Backup probe head fitted to Z2 in interim",
    },
    {
      id:       "NCR-MTL-2026-0006",
      title:    "Heidenhain LC 415 firmware bulletin pending",
      supplier: "Heidenhain",
      lot:      "—",
      age_days: 11,
      severity: "med",
      status:   "open · bulletin under engineering review (R. Vogt)",
      action:   "No build impact yet · update planned post-FAI",
    },
  ];

  const totalToolsReady = tooling.filter(t => t.status === "ready").length;
  const totalToolsTotal = tooling.length;
  const stoneShortage = graniteCell.find(g => g.sku === "LST-600-G");
  const stoneShort = stoneShortage ? Math.max(0, stoneShortage.need - stoneShortage.on_hand) : 0;
  const cellReadyPct = Math.round(100 * totalToolsReady / totalToolsTotal);

  return (
    <div style={{ display: "flex", flexDirection: "column", height: "100%", minHeight: 0, background: _MS_COL.bg }}>

      <_MSToolbar
        right={
          <>
            {_ms_btn({ icon: "Calendar", children: "Shift roster" })}
            {_ms_btn({ icon: "File",     children: "Export readiness PDF" })}
            {_ms_btn({ variant: "primary", icon: "Check", onClick: () => flashToast("Locked shift roster for 2026-04-30"), children: "Lock line for tomorrow" })}
          </>
        }
      >
        <span style={{ fontSize: 12, color: _MS_COL.ink4 }}>
          Tomorrow ·{" "}
          <b style={{ color: _MS_COL.ink2, fontFamily: "var(--font-mono)" }}>2026-04-30 / Shift A</b>
          &nbsp;·&nbsp;target 1 unit / week · WO-MTL-2401
          &nbsp;·&nbsp;<span style={{ color: _MS_COL.warn }}>granite cell short (lap stones) · spindle in-build · 1 NCR open</span>
        </span>
      </_MSToolbar>

      {/* Top header strip — global verdict + four KPIs */}
      <div style={{
        padding: "14px 16px",
        background: _MS_COL.bg2,
        borderBottom: "1px solid " + _MS_COL.line,
        display: "grid", gridTemplateColumns: "2fr 1fr 1fr 1fr 1fr", gap: 16,
        alignItems: "center",
      }}>
        <div>
          {_ms_label("Line readiness verdict · MTL-220 D")}
          <div style={{ marginTop: 6, fontSize: 13, color: _MS_COL.ink, lineHeight: 1.45 }}>
            <b style={{ color: _MS_COL.warn }}>Conditionally ready</b> for shift A on{" "}
            <span style={{ fontFamily: "var(--font-mono)" }}>2026-04-30</span>.
            Resolve <b style={{ fontFamily: "var(--font-mono)" }}>LST-600-G</b> shortage
            (<span style={{ fontFamily: "var(--font-mono)" }}>{stoneShort} sets short</span>,
            ETA <span style={{ fontFamily: "var(--font-mono)" }}>{stoneEtaDays} d</span>) and
            re-dress diamond wheel before <span style={{ fontFamily: "var(--font-mono)" }}>06:00</span>.
            GMN spindle remains the program's critical path:{" "}
            <span style={{ color: _MS_COL.bad, fontFamily: "var(--font-mono)" }}>180 d</span> with no qualified alternate.
          </div>
        </div>
        <_MSStatPill label="cell ready" value={cellReadyPct + "%"} delta={cellReadyPct >= 85 ? "+2 pt" : "−4 pt"} trend={cellReadyPct >= 85 ? "up" : "down"} mono />
        <_MSStatPill label="open NCR"   value={String(ncrs.length)} delta="+1 wk" trend="up" mono />
        <_MSStatPill label="long-lead PO open" value={String(longLeads.filter(l => l.status === "in-build").length) + " / " + longLeads.length} delta="0 chg" trend="flat" mono />
        <_MSStatPill label="FAI target" value="2026-08-14" delta="0 d slip" trend="flat" mono />
      </div>

      <div style={{ flex: 1, display: "grid", gridTemplateColumns: "1.3fr 1.1fr 1.1fr 1.2fr", minHeight: 0 }}>
        <_MSLineLongLeads longLeads={longLeads} setShowSpindleRisk={setShowSpindleRisk} />
        <_MSLineGraniteCell graniteCell={graniteCell} setShowStoneReorder={setShowStoneReorder} flashToast={flashToast} />
        <_MSLineToolingOps tooling={tooling} operators={operators} totalToolsReady={totalToolsReady} totalToolsTotal={totalToolsTotal} />
        <_MSLineNcrRisk ncrs={ncrs} setShowSpindleRisk={setShowSpindleRisk} flashToast={flashToast} />
      </div>

      {showSpindleRisk && <_MSSpindleRiskModal setShowSpindleRisk={setShowSpindleRisk} flashToast={flashToast} />}
      {showStoneReorder && <_MSStoneReorderModal setShowStoneReorder={setShowStoneReorder} stoneEtaDays={stoneEtaDays} setStoneEtaDays={setStoneEtaDays} flashToast={flashToast} />}

      {savedToast && (
        <div style={_MS_A4_TOAST_STYLE}>
          {savedToast}
        </div>
      )}
    </div>
  );
}

function _MSSpindleRiskModal({ setShowSpindleRisk, flashToast }) {
  return (
    <_MSModal
      title="GMN spindle risk · mitigation"
      danger
      body={
        <div>
          <div style={{ marginBottom: 10, fontSize: 12, color: _MS_COL.ink2 }}>
            Three viable mitigations for the sole-source GMN spindle (50.01).
            Only mitigation 1 reduces program critical path. Choose primary.
          </div>
          {(function() {
            var i18n = (typeof window !== "undefined") ? window.forgeI18n : null;
            function mit$(minor, fallback) {
              if (i18n && typeof i18n.formatMoneyMinor === "function") {
                var out = i18n.formatMoneyMinor(minor, "EUR");
                if (out) return out;
              }
              return fallback;
            }
            return [
              {
                id: "m1",
                label: "Ring-fence safety stock (1 finished spindle)",
                cost: mit$("3200000", "€32 000") + " working capital",
                effect: "Recovers 180 d on first failure · primary recommendation",
              },
              {
                id: "m2",
                label: "Step-Tec benchmark on Kessler frame (12 wk)",
                cost: mit$("1800000", "€18 000") + " NRE",
                effect: "Yields qualified alternate by 2026-Q4",
              },
              {
                id: "m3",
                label: "Accept residual · disclose in PPAP narrative",
                cost: "—",
                effect: "MAHLE supplier-quality team to be informed",
              },
            ];
          })().map(m => (
            <div key={m.id} style={{
              padding: 10, marginBottom: 8,
              border: "1px solid " + _MS_COL.line, borderRadius: 2,
              background: _MS_COL.bg2,
            }}>
              <div style={{ display: "flex", justifyContent: "space-between", alignItems: "baseline" }}>
                <b style={{ fontSize: 12.5, color: _MS_COL.ink }}>{m.label}</b>
                <span style={{ fontFamily: "var(--font-mono)", fontSize: 12, color: _MS_COL.ink3 }}>{m.cost}</span>
              </div>
              <div style={{ fontSize: 12, color: _MS_COL.ink2, marginTop: 4 }}>{m.effect}</div>
            </div>
          ))}
        </div>
      }
      onCancel={() => setShowSpindleRisk(false)}
      onConfirm={() => { setShowSpindleRisk(false); flashToast("Mitigation plan attached to ECO-MS-0017"); }}
      confirmLabel="Attach to ECO-MS-0017"
    />
  );
}

function _MSStoneReorderModal({ setShowStoneReorder, stoneEtaDays, setStoneEtaDays, flashToast }) {
  return (
    <_MSModal
      title="Expedite reorder · LST-600-G"
      body={
        <div>
          <div style={{ marginBottom: 10, fontSize: 12, color: _MS_COL.ink2 }}>
            Lap stone shortage blocks granite re-grind op. Choose ETA.
          </div>
          <div style={{ display: "flex", flexDirection: "column", gap: 8 }}>
            {(function() {
              var i18n = (typeof window !== "undefined") ? window.forgeI18n : null;
              function ms4Money(minor, fallback) {
                if (i18n && typeof i18n.formatMoneyMinor === "function") {
                  var out = i18n.formatMoneyMinor(minor, "EUR");
                  if (out) return out;
                }
                return fallback;
              }
              return [
                { eta: 9,  vendor: "Lapmaster Wolters EU · standard",       price: ms4Money("288000", "€2 880") },
                { eta: 4,  vendor: "Lapmaster Wolters EU · air freight",    price: ms4Money("422000", "€4 220") },
                { eta: 2,  vendor: "Asahi Diamond Europe · sub grade 600",  price: ms4Money("594000", "€5 940") },
              ];
            })().map(opt => (
              <div
                key={opt.eta}
                role="button"
                tabIndex={0}
                onClick={() => setStoneEtaDays(opt.eta)}
                onKeyDown={(e) => { if (e.key === "Enter" || e.key === " ") { e.preventDefault(); setStoneEtaDays(opt.eta); } }}
                style={{
                  padding: 10,
                  border: "1px solid " + (stoneEtaDays === opt.eta ? _MS_COL.accent : _MS_COL.line),
                  background: stoneEtaDays === opt.eta ? "color-mix(in oklch, " + _MS_COL.accent + " 8%, transparent)" : _MS_COL.bg2,
                  borderRadius: 2,
                  cursor: "pointer",
                }}
              >
                <div style={{ display: "flex", justifyContent: "space-between" }}>
                  <b style={{ fontSize: 12, color: _MS_COL.ink }}>{opt.vendor}</b>
                  <span style={{ fontFamily: "var(--font-mono)", fontSize: 12, color: _MS_COL.ink2 }}>{opt.price}</span>
                </div>
                <div style={{ fontSize: 12, color: _MS_COL.ink3, marginTop: 4, fontFamily: "var(--font-mono)" }}>
                  ETA {opt.eta} d
                </div>
              </div>
            ))}
          </div>
        </div>
      }
      onCancel={() => setShowStoneReorder(false)}
      onConfirm={() => { setShowStoneReorder(false); flashToast("Reorder placed · ETA " + stoneEtaDays + " d"); }}
      confirmLabel={"Place order (ETA " + stoneEtaDays + " d)"}
    />
  );
}

function _MSLineLongLeads({ longLeads, setShowSpindleRisk }) {
  return (
    <div style={{ borderRight: "1px solid " + _MS_COL.line, display: "flex", flexDirection: "column", minHeight: 0 }}>
      <div style={{
        padding: "8px 14px", borderBottom: "1px solid " + _MS_COL.line,
        background: _MS_COL.bg2,
        display: "flex", justifyContent: "space-between", alignItems: "center",
      }}>
        {_ms_label("LONG-LEAD PO · 4 OPEN")}
        <span style={{ color: _MS_COL.warn, fontSize: 12, fontFamily: "var(--font-mono)" }}>
          2 in-build · 2 received
        </span>
      </div>
      <div style={{ flex: 1, overflow: "auto" }}>
        {longLeads.map(po => (
          <div key={po.tag} style={{
            padding: 14, borderBottom: "1px solid " + _MS_COL.lineSoft,
          }}>
            <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between" }}>
              <span style={{ fontFamily: "var(--font-mono)", fontSize: 12, color: _MS_COL.ink3 }}>{po.tag}</span>
              {po.status === "received" && _ms_pill("ok",   "received")}
              {po.status === "in-build" && _ms_pill("info", "in-build")}
              {po.status === "released" && _ms_pill("warn", "released")}
            </div>
            <div style={{ display: "flex", alignItems: "baseline", justifyContent: "space-between", marginTop: 4 }}>
              <span style={{ fontFamily: "var(--font-mono)", fontSize: 12, color: _MS_COL.ink4 }}>{po.part_num}</span>
              <span style={{ fontSize: 12, color: _MS_COL.ink4, fontFamily: "var(--font-mono)" }}>
                LT {po.lead_days} d
              </span>
            </div>
            <div style={{ fontSize: 12, color: _MS_COL.ink, marginTop: 4 }}>{po.part_name}</div>
            <div style={{ fontSize: 12, color: _MS_COL.ink3, marginTop: 4 }}>{po.supplier}</div>
            <div style={{ marginTop: 8 }}>
              <_MSGauge v={po.pct} target="100%" ok={po.status === "received"} />
            </div>
            <div style={{
              display: "flex", justifyContent: "space-between",
              marginTop: 6, fontSize: 12, color: _MS_COL.ink3, fontFamily: "var(--font-mono)",
            }}>
              <span>released {po.released}</span>
              <span>ETA {po.eta}</span>
            </div>
            <div style={{ fontSize: 12, color: _MS_COL.ink2, marginTop: 8, lineHeight: 1.5 }}>
              {po.note}
            </div>
            {po.tag === "PO-MTL-LL-001" && (
              <div style={{
                marginTop: 10, padding: 10,
                border: "1px dashed " + _MS_COL.bad, background: "color-mix(in oklch, " + _MS_COL.bad + " 6%, transparent)",
                borderRadius: 2,
              }}>
                <div style={{ display: "flex", alignItems: "center", gap: 6 }}>
                  {_ms_dot("err")}
                  <span style={{ fontSize: 12, color: _MS_COL.ink, fontWeight: 600 }}>
                    Calculated risk · GMN sole-source
                  </span>
                </div>
                <div style={{ fontSize: 12, color: _MS_COL.ink2, marginTop: 6, lineHeight: 1.5 }}>
                  No qualified alternate exists for HSK-A63 24 k rpm direct-drive at this torque/runout class.
                  Single-point failure on program critical path.
                </div>
                <div style={{ marginTop: 8 }}>
                  {_ms_btn({ variant: "primary", onClick: () => setShowSpindleRisk(true), children: "Open spindle risk panel" })}
                </div>
              </div>
            )}
          </div>
        ))}
      </div>
    </div>
  );
}

function _MSLineGraniteCell({ graniteCell, setShowStoneReorder, flashToast }) {
  return (
    <div style={{ borderRight: "1px solid " + _MS_COL.line, display: "flex", flexDirection: "column", minHeight: 0 }}>
      <div style={{
        padding: "8px 14px", borderBottom: "1px solid " + _MS_COL.line,
        background: _MS_COL.bg2,
        display: "flex", justifyContent: "space-between", alignItems: "center",
      }}>
        {_ms_label("GRANITE CELL · S3")}
        <span style={{ color: _MS_COL.warn, fontSize: 12, fontFamily: "var(--font-mono)" }}>
          1 short
        </span>
      </div>
      <div style={{ flex: 1, overflow: "auto" }}>
        {graniteCell.map(g => (
          <div key={g.sku} style={{
            padding: 12, borderBottom: "1px solid " + _MS_COL.lineSoft,
            background: g.severity === "critical"
              ? "color-mix(in oklch, " + _MS_COL.bad + " 6%, transparent)"
              : "transparent",
          }}>
            <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between" }}>
              <span style={{ fontFamily: "var(--font-mono)", fontSize: 12, color: _MS_COL.ink3 }}>{g.sku}</span>
              {g.severity === "critical" && _ms_pill("err",  "critical")}
              {g.severity === "ok"       && _ms_pill("ok",   "in stock")}
            </div>
            <div style={{ fontSize: 12, color: _MS_COL.ink, marginTop: 4 }}>{g.name}</div>
            <div style={{ fontSize: 12, color: _MS_COL.ink3, marginTop: 4 }}>{g.vendor}</div>
            <div style={{
              marginTop: 6, fontFamily: "var(--font-mono)", fontSize: 12, color: _MS_COL.ink3,
              display: "grid", gridTemplateColumns: "1fr 1fr 1fr",
            }}>
              <span>need <b style={{ color: _MS_COL.ink }}>{g.need}</b></span>
              <span>o/h  <b style={{ color: g.severity === "critical" ? _MS_COL.bad : _MS_COL.ink }}>{g.on_hand}</b></span>
              <span>{g.reorder > 0 ? "ro " + g.reorder : "—"}</span>
            </div>
            {g.blocks && (
              <div style={{ fontSize: 12, color: _MS_COL.ink2, marginTop: 8, lineHeight: 1.5 }}>
                Blocks: <b>{g.blocks}</b>
              </div>
            )}
            {g.severity === "critical" && (
              <div style={{ display: "flex", gap: 6, marginTop: 8 }}>
                {_ms_btn({ onClick: () => setShowStoneReorder(true), children: "Expedite reorder" })}
                {_ms_btn({ onClick: () => flashToast("Routed substitution request to D. Becker"), children: "Substitute grade 800" })}
              </div>
            )}
          </div>
        ))}
        <div style={{ padding: 12, fontSize: 12, color: _MS_COL.ink3, lineHeight: 1.6 }}>
          {_ms_label("CELL SETUP NOTES")}
          <ul style={{ margin: "4px 0 0 0", padding: "0 0 0 14px" }}>
            <li>Granite re-grind cell qualified per ECO-MS-0017 (rev D).</li>
            <li>Two-pass lap: rough → re-grind diamond → finish lap.</li>
            <li>SPC chart linked to Cp/Cpk study at G3-VT-05.</li>
            <li>Plate flatness re-checked weekly · last 2026-04-19 · 1.5 µm.</li>
          </ul>
        </div>
      </div>
    </div>
  );
}

function _MSLineToolingOps({ tooling, operators, totalToolsReady, totalToolsTotal }) {
  return (
    <div style={{ borderRight: "1px solid " + _MS_COL.line, display: "flex", flexDirection: "column", minHeight: 0 }}>
      <div style={{
        padding: "8px 14px", borderBottom: "1px solid " + _MS_COL.line,
        background: _MS_COL.bg2,
        display: "flex", justifyContent: "space-between", alignItems: "center",
      }}>
        {_ms_label("TOOLING · " + tooling.length + " ITEMS")}
        <span style={{ color: _MS_COL.warn, fontSize: 12, fontFamily: "var(--font-mono)" }}>
          {totalToolsReady} ready · {totalToolsTotal - totalToolsReady} attn
        </span>
      </div>
      <div style={{ flex: 1, overflow: "auto" }}>
        {tooling.map(t => (
          <div key={t.id} style={{
            display: "grid", gridTemplateColumns: "100px 1fr 70px",
            padding: "8px 12px",
            borderBottom: "1px solid " + _MS_COL.lineSoft,
            alignItems: "center",
            fontSize: 12,
          }}>
            <div style={{ fontFamily: "var(--font-mono)", fontSize: 12, color: _MS_COL.ink3 }}>{t.id}</div>
            <div>
              <div style={{ color: _MS_COL.ink }}>{t.name}</div>
              <div style={{ fontFamily: "var(--font-mono)", fontSize: 12, color: _MS_COL.ink4, marginTop: 2 }}>
                {t.station} · {t.calib}
              </div>
            </div>
            <div>
              {t.status === "ready"   && _ms_pill("ok",   "ready")}
              {t.status === "in-prep" && _ms_pill("warn", "in-prep")}
              {t.status === "warn"    && _ms_pill("warn", "due")}
              {t.status === "short"   && _ms_pill("err",  "short")}
            </div>
          </div>
        ))}
        <div style={{
          padding: "10px 14px",
          borderTop: "1px solid " + _MS_COL.line,
          background: _MS_COL.bg2,
        }}>
          {_ms_label("OPERATORS · SHIFT A")}
        </div>
        {operators.reduce((acc, o) => { if (o.shift === "A") acc.push(o); return acc; }, []).map(o => (
          <div key={o.name} style={{ padding: "10px 14px", borderBottom: "1px solid " + _MS_COL.lineSoft }}>
            <div style={{ display: "flex", alignItems: "center", gap: 8, marginBottom: 4 }}>
              {_ms_avatar(o.name, 24)}
              <div style={{ minWidth: 0 }}>
                <div style={{ color: _MS_COL.ink, fontSize: 12 }}>{o.name}</div>
                <div style={{ fontSize: 12, color: _MS_COL.ink4 }}>{o.role}</div>
              </div>
            </div>
            <div style={{
              display: "grid", gridTemplateColumns: "55px 1fr",
              gap: 4, marginTop: 4, fontSize: 12,
              fontFamily: "var(--font-mono)",
            }}>
              {Object.entries(o.skills).map(([k, v]) => (
                <React.Fragment key={k}>
                  <div style={{ color: _MS_COL.ink4, textTransform: "uppercase", letterSpacing: "0.04em" }}>{k}</div>
                  <_MSSkillBar v={v} />
                </React.Fragment>
              ))}
            </div>
          </div>
        ))}
        <div style={{ padding: "10px 14px", fontSize: 12, color: _MS_COL.ink4 }}>
          Shift B (R. Vogt) on-call for FAI test events only.
        </div>
      </div>
    </div>
  );
}

function _MSLineNcrRisk({ ncrs, setShowSpindleRisk, flashToast }) {
  return (
    <div style={{ display: "flex", flexDirection: "column", minHeight: 0 }}>
      <div style={{
        padding: "8px 14px", borderBottom: "1px solid " + _MS_COL.line,
        background: _MS_COL.bg2,
        display: "flex", justifyContent: "space-between", alignItems: "center",
      }}>
        {_ms_label("NCR / QUALITY")}
        <span style={{ color: _MS_COL.bad, fontSize: 12, fontFamily: "var(--font-mono)" }}>
          {ncrs.length} open
        </span>
      </div>
      <div style={{ flex: 1, overflow: "auto" }}>
        {ncrs.map(n => (
          <div key={n.id} style={{ padding: 14, borderBottom: "1px solid " + _MS_COL.lineSoft }}>
            <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between" }}>
              <span style={{ fontFamily: "var(--font-mono)", color: _MS_COL.ink3, fontSize: 12 }}>{n.id}</span>
              {_ms_pill(_ms_severityTone(n.severity), n.severity)}
            </div>
            <div style={{ fontSize: 12, color: _MS_COL.ink, marginTop: 4 }}>{n.title}</div>
            <div style={{ fontSize: 12, color: _MS_COL.ink3, marginTop: 4 }}>
              {n.supplier !== "—" && <span>supplier <b>{n.supplier}</b> · </span>}
              {n.lot !== "—"      && <span>lot <span style={{ fontFamily: "var(--font-mono)" }}>{n.lot}</span> · </span>}
              age <span style={{ fontFamily: "var(--font-mono)" }}>{n.age_days} d</span>
            </div>
            <div style={{ fontSize: 12, color: _MS_COL.ink2, marginTop: 6, lineHeight: 1.5 }}>{n.status}</div>
            <div style={{ fontSize: 12, color: _MS_COL.ink3, marginTop: 4, lineHeight: 1.5 }}>
              <i>action:</i> {n.action}
            </div>
            <div style={{ marginTop: 8, display: "flex", gap: 6 }}>
              {_ms_btn({ children: "Open NCR" })}
              {_ms_btn({ icon: "Sparkle", children: "Suggest dispo" })}
            </div>
          </div>
        ))}

        <div style={{
          margin: 12,
          padding: 14,
          border: "1px solid " + _MS_COL.bad,
          borderRadius: 3,
          background: "color-mix(in oklch, " + _MS_COL.bad + " 4%, " + _MS_COL.bg + ")",
        }}>
          <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between" }}>
            {_ms_label("CALCULATED RISK · GMN SOLE-SOURCE", _MS_COL.bad)}
            {_ms_pill("err", "single-point")}
          </div>
          <div style={{ fontSize: 12, color: _MS_COL.ink, marginTop: 8, lineHeight: 1.55 }}>
            No qualified dual-source exists for the HSK-A63 24 k rpm spindle module.
            Kessler's tilting head accepts only GMN, IBAG, and Step-Tec spindles at this
            runout class. Step-Tec qualified internally but not on this Kessler frame;
            IBAG never benchmarked.
          </div>
          <div style={_MS_A4_RISK_BOX_STYLE}>
            <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", rowGap: 4 }}>
              <span style={{ color: _MS_COL.ink4, fontFamily: "var(--font-mono)", fontSize: 12, letterSpacing: "0.05em" }}>impact</span>
              <span style={{ fontFamily: "var(--font-mono)" }}>180 d slip per failure event</span>
              <span style={{ color: _MS_COL.ink4, fontFamily: "var(--font-mono)", fontSize: 12, letterSpacing: "0.05em" }}>likelihood</span>
              <span style={{ fontFamily: "var(--font-mono)" }}>3% / unit · Kessler EOL data 2018-2025</span>
              <span style={{ color: _MS_COL.ink4, fontFamily: "var(--font-mono)", fontSize: 12, letterSpacing: "0.05em" }}>exposure</span>
              <span style={{ fontFamily: "var(--font-mono)" }}>€32 000 unit cost + €120 000 program slip</span>
            </div>
          </div>
          <div style={{ fontSize: 12, color: _MS_COL.ink2, marginTop: 8, lineHeight: 1.55 }}>
            <b>Mitigation paths</b>: (1) ring-fence one finished spindle as program safety stock,
            (2) commission Step-Tec benchmark on Kessler frame (12 wk + €18 k),
            (3) accept residual risk and surface to MAHLE in PPAP narrative.
          </div>
          <div style={{ display: "flex", gap: 6, marginTop: 10 }}>
            {_ms_btn({ onClick: () => setShowSpindleRisk(true), children: "Open mitigation plan" })}
            {_ms_btn({ onClick: () => flashToast("Risk note pinned to ECO-MS-0017"), children: "Pin to ECO-MS-0017" })}
          </div>
        </div>

        <div style={{ padding: 12, fontSize: 12, color: _MS_COL.ink3, lineHeight: 1.6 }}>
          {_ms_label("READINESS VERDICT")}
          <div style={{ marginTop: 6 }}>
            Line is <b style={{ color: _MS_COL.warn }}>conditionally ready</b> for shift A on{" "}
            <span style={{ fontFamily: "var(--font-mono)" }}>2026-04-30</span>.
            Resolve <span style={{ fontFamily: "var(--font-mono)" }}>LST-600-G</span> shortage and
            re-dress diamond wheel before <span style={{ fontFamily: "var(--font-mono)" }}>06:00</span>.
            If both clear by <span style={{ fontFamily: "var(--font-mono)" }}>22:00</span> tonight,
            granite re-grind op can run 2 cycles before WO-MTL-2401 enters s3 on{" "}
            <span style={{ fontFamily: "var(--font-mono)" }}>2026-05-01 09:00</span>.
          </div>
        </div>
      </div>
    </div>
  );
}

function _MSSkillBar({ v }) {
  const tone = v >= 0.9 ? _MS_COL.ok : v >= 0.6 ? _MS_COL.info : v >= 0.3 ? _MS_COL.warn : _MS_COL.ink4;
  return (
    <div style={{ display: "flex", alignItems: "center", gap: 4 }}>
      <div style={{ height: 5, flex: 1, background: _MS_COL.bg2, borderRadius: 1, overflow: "hidden", border: "1px solid " + _MS_COL.lineSoft }}>
        <div style={{ width: (v * 100) + "%", height: "100%", background: tone }} />
      </div>
      <span style={{ width: 26, textAlign: "right", color: _MS_COL.ink3, fontFamily: "var(--font-mono)", fontSize: 12 }}>{Math.round(v * 100)}</span>
    </div>
  );
}

/* ════════════════════════════════════════════════════════════════════
   §4 — Route registration
   The mittelstand registry-router (agent #3) exposes
   `registerMittelstandRoute` on window. Falls back to `registerPumpRoute`
   if the mittelstand registry is not yet loaded — defensive only.
   ──────────────────────────────────────────────────────────────────── */

(function _ms_registerAct4Routes() {
  const reg = (typeof registerMittelstandRoute === "function")
    ? registerMittelstandRoute
    : (typeof window !== "undefined" && typeof window.registerMittelstandRoute === "function")
      ? window.registerMittelstandRoute
      : (typeof registerPumpRoute === "function")
        ? registerPumpRoute
        : null;
  if (!reg) return;

  reg({
    path: "/build/routing",
    mode: "build",
    title: "Routing canvas · MTL-220 D",
    renderer: () => React.createElement(ScreenMittelstandRouting),
  });
  reg({
    path: "/build/gates",
    mode: "build",
    title: "Quality gates · 5-gate flow",
    renderer: () => React.createElement(ScreenMittelstandQualityGates),
  });
  reg({
    path: "/line/readiness",
    mode: "line",
    title: "Line readiness",
    renderer: () => React.createElement(ScreenMittelstandLineReadiness),
  });
})();

/* expose components on window for the cross-cutting palette ⌘K to find */
if (typeof window !== "undefined") {
  window.ScreenMittelstandRouting       = ScreenMittelstandRouting;
  window.ScreenMittelstandQualityGates  = ScreenMittelstandQualityGates;
  window.ScreenMittelstandLineReadiness = ScreenMittelstandLineReadiness;
}
})();
