(function(){
/* FORGE · mittelstand tenant — Wave A1 / Agent #14 (traveler-D)
   Station 4: Final FAI + customer acceptance. /traveler/test (mode=traveler).
   Emits FAI_PASSED → ACCEPTANCE_SIGNED. Spec: demo/tenant-spec/mittelstand.md §8.
   Mirrors pump/act4-screens.jsx ScreenStationTest (~2216). Palette per §10
   (cool graphite hue 250). Babel-standalone, no imports/exports. Registers
   defensively against `registerMittelstandRoute` (agent #3 registry). */

const { useState: uMSF, useEffect: uEMSF, useRef: uRMSF } = React;

/* Palette — mittelstand cool graphite per §10. Inlined so the screen
   renders even before agent #8's cross-cutting.jsx publishes globals. */
const MS_BG          = "oklch(0.97 0.003 250)";
const MS_BG_2        = "oklch(0.92 0.004 250)";
const MS_BG_3        = "oklch(0.95 0.003 250)";
const MS_INK         = "oklch(0.18 0.01  250)";
const MS_INK_2       = "oklch(0.32 0.01  250)";
const MS_INK_3       = "oklch(0.48 0.01  250)";
const MS_INK_4       = "oklch(0.62 0.005 250)";
const MS_LINE        = "oklch(0.82 0.005 250)";
const MS_LINE_SOFT   = "oklch(0.88 0.004 250)";
const MS_ACCENT      = "oklch(0.55 0.02  250)";
const MS_ACCENT_WARN = "oklch(0.62 0.13  60)";
const MS_ACCENT_BAD  = "oklch(0.55 0.18  25)";
const MS_OK          = "oklch(0.55 0.13  150)";
const MS_FONT_UI     = "var(--font-ui)";
const MS_FONT_MONO   = "var(--font-mono)";

/* Extracted styles (react-doctor: no-inline-exhaustive-style). */
function _msfAvatarStyle(s, t) {
  return { display: "inline-flex", alignItems: "center", justifyContent: "center",
    width: s, height: s, borderRadius: "50%",
    background: "color-mix(in oklch, " + t + " 16%, " + MS_BG_2 + ")", color: t,
    border: "1px solid color-mix(in oklch, " + t + " 30%, " + MS_LINE + ")",
    fontFamily: MS_FONT_MONO, fontSize: 12, letterSpacing: "0.04em", fontWeight: 600 };
}
function _msfStatStyle(tone) {
  return { display: "inline-flex", alignItems: "center", gap: 5,
    padding: "2px 7px", borderRadius: 3,
    fontFamily: MS_FONT_MONO, fontSize: 12, letterSpacing: "0.04em",
    color: tone, background: "color-mix(in oklch, " + tone + " 10%, transparent)",
    border: "1px solid color-mix(in oklch, " + tone + " 28%, transparent)" };
}
function _msfBtnStyle(primary, ghost, disabled) {
  return { display: "inline-flex", alignItems: "center", gap: 6, padding: "7px 12px",
    fontFamily: MS_FONT_MONO, fontSize: 12, letterSpacing: "0.03em",
    color: primary ? "#fff" : (disabled ? MS_INK_4 : MS_INK),
    background: primary ? MS_INK : (ghost ? "transparent" : MS_BG),
    border: "1px solid " + (primary ? MS_INK : MS_LINE), borderRadius: 3,
    cursor: disabled ? "not-allowed" : "pointer",
    opacity: disabled ? 0.55 : 1 };
}
function _msfTestNumStyle(pass) {
  return { width: 22, height: 22, borderRadius: "50%",
    background: pass ? MS_OK : MS_ACCENT_BAD, color: "#fff",
    display: "inline-flex", alignItems: "center", justifyContent: "center",
    fontSize: 12, fontFamily: MS_FONT_MONO, fontWeight: 600 };
}
const _MSF_PASS_BANNER_STYLE = { marginTop: 8, padding: 10,
  background: "color-mix(in oklch, " + MS_OK + " 8%, transparent)",
  border: "1px solid " + MS_OK, borderRadius: 4, fontSize: 12, color: MS_INK,
  display: "flex", justifyContent: "space-between", alignItems: "center" };
function _msfWitnessInputStyle(accepted) {
  return { flex: 1, padding: "7px 10px",
    fontFamily: MS_FONT_UI, fontSize: 12, color: MS_INK,
    background: accepted ? MS_BG_3 : MS_BG,
    border: "1px solid " + MS_LINE, borderRadius: 3, outline: "0 solid transparent" };
}
const _MSF_PDF_ROW_STYLE = { padding: 12, border: "1px solid " + MS_LINE, borderRadius: 4, background: MS_BG,
  display: "flex", justifyContent: "space-between", alignItems: "center", gap: 12 };
const _MSF_TOAST_STYLE = {
  position: "fixed",
  bottom: 24, right: 24,
  padding: "10px 14px",
  background: MS_INK, color: "#fff",
  borderRadius: 4,
  fontFamily: MS_FONT_MONO, fontSize: 12, letterSpacing: "0.03em",
  boxShadow: "0 8px 28px -10px rgba(0,0,0,0.30)",
  zIndex: 50,
};

function _msf_initials(n) {
  if (!n) return "—";
  const p = String(n).replace(/[^A-Za-z. ]/g, "").split(/\s+/).filter(Boolean);
  if (!p.length) return "—";
  return ((p[0][0] || "") + (p[1] ? p[1][0] : (p[0][1] || ""))).toUpperCase();
}

function _msf_avatar(name, size, tone) {
  const s = size || 22, t = tone || MS_ACCENT;
  return (
    <span style={_msfAvatarStyle(s, t)}>{_msf_initials(name)}</span>
  );
}

function _msf_stat(pass, label) {
  const tone = pass ? MS_OK : MS_ACCENT_BAD;
  return (
    <span style={_msfStatStyle(tone)}>
      <span style={{ width: 6, height: 6, borderRadius: "50%", background: tone }} />
      {label || (pass ? "in tol" : "out of tol")}
    </span>
  );
}

function _msf_btn({ children, onClick, variant, disabled, title }) {
  const primary = variant === "primary", ghost = variant === "ghost";
  return (
    <button type="button" title={title} disabled={!!disabled}
      onClick={disabled ? undefined : onClick}
      style={_msfBtnStyle(primary, ghost, disabled)}>{children}</button>
  );
}

function _msf_label({ children }) {
  return <div style={{ fontFamily: MS_FONT_MONO, fontSize: 12, letterSpacing: "0.14em",
    textTransform: "uppercase", color: MS_INK_4 }}>{children}</div>;
}

function _msf_kv({ k, v, mono }) {
  return (<div><_msf_label>{k}</_msf_label>
    <span style={{ fontFamily: mono ? MS_FONT_MONO : MS_FONT_UI, fontSize: 12, color: MS_INK }}>{v}</span>
  </div>);
}

function _MSFStationHeader({ operator, station, seq, wo, right }) {
  return (
    <div style={{ padding: "10px 14px", background: MS_BG_2, borderBottom: "1px solid " + MS_LINE,
      display: "flex", alignItems: "center", gap: 14 }}>
      {_msf_avatar(operator, 32, MS_ACCENT)}
      <div style={{ flex: 1, minWidth: 0 }}>
        <div style={{ fontFamily: MS_FONT_UI, fontSize: 13, color: MS_INK, display: "flex", alignItems: "center", gap: 8 }}>
          <b>{operator}</b><span style={{ color: MS_INK_4 }}>·</span><span style={{ color: MS_INK_2 }}>{station}</span>
          {seq && <span style={{ marginLeft: 6, padding: "1px 6px", border: "1px solid " + MS_LINE, borderRadius: 3,
            fontFamily: MS_FONT_MONO, fontSize: 12, color: MS_INK_3 }}>seq {seq}</span>}
        </div>
        <div style={{ fontFamily: MS_FONT_MONO, fontSize: 12, color: MS_INK_4, marginTop: 2 }}>{wo}</div>
      </div>
      {right}
    </div>
  );
}

/* Ballbar — synthetic ISO 230-4 polar trace · captured circularity 2.6 µm */
function _MSFBallbar() {
  const W = 220, H = 220, cx = W / 2, cy = H / 2, rNominal = 70, N = 240;
  const pts = [];
  for (let i = 0; i < N; i++) {
    const th = (i / N) * Math.PI * 2;
    const dev = 0.9 * Math.sin(th * 4) + 0.4 * Math.sin(th * 2 + 0.6);
    const r = rNominal + dev * 1.6;
    pts.push([cx + r * Math.cos(th), cy + r * Math.sin(th)]);
  }
  const path = pts.map(function(p, i){ return (i ? "L" : "M") + p[0].toFixed(2) + "," + p[1].toFixed(2); }).join(" ") + " Z";
  return (
    <svg viewBox={"0 0 " + W + " " + H} width="100%" height={H} style={{ background: MS_BG, border: "1px solid " + MS_LINE, borderRadius: 4 }}>
      {/* tolerance band ±5 µm illustrative ring */}
      <circle cx={cx} cy={cy} r={rNominal + 4} fill="none" stroke={MS_LINE_SOFT} strokeDasharray="3 3" />
      <circle cx={cx} cy={cy} r={rNominal - 4} fill="none" stroke={MS_LINE_SOFT} strokeDasharray="3 3" />
      <circle cx={cx} cy={cy} r={rNominal} fill="none" stroke={MS_ACCENT} strokeWidth="1.0" />
      {/* axes */}
      <line x1={cx - 90} y1={cy} x2={cx + 90} y2={cy} stroke={MS_LINE_SOFT} strokeWidth="0.5" />
      <line x1={cx} y1={cy - 90} x2={cx} y2={cy + 90} stroke={MS_LINE_SOFT} strokeWidth="0.5" />
      {/* captured trace */}
      <path d={path} fill="none" stroke={MS_OK} strokeWidth="1.4" />
      {/* legend */}
      <g transform="translate(8, 12)">
        <text x="0" y="0" fontSize="9.5" fontFamily={MS_FONT_MONO} fill={MS_INK_3}>ballbar · Renishaw QC20-W · 150 mm</text>
        <text x="0" y="12" fontSize="9.5" fontFamily={MS_FONT_MONO} fill={MS_INK_3}>circularity 2.6 µm · tol ±5 µm</text>
      </g>
      <g transform={"translate(" + (W - 80) + ", " + (H - 18) + ")"}>
        <line x1="0" y1="-3" x2="14" y2="-3" stroke={MS_OK} strokeWidth="1.4" />
        <text x="20" y="0" fontSize="9" fontFamily={MS_FONT_MONO} fill={MS_INK_4}>captured</text>
      </g>
    </svg>
  );
}

/* Vibration trace — mm/s RMS over 60 s @ 12k rpm contouring */
function _MSFVibrationTrace() {
  const W = 460, H = 160, padL = 38, padB = 28, padT = 14, padR = 10;
  const innerW = W - padL - padR, innerH = H - padT - padB, Vmax = 1.0;
  const samples = [];
  for (let i = 0; i < 60; i++) {
    const base = 0.42 + 0.10 * Math.sin(i / 5) + 0.06 * Math.sin(i / 1.7);
    samples.push({ t: i, v: Math.max(0.1, Math.min(0.85, base + (i === 28 ? 0.18 : 0))) });
  }
  const sx = function(t){ return padL + (t / 60) * innerW; };
  const sy = function(v){ return padT + innerH - (v / Vmax) * innerH; };
  const path = samples.map(function(p, i){ return (i ? "L" : "M") + sx(p.t) + "," + sy(p.v); }).join(" ");
  const peak = samples.reduce(function(a, p){ return p.v > a.v ? p : a; }, samples[0]);
  return (
    <svg viewBox={"0 0 " + W + " " + H} width="100%" height={H} style={{ background: MS_BG, border: "1px solid " + MS_LINE, borderRadius: 4 }}>
      {/* y grid */}
      {[0, 0.2, 0.4, 0.6, 0.8, 1.0].map(function(v){
        return (
          <g key={"y"+v}>
            <line x1={padL} y1={sy(v)} x2={W - padR} y2={sy(v)} stroke={MS_LINE_SOFT} strokeWidth="0.5" />
            <text x={padL - 5} y={sy(v) + 4} fontSize="9" textAnchor="end" fontFamily={MS_FONT_MONO} fill={MS_INK_4}>{v.toFixed(1)}</text>
          </g>
        );
      })}
      {/* x grid */}
      {[0, 15, 30, 45, 60].map(function(t){
        return (
          <g key={"x"+t}>
            <line x1={sx(t)} y1={padT} x2={sx(t)} y2={H - padB} stroke={MS_LINE_SOFT} strokeWidth="0.5" />
            <text x={sx(t)} y={H - padB + 12} fontSize="9" textAnchor="middle" fontFamily={MS_FONT_MONO} fill={MS_INK_4}>{t}s</text>
          </g>
        );
      })}
      {/* limit bands: 0.8 accept · 1.0 ship-hold */}
      <line x1={padL} y1={sy(0.8)} x2={W - padR} y2={sy(0.8)} stroke={MS_ACCENT_WARN} strokeDasharray="4 3" strokeWidth="1.0" />
      <text x={W - padR - 4} y={sy(0.8) - 3} fontSize="9" textAnchor="end" fontFamily={MS_FONT_MONO} fill={MS_ACCENT_WARN}>accept ≤ 0.8 mm/s RMS</text>
      <text x="6" y="14" fontSize="9.5" fontFamily={MS_FONT_MONO} fill={MS_INK_3}>v (mm/s RMS)</text>
      <text x={W - padR - 4} y={H - 4} fontSize="9.5" textAnchor="end" fontFamily={MS_FONT_MONO} fill={MS_INK_3}>t (60 s · 12k rpm contouring)</text>
      {/* trace */}
      <path d={path} stroke={MS_OK} strokeWidth="1.4" fill="none" />
      {/* peak marker */}
      <circle cx={sx(peak.t)} cy={sy(peak.v)} r="4" fill={MS_OK} stroke={MS_BG} strokeWidth="1.4" />
      <text x={sx(peak.t) + 8} y={sy(peak.v) - 6} fontSize="10" fontFamily={MS_FONT_MONO} fill={MS_OK} fontWeight="600">
        peak {peak.v.toFixed(2)} mm/s
      </text>
    </svg>
  );
}

/* ════════════════════════════════════════════════════════════════════
   ScreenMittelstandFAI — Station 4 (FAI + customer acceptance)
   Mounted at /traveler/test in mittelstand registry.
   ──────────────────────────────────────────────────────────────────── */

function _MSFTestResultsTable({ tests }) {
  return (
    <div style={{ padding: 16, borderRight: "1px solid " + MS_LINE, minWidth: 0 }}>
      <div style={{ display: "flex", justifyContent: "space-between", alignItems: "baseline", marginBottom: 10 }}>
        <_msf_label>ISO 230-2 GEOMETRIC TEST · 9 ITEMS · MTL-220 REV D</_msf_label>
        <span style={{ fontFamily: MS_FONT_MONO, fontSize: 12, color: MS_INK_3 }}>
          ref · INS-MTL-220-D-04 · CMM Zeiss UPMC 850 cross-check
        </span>
      </div>

      {tests.map(function(t, i) {
        return (
          <div key={t.id} style={{ padding: 11, marginBottom: 8,
            border: "1px solid " + (t.pass ? MS_LINE : MS_ACCENT_BAD),
            borderRadius: 4, background: MS_BG }}>
            <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: 6 }}>
              <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
                <span style={_msfTestNumStyle(t.pass)}>{i + 1}</span>
                <span style={{ color: MS_INK, fontSize: 13, fontWeight: 500 }}>{t.name}</span>
                <span style={{ fontFamily: MS_FONT_MONO, fontSize: 12, color: MS_INK_4,
                  padding: "1px 6px", border: "1px solid " + MS_LINE_SOFT, borderRadius: 3 }}>{t.id}</span>
              </div>
              {_msf_stat(t.pass)}
            </div>
            <div style={{ display: "grid", gridTemplateColumns: "1.4fr 0.9fr 0.9fr 90px", gap: 8, fontSize: 12 }}>
              <_msf_kv k="instrument" v={t.instrument} />
              <_msf_kv k="spec" v={t.spec} mono />
              <_msf_kv k="captured" v={t.captured} mono />
              <_msf_kv k="timestamp" v={t.ts} mono />
            </div>
          </div>
        );
      })}

      <div style={_MSF_PASS_BANNER_STYLE}>
        <span><b>{tests.filter(function(t){ return t.pass; }).length} / {tests.length} tests passed.</b>
          {" "}Granite flatness post-ECO-MS-0017 verified · vibration root-cause cleared.</span>
        <span style={{ fontFamily: MS_FONT_MONO, fontSize: 12, color: MS_OK }}>total 88:14</span>
      </div>
    </div>
  );
}

function _MSFWitnessPanel({ witnessName, setWitness, witnessPresent, witnessTs, accepted, onCaptureWitness }) {
  return (
    <div style={{ padding: 12, border: "1px solid " + MS_LINE, borderRadius: 4, background: MS_BG }}>
      <div style={{ display: "flex", justifyContent: "space-between", alignItems: "baseline", marginBottom: 8 }}>
        <_msf_label>MAHLE WITNESS SIGNATURE</_msf_label>
        <span style={{ fontFamily: MS_FONT_MONO, fontSize: 12, color: MS_INK_4 }}>{witnessPresent ? "captured" : "awaiting"}</span>
      </div>
      <div style={{ display: "flex", gap: 8, alignItems: "center" }}>
        <input id="ms-trav-fai-f1" name="ms-trav-fai-f1" aria-label="MAHLE QA representative · full name" type="text" value={witnessName}
          onChange={function(e){ setWitness(e.target.value); }}
          disabled={accepted} placeholder="MAHLE QA representative · full name"
          style={_msfWitnessInputStyle(accepted)} />
        <_msf_btn variant={witnessName.trim() && !witnessPresent ? "primary" : ""}
          onClick={onCaptureWitness}
          disabled={!witnessName.trim() || witnessPresent || accepted}>
          {witnessPresent ? "Captured ✓" : "Capture signature"}
        </_msf_btn>
      </div>
      {witnessPresent && (
        <div style={{ marginTop: 8, display: "flex", gap: 14, fontSize: 12 }}>
          <_msf_kv k="witnessName" v={witnessName.trim()} />
          <_msf_kv k="witnessTs" v={witnessTs} mono />
          <_msf_kv k="role" v="MAHLE Industriebeteiligungen · QA" />
        </div>
      )}
    </div>
  );
}

function _MSFAcceptanceGate({ canAdvance, accepted, allPass, pdfGenerated, witnessPresent, onAdvanceAcceptance }) {
  return (
    <div style={{ padding: 12,
      border: "1px solid " + (canAdvance ? MS_OK : MS_LINE), borderRadius: 4,
      background: canAdvance ? "color-mix(in oklch, " + MS_OK + " 6%, " + MS_BG + ")" : MS_BG_3 }}>
      <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: 8 }}>
        <_msf_label>ACCEPTANCE GATE · ALL GREEN REQUIRED</_msf_label>
        <span style={{ fontFamily: MS_FONT_MONO, fontSize: 12, color: canAdvance ? MS_OK : MS_INK_4 }}>
          {accepted ? "closed" : canAdvance ? "ready" : "blocked"}
        </span>
      </div>
      <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr 1fr", gap: 8, marginBottom: 10 }}>
        <_MSFGate label="9 / 9 tests pass" ok={allPass} />
        <_MSFGate label="FAI PDF generated" ok={pdfGenerated} />
        <_MSFGate label="MAHLE witness signed" ok={witnessPresent} />
      </div>
      <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center" }}>
        <div style={{ fontSize: 12, color: MS_INK_3 }}>
          emits <span style={{ fontFamily: MS_FONT_MONO, color: MS_INK }}>FAI_PASSED</span>
          {" → "}
          <span style={{ fontFamily: MS_FONT_MONO, color: MS_INK }}>ACCEPTANCE_SIGNED</span>
          {" · ledger arc closes · TRV-MS-0244"}
        </div>
        <_msf_btn
          variant="primary"
          onClick={onAdvanceAcceptance}
          disabled={!canAdvance}
        >
          {accepted ? "Acceptance signed ▸" : "Advance to acceptance"}
        </_msf_btn>
      </div>
    </div>
  );
}

function ScreenMittelstandFAI() {
  const operator    = "S. Klein";        // Quality Lead — owns FAI per spec
  const stationName = "Final FAI + Acceptance (s4)";
  const serial      = "MTL-220-0095";        // unit 1 of MAHLE batch-1 (matches fixtures-mittelstand.jsx)
  const wo          = "WO-MTL-2401 · MTL-220 Rev D · MAHLE Industriebeteiligungen GmbH · 24u";

  // ISO 230-2 geometric tests · MTL-220 Rev D · post-ECO-MS-0017 (±3 µm granite).
  const _initialTests = [
    { id: "G1", name: "Linear positioning · X-axis",        instrument: "Renishaw XL-80 laser interferometer", spec: "≤ ±3 µm / 600 mm", captured: "+1.8 µm",   pass: true, ts: "08:42:11" },
    { id: "G2", name: "Linear positioning · Y-axis",        instrument: "Renishaw XL-80 laser interferometer", spec: "≤ ±3 µm / 600 mm", captured: "+2.1 µm",   pass: true, ts: "08:51:40" },
    { id: "G3", name: "Linear positioning · Z-axis",        instrument: "Renishaw XL-80 laser interferometer", spec: "≤ ±3 µm / 400 mm", captured: "+1.4 µm",   pass: true, ts: "08:59:02" },
    { id: "G4", name: "Squareness · XY plane",              instrument: "Granite square + LC 415 encoder",     spec: "≤ 4 µm/m",         captured: "2.7 µm/m",  pass: true, ts: "09:08:25" },
    { id: "G5", name: "Squareness · XZ plane",              instrument: "Granite square + LC 415 encoder",     spec: "≤ 4 µm/m",         captured: "3.1 µm/m",  pass: true, ts: "09:14:48" },
    { id: "G6", name: "Squareness · YZ plane",              instrument: "Granite square + LC 415 encoder",     spec: "≤ 4 µm/m",         captured: "2.4 µm/m",  pass: true, ts: "09:21:09" },
    { id: "B1", name: "Ballbar circularity · XY @ 4 m/min", instrument: "Renishaw QC20-W · 150 mm",            spec: "≤ 5 µm",           captured: "2.6 µm",    pass: true, ts: "09:38:17" },
    { id: "B2", name: "Ballbar circularity · YZ @ 4 m/min", instrument: "Renishaw QC20-W · 150 mm",            spec: "≤ 5 µm",           captured: "3.4 µm",    pass: true, ts: "09:46:02" },
    { id: "V1", name: "Contouring vibration · 12k rpm",     instrument: "PCB 356A16 tri-ax + Brüel SQuadriga", spec: "≤ 0.8 mm/s RMS",   captured: "0.61 mm/s", pass: true, ts: "10:02:33" },
  ];

  const [tests]                   = uMSF(_initialTests);
  const [witnessName, setWitness] = uMSF("");
  const [witnessTs, setWitnessTs] = uMSF(null);
  const [pdfGenerated, setPdfGen] = uMSF(false);
  const [accepted, setAccepted]   = uMSF(false);
  const [toast, setToast]         = uMSF(null);
  const _toastTimerRef            = uRMSF(null);

  // Reset on tenant change so screen does not bleed state across tenants
  uEMSF(function() {
    function onTenant() {
      setWitness("");
      setWitnessTs(null);
      setPdfGen(false);
      setAccepted(false);
      setToast(null);
      if (_toastTimerRef.current) { clearTimeout(_toastTimerRef.current); _toastTimerRef.current = null; }
    }
    window.addEventListener("forge:tenant-change", onTenant);
    return function() {
      window.removeEventListener("forge:tenant-change", onTenant);
      if (_toastTimerRef.current) clearTimeout(_toastTimerRef.current);
    };
  }, []);

  function flash(msg) {
    setToast(msg);
    if (_toastTimerRef.current) clearTimeout(_toastTimerRef.current);
    _toastTimerRef.current = setTimeout(function(){ setToast(null); }, 2600);
  }

  function emitForgeEvent(type, payload) {
    if (typeof window === "undefined") return;
    try {
      window.dispatchEvent(new CustomEvent("forge:ledger", {
        detail: {
          type: type,
          actor: operator,
          ts: new Date().toISOString(),
          mode: "traveler",
          station: "s4",
          wo: "WO-MTL-2401",
          part: "MTL-220.00.00",
          serial: serial,
          payload: payload || {},
        },
      }));
    } catch (e) { /* swallow — ledger is best-effort from the screen */ }
  }

  // Wave 8E.3 — server-side traveler checkin. Default station is "s4"
  // (the routing slot), but callers must override to "FAI"/"r6" when the
  // gate-ladder side-effect is desired so the mittelstand state machine
  // inserts the qual_records PPAP-evidence row (server/state-machines/mittelstand.js:222).
  // Returns the underlying promise so callers can chain success/error toasts.
  function _trCheckinMS(extra) {
    const fApi = (typeof window !== "undefined") ? window.forgeApi : null;
    if (!fApi || !fApi.traveler || typeof fApi.traveler.checkin !== "function") {
      return Promise.resolve(null);
    }
    const cur = (typeof window !== "undefined" && window.__forgeCurrentUser) || { name: operator };
    const body = Object.assign({
      station: "s4",
      actor:   cur.name,
    }, extra || {});
    return fApi.traveler.checkin(serial, body);
  }

  const allPass        = tests.every(function(t){ return t.pass; });
  const witnessPresent = witnessName.trim().length > 0 && !!witnessTs;
  const canAdvance     = allPass && pdfGenerated && witnessPresent && !accepted;

  function onCaptureWitness() {
    if (!witnessName.trim()) return;
    const now = new Date();
    const stamp = now.toISOString().slice(0, 19).replace("T", " ") + " UTC";
    setWitnessTs(stamp);
    flash("Witness captured · " + witnessName.trim());
    emitForgeEvent("CUSTOMER_WITNESSED", { witnessName: witnessName.trim(), ts: stamp });
  }

  function onGeneratePdf() {
    setPdfGen(true);
    flash("FAI report PDF generated");
    emitForgeEvent("FAI_PACKAGE_GENERATED", {
      doc: "FAI-" + serial + "-" + new Date().toISOString().slice(0, 10) + ".pdf",
      tests: tests.length,
      framework: "AS9102 · IATF 16949 PPAP Lvl 3",
    });
  }

  function onAdvanceAcceptance() {
    if (!canAdvance) return;
    setAccepted(true);
    emitForgeEvent("FAI_PASSED", {
      tests_passed: tests.length,
      ballbar_um: 2.6,
      vibration_mm_s_rms: 0.61,
      framework: "ISO 230-2 · ISO 230-4 · IATF 16949",
    });
    // Per spec §8 station 4: FAI_PASSED → ACCEPTANCE_SIGNED, ledger close.
    emitForgeEvent("ACCEPTANCE_SIGNED", {
      customer:  "MAHLE Industriebeteiligungen GmbH",
      witness:   witnessName.trim(),
      witness_ts: witnessTs,
      traveler:  "TRV-MS-0244",
      release:   "unit released · ledger arc closes",
    });
    // Wave 8E.3 — persist FAI pass on the server. Station "FAI" routes
    // through mittelstand.js applyCheckin, which inserts a qual_records row
    // with the PPAP evidence (ppap_level, dim_report, evidence_uri) and
    // flips traveler.status → "ship". Toast surfaces server result.
    _trCheckinMS({
      station: "FAI",
      result: "pass",
      ppap_level: 3,
      evidence_uri: "ipfs://Qm-FAI-demo",
      dim_report: "DR-2026-095",
      material_cert: "CoC-MTL-220-0095",
      functional_test: "ISO 230-2 · ballbar · vibration",
      dispo_path: "acceptance-signed",
      dimensions: {
        tests_passed: tests.length,
        ballbar_um: 2.6,
        vibration_mm_s_rms: 0.61,
      },
      photos: ["FAI-" + serial + "-" + new Date().toISOString().slice(0, 10) + ".pdf"],
      notes: "FAI_PASSED · PPAP-3 · witness " + witnessName.trim(),
      measurement_notes: "FAI_PASSED → ACCEPTANCE_SIGNED · witness " + witnessName.trim(),
    }).then(function(r) {
      const qr = r && r.qualRecord;
      flash(qr
        ? "FAI_PASSED → ship · qual " + qr.id + " · PPAP-3"
        : "FAI_PASSED → ACCEPTANCE_SIGNED · TRV-MS-0244");
    }).catch(function(err) {
      const msg = (err && err.message) || "FAI checkin failed";
      if (typeof console !== "undefined") console.warn("[mittelstand-fai] traveler.checkin failed", err);
      flash("error · " + msg);
    });
  }

  return (
    <div style={{
      display: "flex", flexDirection: "column",
      height: "100%", minHeight: 0,
      fontFamily: MS_FONT_UI, color: MS_INK, background: MS_BG,
    }}>

      <_MSFStationHeader
        operator={operator}
        station={stationName}
        seq="04 / 04"
        wo={wo}
        right={
          <span style={{ fontFamily: MS_FONT_MONO, color: MS_INK_3, fontSize: 12 }}>
            cycle target 95 min · actual 88 min
          </span>
        }
      />

      {/* arrival + station progress */}
      <div style={{
        padding: "10px 14px", background: MS_BG_3, borderBottom: "1px solid " + MS_LINE,
        display: "flex", alignItems: "center", gap: 14,
      }}>
        <div style={{
          padding: "6px 12px",
          border: "1px solid " + MS_ACCENT, borderRadius: 4,
          background: "color-mix(in oklch, " + MS_ACCENT + " 8%, " + MS_BG + ")",
        }}>
          <_msf_label>UNIT ARRIVED FROM SUBASSY</_msf_label>
          <div style={{ fontFamily: MS_FONT_MONO, fontSize: 14, color: MS_INK, letterSpacing: "0.04em" }}>{serial}</div>
        </div>
        <div style={{ flex: 1, display: "flex", gap: 14 }}>
          {["RECV", "MACH", "SUBASSY", "FAI"].map(function(label, i) {
            const done = i < 3, active = i === 3 && !accepted, closed = i === 3 && accepted;
            const tone = closed || done ? MS_OK : active ? MS_ACCENT : MS_INK_4;
            return (
              <div key={label} style={{ display: "flex", flexDirection: "column", alignItems: "center", gap: 4 }}>
                <div style={{ width: 22, height: 22, borderRadius: "50%",
                  background: done || closed ? MS_OK : active ? MS_ACCENT : MS_BG_2,
                  border: "1px solid " + tone,
                  boxShadow: active ? "0 0 0 4px color-mix(in oklch, " + MS_ACCENT + " 18%, transparent)" : "none" }} />
                <span style={{ fontFamily: MS_FONT_MONO, fontSize: 12, color: active ? MS_INK : MS_INK_4, letterSpacing: "0.04em" }}>{label}</span>
              </div>
            );
          })}
        </div>
        <div style={{ display: "flex", gap: 8, alignItems: "center" }}>
          <span style={{
            padding: "3px 8px", borderRadius: 3,
            border: "1px solid " + MS_LINE, background: MS_BG,
            fontFamily: MS_FONT_MONO, fontSize: 12, color: MS_INK_3,
          }}>traveler TRV-MS-0244</span>
          <_msf_btn variant="ghost" title="Reference: Test instructions TI-MTL-220-D-04">TI-MTL-220-D-04 ↗</_msf_btn>
        </div>
      </div>

      {/* main grid */}
      <div style={{ flex: 1, display: "grid", gridTemplateColumns: "1.2fr 1fr", minHeight: 0, overflow: "auto" }}>

        <_MSFTestResultsTable tests={tests} />

        {/* ── RIGHT: ballbar · vibration · witness · PDF · advance ─────── */}
        <div style={{ padding: 16, display: "flex", flexDirection: "column", minHeight: 0, gap: 14 }}>

          {/* Ballbar */}
          <div>
            <_msf_label>BALLBAR · ISO 230-4 · XY @ 4 m/min</_msf_label>
            <div style={{ marginTop: 6 }}>
              <_MSFBallbar />
            </div>
          </div>

          {/* Vibration */}
          <div>
            <_msf_label>CONTOURING VIBRATION · ISO 230-8 · 12K RPM</_msf_label>
            <div style={{ marginTop: 6 }}>
              <_MSFVibrationTrace />
            </div>
          </div>

          {/* Operating point readout (mirrors pump duty card) */}
          <div style={{ padding: 10, border: "1px solid " + MS_LINE, borderRadius: 3, background: MS_BG_3 }}>
            <_msf_label>FAI HEADLINE · MTL-220 REV D · S/N 0095</_msf_label>
            <div style={{ marginTop: 6, display: "grid", gridTemplateColumns: "repeat(4, 1fr)", gap: 12, fontSize: 12 }}>
              <div><_msf_label>circularity</_msf_label><span style={{ fontFamily: MS_FONT_MONO, color: MS_OK }}>2.6 µm</span></div>
              <div><_msf_label>squareness max</_msf_label><span style={{ fontFamily: MS_FONT_MONO, color: MS_OK }}>3.1 µm/m</span></div>
              <div><_msf_label>vib peak</_msf_label><span style={{ fontFamily: MS_FONT_MONO, color: MS_OK }}>0.61 mm/s</span></div>
              <div><_msf_label>granite flat</_msf_label><span style={{ fontFamily: MS_FONT_MONO, color: MS_OK }}>±2.4 µm</span></div>
            </div>
          </div>

          <_MSFWitnessPanel witnessName={witnessName} setWitness={setWitness} witnessPresent={witnessPresent} witnessTs={witnessTs} accepted={accepted} onCaptureWitness={onCaptureWitness} />

          {/* FAI report PDF generation */}
          <div style={_MSF_PDF_ROW_STYLE}>
            <div style={{ minWidth: 0 }}>
              <div style={{ fontFamily: MS_FONT_MONO, fontSize: 12, color: MS_INK }}>FAI-MTL-220-D-S0095-2026-08-14.pdf</div>
              <div style={{ fontSize: 12, color: MS_INK_3, marginTop: 4 }}>
                AS9102 form set · IATF 16949 PPAP Lvl 3 · 9-test ISO 230-2 dimensional report · ballbar trace · vibration log · witness page · operator signature.
              </div>
            </div>
            <_msf_btn variant="primary" onClick={onGeneratePdf} disabled={pdfGenerated || !allPass || accepted}>
              {pdfGenerated ? "PDF generated ✓" : "Generate FAI PDF"}
            </_msf_btn>
          </div>

          <_MSFAcceptanceGate canAdvance={canAdvance} accepted={accepted} allPass={allPass} pdfGenerated={pdfGenerated} witnessPresent={witnessPresent} onAdvanceAcceptance={onAdvanceAcceptance} />

          {/* Notes */}
          <div style={{ marginTop: "auto", paddingTop: 6, fontSize: 12, color: MS_INK_4, lineHeight: 1.5 }}>
            <_msf_label>NOTES</_msf_label>
            Re-test policy: any single ISO 230-2 item failure permits one re-run within
            30 min. Two failures route to NCR-FAI-quarantine and re-open ECO-MS-0017
            CAPA. Vibration ship-hold threshold is 1.0 mm/s RMS. CMM dimensional
            log archived as DMIS file alongside the PDF.
          </div>
        </div>
      </div>

      {/* Toast */}
      {toast && (
        <div style={_MSF_TOAST_STYLE}>{toast}</div>
      )}
    </div>
  );
}

/* Small gate-row pill used inside the acceptance panel. */
function _MSFGate({ label, ok }) {
  const tone = ok ? MS_OK : MS_INK_4;
  return (
    <div style={{
      display: "flex", alignItems: "center", gap: 8,
      padding: "8px 10px",
      border: "1px solid " + (ok ? MS_OK : MS_LINE),
      borderRadius: 3,
      background: ok ? "color-mix(in oklch, " + MS_OK + " 7%, transparent)" : MS_BG,
    }}>
      <span style={{
        width: 9, height: 9, borderRadius: "50%",
        background: tone,
        boxShadow: "0 0 0 3px color-mix(in oklch, " + tone + " 16%, transparent)",
      }} />
      <span style={{ fontFamily: MS_FONT_MONO, fontSize: 12, color: ok ? MS_INK : MS_INK_3 }}>{label}</span>
    </div>
  );
}

/* Route registration — guarded against agent #3's registry. Order-independent:
   exposes window.ScreenMittelstandFAI either way. */
if (typeof window !== "undefined") window.ScreenMittelstandFAI = ScreenMittelstandFAI;
if (typeof registerMittelstandRoute === "function") {
  registerMittelstandRoute({
    path: "/traveler/test",
    mode: "traveler",
    title: "FAI + acceptance",
    renderer: function() { return React.createElement(ScreenMittelstandFAI); },
  });
}
})();
