/* FORGE — Act-3 pump-tenant screens (S15..S20).
   Babel-standalone in-browser React. NO ES imports / exports. Globals:
     React, getActiveTenant, useActiveTenant, navigate, registerPumpRoute,
     Icons, and primitives from ui.jsx (Pill, Btn, Panel, StatPill, Bar, Progress).
   Aesthetic: paper-deck, mono labels, oklch ink ramp.
   Anonymisation: synthetic supplier names only (Athena/Spire/Kestrel/Elara/
     Indus/Vega/Halcyon). NEVER use real Indian-pump-industry names. */

const { useState: uSA3, useMemo: uMA3, useEffect: uEA3 } = React;

// ───────────────────────────────────────────────────────────── ink atoms
const A3 = {
  BG:        "oklch(0.985 0.004 85)",
  BG_2:      "oklch(0.93 0.005 85)",
  BG_3:      "oklch(0.965 0.005 85)",
  INK:       "oklch(0.16 0.01 85)",
  INK_2:     "oklch(0.30 0.01 85)",
  INK_3:     "oklch(0.46 0.01 85)",
  INK_4:     "oklch(0.60 0.01 85)",
  LINE:      "oklch(0.84 0.006 85)",
  LINE_SOFT: "oklch(0.90 0.005 85)",
  OK:        "oklch(0.62 0.13 150)",
  WARN:      "oklch(0.72 0.14 75)",
  BAD:       "oklch(0.58 0.20 28)",
  COOL:      "oklch(0.58 0.13 240)",
  ACCENT:    "oklch(0.55 0.18 28)",
  FONT_UI:   "var(--font-ui)",
  FONT_MONO: "var(--font-mono)",
  FONT_SER:  "var(--font-serif)",
};

function a3MonoSmall(extra) {
  return Object.assign({
    fontFamily: A3.FONT_MONO,
    fontSize: 12,
    letterSpacing: "0.08em",
    textTransform: "uppercase",
    color: A3.INK_3,
  }, extra || {});
}

function a3Card(extra) {
  return Object.assign({
    background: A3.BG_3,
    border: "1px solid " + A3.LINE,
    borderRadius: 4,
    padding: 12,
  }, extra || {});
}

function a3ScoreColor(pct) {
  if (pct >= 90) return A3.OK;
  if (pct >= 80) return A3.WARN;
  return A3.BAD;
}

function a3StatusTone(status) {
  const s = String(status || "").toLowerCase();
  if (s === "approved" || s === "ready" || s === "ok") return A3.OK;
  if (s === "conditional" || s === "in-prep" || s === "partial" || s === "in-progress") return A3.WARN;
  if (s === "blocked" || s === "fail" || s === "rejected") return A3.BAD;
  return A3.INK_3;
}

/* Extracted styles (react-doctor: no-inline-exhaustive-style). */
function _a3BadgeStyle(c) {
  return {
    display: "inline-flex", alignItems: "center", gap: 5, height: 20,
    padding: "0 8px", borderRadius: 999,
    fontFamily: A3.FONT_MONO, fontSize: 12, fontWeight: 600, letterSpacing: "0.08em",
    textTransform: "uppercase",
    border: "1px solid " + c, color: c, background: A3.BG_3,
  };
}
function _a3PillBtnStyle(active, activeBg, activeBorder, activeFg) {
  return {
    padding: "4px 10px", borderRadius: 999,
    border: "1px solid " + (active ? activeBorder : A3.LINE),
    background: active ? activeBg : A3.BG_3,
    color: active ? activeFg : A3.INK_2,
    fontFamily: A3.FONT_MONO, fontSize: 12, textTransform: "uppercase",
    letterSpacing: "0.06em", cursor: "pointer",
  };
}
const _A3_INK_BTN_STYLE = {
  background: A3.INK, color: A3.BG, padding: "8px 14px",
  borderRadius: 4, border: 0, fontFamily: A3.FONT_MONO, fontSize: 12,
  letterSpacing: "0.05em", textTransform: "uppercase", cursor: "pointer",
};
const _A3_BG3_BTN_STYLE = {
  background: A3.BG_3, color: A3.INK_2, padding: "6px 12px", borderRadius: 4,
  border: "1px solid " + A3.LINE, fontFamily: A3.FONT_MONO, fontSize: 12,
  letterSpacing: "0.05em", textTransform: "uppercase", cursor: "pointer",
};
const _A3_ACCENT_BTN_STYLE = {
  width: "100%", padding: "8px 12px", borderRadius: 4,
  background: A3.ACCENT, color: A3.BG, border: 0,
  fontFamily: A3.FONT_MONO, fontSize: 12, letterSpacing: "0.05em",
  textTransform: "uppercase", cursor: "pointer",
};
const _A3_FLASH_STYLE = {
  position: "fixed", bottom: 24, right: 28,
  background: A3.INK, color: A3.BG, padding: "12px 16px", borderRadius: 4,
  fontFamily: A3.FONT_MONO, fontSize: 12, letterSpacing: "0.05em",
  boxShadow: "0 6px 20px rgba(0,0,0,0.15)", maxWidth: 360,
};
function _a3VendorRowStyle(isLast) {
  return {
    display: "grid",
    gridTemplateColumns: "60px 1fr 220px 200px 80px",
    gap: 12, padding: "10px 6px",
    borderBottom: !isLast ? "1px solid " + A3.LINE_SOFT : "0",
    alignItems: "center",
  };
}
function _a3VendorScoreBtnStyle(sel, color) {
  return {
    flex: 1, padding: "6px 0",
    border: "1px solid " + (sel ? color : A3.LINE),
    background: sel ? color : A3.BG_3,
    color: sel ? A3.BG : A3.INK_3,
    fontFamily: A3.FONT_MONO, fontSize: 12, fontWeight: 600,
    cursor: "pointer", borderRadius: 2,
  };
}
const _A3_VENDOR_FOOTER_STYLE = {
  position: "sticky", bottom: 0, marginTop: 0,
  background: A3.BG, borderTop: "2px solid " + A3.INK,
  padding: "14px 18px", display: "flex",
  justifyContent: "space-between", alignItems: "center",
};
function _a3TabScoreStyle(ts) {
  return {
    fontFamily: A3.FONT_MONO, fontSize: 18, fontWeight: 600, fontVariantNumeric: "tabular-nums",
    color: ts == null ? A3.INK_4 : a3ScoreColor(ts),
  };
}
function _a3OverallScoreStyle(overall) {
  return {
    fontFamily: A3.FONT_MONO, fontSize: 22, fontWeight: 600, fontVariantNumeric: "tabular-nums",
    color: overall == null ? A3.INK_4 : a3ScoreColor(overall),
  };
}
const _a3VendorCancelStyle = {
  padding: "10px 16px", border: "1px solid " + A3.LINE, background: A3.BG_3, color: A3.INK_2,
  borderRadius: 4, fontFamily: A3.FONT_MONO, fontSize: 12, textTransform: "uppercase", cursor: "pointer",
};
function _a3VendorSubmitStyle(overall) {
  return {
    padding: "10px 18px", border: 0,
    background: overall == null ? A3.INK_4 : A3.INK,
    color: A3.BG, borderRadius: 4,
    fontFamily: A3.FONT_MONO, fontSize: 12, textTransform: "uppercase", letterSpacing: "0.05em",
    cursor: overall == null ? "not-allowed" : "pointer",
  };
}
function _a3HeroPlanRowStyle(isLast) {
  return {
    display: "grid", gridTemplateColumns: "44px 1fr 90px 70px 90px",
    gap: 8, padding: "6px 0",
    borderBottom: !isLast ? "1px solid " + A3.LINE_SOFT : "0",
    alignItems: "center", fontSize: 12,
  };
}
const _A3_ECO_BTN_STYLE = {
  width: "100%", padding: "8px 10px", border: "1px solid " + A3.ACCENT,
  background: A3.BG_3, color: A3.ACCENT, borderRadius: 4,
  fontFamily: A3.FONT_MONO, fontSize: 12, letterSpacing: "0.05em",
  textTransform: "uppercase", cursor: "pointer",
};
function _a3SeriesBtnStyle(passed) {
  return {
    width: "100%", padding: "10px 12px", border: 0,
    background: passed >= 4 ? A3.OK : A3.INK_4,
    color: A3.BG, borderRadius: 4,
    fontFamily: A3.FONT_MONO, fontSize: 12, letterSpacing: "0.05em",
    textTransform: "uppercase",
    cursor: passed >= 4 ? "pointer" : "not-allowed",
    opacity: passed >= 4 ? 1 : 0.65,
  };
}
function _a3PfmeaRowStyle(colTpl, sel, isLast) {
  return {
    display: "grid", gridTemplateColumns: colTpl, gap: 8,
    padding: "10px 12px",
    borderBottom: !isLast ? "1px solid " + A3.LINE_SOFT : "0",
    alignItems: "center",
    background: sel ? A3.BG_2 : "transparent",
    cursor: "pointer",
  };
}
function _a3PfmeaHeaderStyle(colTpl) {
  return {
    display: "grid", gridTemplateColumns: colTpl,
    padding: "10px 12px", background: A3.BG_2,
    borderBottom: "1px solid " + A3.LINE,
    fontSize: 12, textTransform: "uppercase",
    fontFamily: A3.FONT_MONO, letterSpacing: "0.06em",
    gap: 8,
  };
}
function _a3RpnBadgeStyle(rpn, rpnColor) {
  return {
    fontFamily: A3.FONT_MONO, fontSize: 13, fontWeight: 600,
    textAlign: "center", fontVariantNumeric: "tabular-nums",
    color: rpnColor(rpn),
    background: rpn >= 100 ? "color-mix(in oklch, " + A3.BAD + " 14%, transparent)" :
               rpn >= 50 ? "color-mix(in oklch, " + A3.WARN + " 14%, transparent)" :
               "color-mix(in oklch, " + A3.OK + " 14%, transparent)",
    borderRadius: 3,
    padding: "3px 6px",
  };
}
const _A3_PFMEA_MODAL_BACKDROP = {
  position: "fixed", inset: 0,
  background: "rgba(50,40,30,0.45)",
  display: "flex", alignItems: "center", justifyContent: "center",
  zIndex: 50,
};
const _A3_PFMEA_MODAL_PANEL = {
  background: A3.BG, border: "1px solid " + A3.LINE,
  borderRadius: 4, padding: 22, width: 540, boxShadow: "0 20px 60px rgba(50,40,30,0.25)",
};
const _A3_DIALOG_CANCEL_STYLE = {
  padding: "8px 14px", border: "1px solid " + A3.LINE, background: A3.BG_3, color: A3.INK_2,
  borderRadius: 4, fontFamily: A3.FONT_MONO, fontSize: 12, textTransform: "uppercase", cursor: "pointer",
};
const _A3_DIALOG_SUBMIT_STYLE = {
  padding: "8px 18px", border: 0, background: A3.INK, color: A3.BG,
  borderRadius: 4, fontFamily: A3.FONT_MONO, fontSize: 12, textTransform: "uppercase",
  letterSpacing: "0.05em", cursor: "pointer",
};
const _A3_STEP_FILE_STYLE = {
  display: "flex", alignItems: "center", gap: 8,
  padding: "8px 10px", border: "1px dashed " + A3.LINE,
  borderRadius: 3, background: A3.BG_3, cursor: "pointer",
};
const _A3_DROP_STYLE = {
  border: "1px dashed " + A3.LINE, borderRadius: 3,
  padding: "8px 0", textAlign: "center",
  fontFamily: A3.FONT_MONO, fontSize: 12, color: A3.INK_4,
  cursor: "default",
};
const _A3_HEADER_GHOST_BTN_STYLE = {
  padding: "8px 14px", borderRadius: 4,
  border: "1px solid " + A3.LINE, background: A3.BG_3,
  fontFamily: A3.FONT_MONO, fontSize: 12, textTransform: "uppercase",
  color: A3.INK_2, cursor: "pointer",
};
const _A3_HEADER_INK_BTN_STYLE = {
  padding: "8px 14px", borderRadius: 4, border: 0,
  background: A3.INK, color: A3.BG,
  fontFamily: A3.FONT_MONO, fontSize: 12, textTransform: "uppercase",
  letterSpacing: "0.05em", cursor: "pointer",
};
function _a3PromoteBtnStyle(passed) {
  return {
    width: "100%", padding: "10px 12px", border: 0,
    background: passed ? A3.OK : A3.INK_4,
    color: A3.BG, borderRadius: 4,
    fontFamily: A3.FONT_MONO, fontSize: 12, letterSpacing: "0.05em",
    textTransform: "uppercase",
    cursor: passed ? "pointer" : "not-allowed",
    opacity: passed ? 1 : 0.65,
  };
}
const _A3_SMALL_BTN_STYLE = {
  padding: "5px 10px", borderRadius: 4,
  border: "1px solid " + A3.LINE, background: A3.BG_3,
  fontFamily: A3.FONT_MONO, fontSize: 12, textTransform: "uppercase",
  color: A3.INK_2, cursor: "pointer",
};
function _a3SignOffDot(s) {
  return {
    width: 24, height: 24, borderRadius: 999,
    border: "2px solid " + s.color,
    background: s.status === "signed" ? s.color : "transparent",
    display: "flex", alignItems: "center", justifyContent: "center",
    color: A3.BG, fontFamily: A3.FONT_MONO, fontSize: 12, fontWeight: 600,
  };
}
function _a3TabBtnStyle(active) {
  return {
    padding: "10px 16px", marginRight: 4, border: 0,
    borderBottom: "2px solid " + (active ? A3.INK : "transparent"),
    background: "transparent",
    color: active ? A3.INK : A3.INK_3,
    fontFamily: A3.FONT_MONO, fontSize: 12, letterSpacing: "0.05em",
    textTransform: "uppercase", cursor: "pointer",
  };
}
function _a3StationChipStyle(color) {
  return {
    padding: "4px 10px", borderRadius: 999,
    border: "1px solid " + color, background: A3.BG_3,
    color: color, fontFamily: A3.FONT_MONO, fontSize: 12,
    cursor: "pointer", textTransform: "uppercase",
  };
}

function a3Badge(label, tone) {
  const c = tone || A3.INK_3;
  return (
    <span style={_a3BadgeStyle(c)}>
      <span style={{ width: 5, height: 5, borderRadius: 999, background: c }} />
      {label}
    </span>
  );
}

// deterministic hash → score (stable per supplier name)
function a3Hash(s) {
  let h = 2166136261;
  for (let i = 0; i < s.length; i++) {
    h ^= s.charCodeAt(i);
    h = (h * 16777619) >>> 0;
  }
  return h;
}

// Supplier coords on the rough India outline (viewBox 0..400 / 0..480).
// Approximations only — for sketch-map flair.
const A3_SUPPLIER_COORDS = {
  "SUP-01": { x: 110, y: 230, city: "Rajkot" },
  "SUP-02": { x: 175, y: 295, city: "Kolhapur" },
  "SUP-03": { x: 130, y: 240, city: "Surat" },
  "SUP-04": { x: 180, y: 270, city: "Pune" },
  "SUP-05": { x: 105, y: 265, city: "Bhavnagar" },
  "SUP-06": { x: 195, y: 360, city: "Coimbatore" },
  "SUP-07": { x: 195, y: 280, city: "Aurangabad" },
};

// rough India outline polygon (sketch only)
const A3_INDIA_OUTLINE =
  "M150,40 L210,55 L255,80 L300,140 L320,210 L320,260 L290,300 " +
  "L255,355 L220,400 L195,440 L170,425 L155,380 L130,335 L105,290 " +
  "L85,245 L65,205 L60,160 L75,115 L100,75 L125,55 Z";

// ──────────────────────────────────────────────────────── S15: SuppliersList
function ScreenSupplierList() {
  const tenant = useActiveTenant();
  const suppliers = (tenant && tenant.suppliers) || [];

  const [statusFilter, setStatusFilter] = uSA3("all");
  const [catFilter, setCatFilter] = uSA3("all");
  const [maxLead, setMaxLead] = uSA3(60);
  const [hovered, setHovered] = uSA3(null);

  // reset local UI state when tenant switches
  uEA3(function () {
    if (typeof window === "undefined") return;
    function onTenantChange() {
      setStatusFilter("all");
      setCatFilter("all");
      setMaxLead(60);
      setHovered(null);
    }
    window.addEventListener("forge:tenant-change", onTenantChange);
    return function () { window.removeEventListener("forge:tenant-change", onTenantChange); };
  }, []);

  const categories = uMA3(function () {
    const cats = {};
    suppliers.forEach(function (s) { cats[s.category] = true; });
    return Object.keys(cats);
  }, [suppliers]);

  const filtered = suppliers.filter(function (s) {
    if (statusFilter !== "all" && s.status !== statusFilter) return false;
    if (catFilter !== "all" && s.category !== catFilter) return false;
    if (s.lead_time_days > maxLead) return false;
    return true;
  });

  function openAudit(supplier) {
    if (typeof window !== "undefined") {
      window.__a3AuditSupplierId = supplier.id;
    }
    if (typeof navigate === "function") navigate("/forge/audit");
  }

  const root = {
    background: A3.BG, color: A3.INK, minHeight: "100%",
    fontFamily: A3.FONT_UI, fontSize: 13, padding: "20px 28px 60px",
  };

  return (
    <div style={root}>
      {/* header */}
      <div style={{ display: "flex", alignItems: "baseline", justifyContent: "space-between", marginBottom: 14 }}>
        <div>
          <div style={a3MonoSmall({ marginBottom: 4 })}>forge:// suppliers</div>
          <div style={{ fontFamily: A3.FONT_SER, fontSize: 26, letterSpacing: "-0.01em" }}>
            Supplier panel
          </div>
          <div style={{ color: A3.INK_3, fontSize: 12, marginTop: 4 }}>
            {suppliers.length} qualified · {filtered.length} shown
          </div>
        </div>
        <button
          onClick={function () { if (typeof navigate === "function") navigate("/forge/vendor-onboard"); }}
          style={_A3_INK_BTN_STYLE}>
          + Qualify new supplier
        </button>
      </div>

      {/* filter bar */}
      <div style={Object.assign(a3Card({ marginBottom: 16 }), { display: "flex", gap: 16, alignItems: "center", flexWrap: "wrap" })}>
        <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
          <span style={a3MonoSmall()}>Status</span>
          {["all", "approved", "conditional", "blocked"].map(function (v) {
            const active = statusFilter === v;
            return (
              <button key={v}
                onClick={function () { setStatusFilter(v); }}
                style={_a3PillBtnStyle(active, A3.INK, A3.INK, A3.BG)}>{v}</button>
            );
          })}
        </div>
        <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
          <span style={a3MonoSmall()}>Category</span>
          <select value={catFilter} onChange={function (e) { setCatFilter(e.target.value); }}
            id="suppliers-category-filter" name="suppliers-category-filter"
            aria-label="Filter by category"
            style={{
              padding: "4px 8px", border: "1px solid " + A3.LINE,
              background: A3.BG_3, fontFamily: A3.FONT_MONO, fontSize: 12,
            }}>
            <option value="all">all</option>
            {categories.map(function (c) { return <option key={c} value={c}>{c}</option>; })}
          </select>
        </div>
        <div style={{ display: "flex", alignItems: "center", gap: 8, minWidth: 240 }}>
          <span style={a3MonoSmall()}>Lead-time ≤</span>
          <input type="range" min="7" max="60" value={maxLead}
            id="suppliers-max-lead" name="suppliers-max-lead"
            aria-label="Maximum lead time (days)"
            onChange={function (e) { setMaxLead(parseInt(e.target.value, 10)); }}
            style={{ flex: 1 }} />
          <span style={{ fontFamily: A3.FONT_MONO, fontSize: 12, color: A3.INK_2, minWidth: 50 }}>{maxLead}d</span>
        </div>
      </div>

      {/* main grid: cards + map + rail */}
      <div style={{ display: "grid", gridTemplateColumns: "1fr 280px", gap: 18 }}>
        {/* left: cards then map */}
        <div>
          <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fill, minmax(260px, 1fr))", gap: 12 }}>
            {filtered.map(function (s) {
              return (
                <div key={s.id}
                  role="button"
                  tabIndex={0}
                  onClick={function () { openAudit(s); }}
                  onKeyDown={function (e) { if (e.key === "Enter" || e.key === " ") { e.preventDefault(); openAudit(s); } }}
                  style={Object.assign(a3Card({ cursor: "pointer", transition: "transform .12s, box-shadow .12s" }), {
                    boxShadow: hovered === s.id ? "0 4px 14px rgba(0,0,0,0.06)" : "none",
                    transform: hovered === s.id ? "translateY(-1px)" : "translateY(0)",
                  })}
                  onMouseEnter={function () { setHovered(s.id); }}
                  onMouseLeave={function () { setHovered(null); }}>
                  <div style={{ display: "flex", justifyContent: "space-between", alignItems: "flex-start", marginBottom: 8 }}>
                    <div>
                      <div style={a3MonoSmall({ marginBottom: 3 })}>{s.id}</div>
                      <div style={{ fontWeight: 600, fontSize: 14 }}>{s.name}</div>
                    </div>
                    {a3Badge(s.status, a3StatusTone(s.status))}
                  </div>
                  <div style={{ fontSize: 12, color: A3.INK_3, marginBottom: 6, minHeight: 32 }}>{s.category}</div>
                  <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginTop: 10 }}>
                    <div>
                      <div style={a3MonoSmall()}>Location</div>
                      <div style={{ fontSize: 12 }}>{s.location}</div>
                    </div>
                    <div>
                      <div style={a3MonoSmall()}>Lead-time</div>
                      <div style={{ fontSize: 12, fontFamily: A3.FONT_MONO }}>{s.lead_time_days}d</div>
                    </div>
                  </div>
                  <div style={{ marginTop: 12, paddingTop: 10, borderTop: "1px solid " + A3.LINE_SOFT, display: "flex", alignItems: "center", justifyContent: "space-between" }}>
                    <div>
                      <div style={a3MonoSmall()}>Audit score</div>
                      <div style={{
                        fontFamily: A3.FONT_MONO, fontSize: 18,
                        color: a3ScoreColor(s.audit_score_pct),
                        fontWeight: 600, fontVariantNumeric: "tabular-nums",
                      }}>{s.audit_score_pct}%</div>
                    </div>
                    <div style={{ width: 110, height: 6, background: A3.BG_2, borderRadius: 3, overflow: "hidden" }}>
                      <div style={{
                        width: s.audit_score_pct + "%",
                        height: "100%",
                        background: a3ScoreColor(s.audit_score_pct),
                      }} />
                    </div>
                  </div>
                  <div style={{ marginTop: 8, fontSize: 12, color: A3.INK_3, fontFamily: A3.FONT_MONO }}>
                    last audit · {s.last_audit}
                  </div>
                  {s.note ? (
                    <div style={{ marginTop: 6, fontSize: 12, color: A3.BAD }}>⚠ {s.note}</div>
                  ) : null}
                </div>
              );
            })}
            {filtered.length === 0 ? (
              <div style={Object.assign(a3Card(), { gridColumn: "1 / -1", textAlign: "center", color: A3.INK_3 })}>
                No suppliers match the current filter.
              </div>
            ) : null}
          </div>

          <_SupplierListMap filtered={filtered} suppliers={suppliers} hovered={hovered} setHovered={setHovered} openAudit={openAudit} />
        </div>

        <_SupplierListRail suppliers={suppliers} />
      </div>
    </div>
  );
}

// ───────────────────────────────────────────────────── S15 helpers
function _SupplierListMap({ filtered, suppliers, hovered, setHovered, openAudit }) {
  return (
    <div style={Object.assign(a3Card({ marginTop: 18 }), { padding: 0, overflow: "hidden" })}>
      <div style={{ padding: "10px 14px", borderBottom: "1px solid " + A3.LINE_SOFT, display: "flex", justifyContent: "space-between", alignItems: "center" }}>
        <span style={a3MonoSmall()}>Geographic view · India</span>
        <span style={{ fontSize: 12, color: A3.INK_3, fontFamily: A3.FONT_MONO }}>hover dot for detail</span>
      </div>
      <div style={{ position: "relative", padding: 16 }}>
        <svg viewBox="0 0 400 480" width="100%" height="420" style={{ display: "block" }}>
          <defs>
            <pattern id="a3hatch" width="6" height="6" patternUnits="userSpaceOnUse" patternTransform="rotate(45)">
              <line x1="0" y1="0" x2="0" y2="6" stroke={A3.LINE_SOFT} strokeWidth="1" />
            </pattern>
          </defs>
          <path d={A3_INDIA_OUTLINE} fill="url(#a3hatch)" stroke={A3.INK_3} strokeWidth="1.4" strokeLinejoin="round" />
          <line x1="50" y1="430" x2="120" y2="430" stroke={A3.INK_4} strokeWidth="0.8" />
          <text x="50" y="448" fontFamily={A3.FONT_MONO} fontSize="9" fill={A3.INK_3}>~700km</text>
          {filtered.map(function (s) {
            const c = A3_SUPPLIER_COORDS[s.id];
            if (!c) return null;
            const tone = a3StatusTone(s.status);
            return (
              <g key={s.id}
                 onMouseEnter={function () { setHovered(s.id); }}
                 onMouseLeave={function () { setHovered(null); }}
                 onClick={function () { openAudit(s); }}
                 style={{ cursor: "pointer" }}>
                <circle cx={c.x} cy={c.y} r={hovered === s.id ? 9 : 6}
                        fill={tone} stroke={A3.BG} strokeWidth="2" />
                <text x={c.x + 12} y={c.y + 3} fontFamily={A3.FONT_MONO} fontSize="9" fill={A3.INK_2}>
                  {c.city}
                </text>
              </g>
            );
          })}
          {hovered ? (function () {
            const s = suppliers.find(function (x) { return x.id === hovered; });
            const c = s && A3_SUPPLIER_COORDS[s.id];
            if (!s || !c) return null;
            return (
              <g>
                <rect x={c.x + 18} y={c.y - 30} width="170" height="42" fill={A3.INK} rx="3" />
                <text x={c.x + 26} y={c.y - 14} fontFamily={A3.FONT_MONO} fontSize="10" fill={A3.BG}>
                  {s.name}
                </text>
                <text x={c.x + 26} y={c.y - 1} fontFamily={A3.FONT_MONO} fontSize="9" fill={A3.BG_2}>
                  {s.lead_time_days}d lead · {s.audit_score_pct}%
                </text>
              </g>
            );
          })() : null}
        </svg>
        <div style={{ display: "flex", gap: 14, justifyContent: "center", marginTop: 6, fontFamily: A3.FONT_MONO, fontSize: 12 }}>
          <span><span style={{ display: "inline-block", width: 8, height: 8, background: A3.OK, borderRadius: 999, marginRight: 5 }} />approved</span>
          <span><span style={{ display: "inline-block", width: 8, height: 8, background: A3.WARN, borderRadius: 999, marginRight: 5 }} />conditional</span>
          <span><span style={{ display: "inline-block", width: 8, height: 8, background: A3.BAD, borderRadius: 999, marginRight: 5 }} />blocked</span>
        </div>
      </div>
    </div>
  );
}

function _SupplierListRail({ suppliers }) {
  return (
    <div>
      <div style={a3Card()}>
        <div style={a3MonoSmall({ marginBottom: 8 })}>Qualify new supplier</div>
        <div style={{ fontSize: 12, color: A3.INK_3, marginBottom: 10 }}>
          Run VQP 2.0 against any new vendor across Legal, QMS, EHS and Process. Conditional approval available with 60-day plan.
        </div>
        <button
          onClick={function () { if (typeof navigate === "function") navigate("/forge/vendor-onboard"); }}
          style={_A3_ACCENT_BTN_STYLE}>
          Start onboarding wizard →
        </button>
      </div>

      <div style={Object.assign(a3Card({ marginTop: 12 }), {})}>
        <div style={a3MonoSmall({ marginBottom: 8 })}>Risk concentrations</div>
        <div style={{ fontSize: 12 }}>
          <div style={{ display: "flex", justifyContent: "space-between", marginBottom: 4 }}>
            <span>Castings</span><span style={{ fontFamily: A3.FONT_MONO, color: A3.WARN }}>2 sources</span>
          </div>
          <div style={{ display: "flex", justifyContent: "space-between", marginBottom: 4 }}>
            <span>Stamping</span><span style={{ fontFamily: A3.FONT_MONO, color: A3.BAD }}>1 source</span>
          </div>
          <div style={{ display: "flex", justifyContent: "space-between", marginBottom: 4 }}>
            <span>Copper / cable</span><span style={{ fontFamily: A3.FONT_MONO, color: A3.BAD }}>1 source</span>
          </div>
          <div style={{ display: "flex", justifyContent: "space-between" }}>
            <span>SS shafts</span><span style={{ fontFamily: A3.FONT_MONO, color: A3.BAD }}>1 source</span>
          </div>
        </div>
      </div>

      <div style={Object.assign(a3Card({ marginTop: 12 }), {})}>
        <div style={a3MonoSmall({ marginBottom: 8 })}>Audits due (30d)</div>
        {suppliers.slice(0, 5).map(function (s, i) {
          const due = ["12d", "18d", "21d", "24d", "29d"][i] || "30d+";
          return (
            <div key={s.id} style={{ display: "flex", justifyContent: "space-between", padding: "5px 0", borderBottom: i < 4 ? "1px solid " + A3.LINE_SOFT : "0" }}>
              <span style={{ fontSize: 12 }}>{s.name}</span>
              <span style={{ fontFamily: A3.FONT_MONO, fontSize: 12, color: A3.INK_3 }}>{due}</span>
            </div>
          );
        })}
      </div>

      <div style={Object.assign(a3Card({ marginTop: 12 }), { background: A3.BG_2 })}>
        <div style={a3MonoSmall({ marginBottom: 6 })}>VQP 2.0 protocol</div>
        <div style={{ fontSize: 12, color: A3.INK_3, lineHeight: 1.5 }}>
          46 criteria across 4 axes. Legal must score 100% to advance from conditional to approved status. Score retained for 12 months.
        </div>
      </div>
    </div>
  );
}

// ───────────────────────────────────────────────────── S16: VendorOnboarding
function ScreenVendorOnboarding() {
  const tenant = useActiveTenant();
  const tmpl = tenant && tenant.vendor_audit_template;
  const auditCase = tenant && tenant.audit_case;

  const prefill = uMA3(function () {
    if (typeof window === "undefined") return false;
    const h = window.location.hash || "";
    return /prefill=helios/i.test(h) || /[?&]prefill=helios/i.test(h);
  }, []);

  const [activeTab, setActiveTab] = uSA3(0);
  const [scores, setScores] = uSA3(function () {
    const init = {};
    if (!tmpl) return init;
    tmpl.tabs.forEach(function (t) {
      t.criteria.forEach(function (c) {
        init[c.id] = -1;
      });
    });
    if (prefill && auditCase) {
      // Pre-fill from audit case findings: pass=3, partial=2, fail=1
      auditCase.tabs.forEach(function (t) {
        t.findings.forEach(function (f) {
          init[f.id] = (f.result === "pass") ? 3 : (f.result === "partial") ? 2 : (f.result === "fail") ? 1 : 0;
        });
      });
    }
    return init;
  });
  const [notes, setNotes] = uSA3({});
  const [vendorName, setVendorName] = uSA3(prefill ? "Helios AgriFlow Pvt Ltd" : "");
  const [flash, setFlash] = uSA3(null);
  const a3SubmitTimer = React.useRef(null);

  // cleanup pending navigation timer on unmount
  uEA3(function () {
    return function () {
      if (a3SubmitTimer.current) {
        clearTimeout(a3SubmitTimer.current);
        a3SubmitTimer.current = null;
      }
    };
  }, []);

  // reset local state on tenant switch
  uEA3(function () {
    if (typeof window === "undefined") return;
    function onTenantChange() {
      setActiveTab(0);
      setNotes({});
      setVendorName("");
      setFlash(null);
      setScores({});
    }
    window.addEventListener("forge:tenant-change", onTenantChange);
    return function () { window.removeEventListener("forge:tenant-change", onTenantChange); };
  }, []);

  if (!tmpl) {
    return (
      <div style={{ padding: 32, fontFamily: A3.FONT_UI, color: A3.INK_3 }}>
        Vendor audit template not loaded.
      </div>
    );
  }

  function setScore(id, v) {
    const next = Object.assign({}, scores);
    next[id] = v;
    setScores(next);
  }
  function setNote(id, v) {
    const next = Object.assign({}, notes);
    next[id] = v;
    setNotes(next);
  }

  // tab score: average of scored criteria / 3 * 100, blanks excluded
  function tabScore(tab) {
    let sum = 0, n = 0;
    tab.criteria.forEach(function (c) {
      const s = scores[c.id];
      if (typeof s === "number" && s >= 0) { sum += s; n++; }
    });
    if (n === 0) return null;
    return Math.round((sum / (n * 3)) * 100);
  }
  function overallScore() {
    let sum = 0, n = 0;
    tmpl.tabs.forEach(function (t) {
      t.criteria.forEach(function (c) {
        const s = scores[c.id];
        if (typeof s === "number" && s >= 0) { sum += s; n++; }
      });
    });
    if (n === 0) return null;
    return Math.round((sum / (n * 3)) * 100);
  }

  const overall = overallScore();
  const legalTab = tmpl.tabs[0];
  const legalScore = tabScore(legalTab);
  const legalGate = legalScore === 100;

  function onSubmit() {
    // W14B/W15C — persist scorecard via forgeApi.mutate before flash+nav. The
    // server's JSON-patch-lite uses positional paths (suppliers is an array of
    // {id,name,…}), so resolve the supplier index from tenant.suppliers by
    // matching id or slugified name. If found → `replace /<idx>/audit_scorecard`;
    // otherwise the wizard is onboarding a brand-new vendor → `add /-` a
    // synthesised supplier row carrying the scorecard. queuedOk fallback is
    // kept as a defensive guardrail in case the server schema regresses.
    const slug = (vendorName || "unnamed").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || "unnamed";
    const scorecard = {
      vendor_name: vendorName || "Unnamed vendor",
      overall_pct: overall || 0,
      legal_gate_cleared: !!legalGate,
      scores: scores, notes: notes,
      submitted_at: Date.now(),
    };
    const u = (typeof window !== "undefined") ? window.__forgeCurrentUser : null;
    const actor = (u && u.name) || "—";
    const suppliersArr = (tenant && tenant.suppliers) || [];
    const slugifyName = function (n) {
      return String(n || "").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
    };
    const idx = suppliersArr.findIndex(function (s) {
      return s && (s.id === slug || s.id === vendorName || slugifyName(s.name) === slug);
    });
    const patch = (idx >= 0)
      ? { op: "replace", path: "/" + idx + "/audit_scorecard", value: Object.assign({}, scorecard, { audited_by: actor }) }
      : { op: "add",     path: "/-",                          value: { id: slug, name: vendorName || "Unnamed vendor", status: "conditional", audit_scorecard: Object.assign({}, scorecard, { audited_by: actor }) } };
    const queuedOk = function (err) { return err && (err.status === 404 || err.status === 400); };
    if (window.forgeApi && typeof window.forgeApi.mutate === "function") {
      window.forgeApi.mutate("suppliers", patch).then(function () {
        setFlash("Audit saved · " + (vendorName || "Unnamed vendor") + " — " + (overall || 0) + "% overall " +
          (legalGate ? "(Legal gate cleared)" : "(Legal < 100%, conditional only)"));
      }).catch(function (err) {
        if (queuedOk(err)) {
          setFlash("Audit queued · " + (vendorName || "Unnamed vendor") + " — " + (overall || 0) + "% overall " +
            (legalGate ? "(Legal gate cleared)" : "(Legal < 100%, conditional only)"));
        } else {
          setFlash("Audit failed · " + (err && err.message || "unknown"));
        }
      });
    } else {
      setFlash("Audit saved · " + (vendorName || "Unnamed vendor") + " — " + (overall || 0) + "% overall " +
        (legalGate ? "(Legal gate cleared)" : "(Legal < 100%, conditional only)"));
    }
    if (a3SubmitTimer.current) clearTimeout(a3SubmitTimer.current);
    a3SubmitTimer.current = setTimeout(function () {
      a3SubmitTimer.current = null;
      if (typeof navigate === "function") navigate("/forge/suppliers");
    }, 1200);
  }

  const root = {
    background: A3.BG, color: A3.INK, minHeight: "100%",
    fontFamily: A3.FONT_UI, fontSize: 13, padding: "20px 28px 100px",
    position: "relative",
  };

  const tabBtnStyle = function (active) {
    return {
      flex: 1,
      padding: "10px 14px",
      background: active ? A3.BG : A3.BG_2,
      color: active ? A3.INK : A3.INK_3,
      borderTop: "1px solid " + A3.LINE,
      borderLeft: "1px solid " + A3.LINE,
      borderRight: "1px solid " + A3.LINE,
      borderBottom: "1px solid " + (active ? A3.BG : A3.LINE),
      borderRadius: "4px 4px 0 0",
      fontFamily: A3.FONT_MONO, fontSize: 12, letterSpacing: "0.05em",
      textTransform: "uppercase",
      cursor: "pointer",
      marginRight: 2,
    };
  };

  return (
    <div style={root}>
      {/* header */}
      <div style={{ display: "flex", alignItems: "baseline", justifyContent: "space-between", marginBottom: 14 }}>
        <div>
          <div style={a3MonoSmall({ marginBottom: 4 })}>forge:// vendor-onboard · {tmpl.name}</div>
          <div style={{ fontFamily: A3.FONT_SER, fontSize: 26, letterSpacing: "-0.01em" }}>
            Vendor onboarding wizard
          </div>
          <div style={{ color: A3.INK_3, fontSize: 12, marginTop: 4 }}>
            Score 0–3 on each criterion. Legal axis must be 100% to advance to approved status.
          </div>
        </div>
        <button
          onClick={function () { if (typeof navigate === "function") navigate("/forge/suppliers"); }}
          style={_A3_BG3_BTN_STYLE}>
          ← Back to suppliers
        </button>
      </div>

      {/* vendor identity */}
      <div style={Object.assign(a3Card({ marginBottom: 16 }), { display: "grid", gridTemplateColumns: "1fr 1fr 1fr 1fr", gap: 16 })}>
        <div>
          <div style={a3MonoSmall({ marginBottom: 4 })}>Vendor</div>
          <input value={vendorName} onChange={function (e) { setVendorName(e.target.value); }}
            placeholder="e.g. Helios AgriFlow Pvt Ltd"
            id="vendor-onboard-name" name="vendor-onboard-name"
            aria-label="Vendor name"
            style={{
              width: "100%", padding: "6px 8px", border: "1px solid " + A3.LINE,
              background: A3.BG, fontSize: 13, fontFamily: A3.FONT_UI,
            }} />
        </div>
        <div>
          <div style={a3MonoSmall({ marginBottom: 4 })}>Auditor</div>
          <div style={{ fontSize: 13, color: A3.INK_2 }}>{prefill ? "Priya I." : "Karan V."}</div>
        </div>
        <div>
          <div style={a3MonoSmall({ marginBottom: 4 })}>Date</div>
          <div style={{ fontSize: 13, fontFamily: A3.FONT_MONO, color: A3.INK_2 }}>2026-04-29</div>
        </div>
        <div>
          <div style={a3MonoSmall({ marginBottom: 4 })}>Protocol revision</div>
          <div style={{ fontSize: 13, fontFamily: A3.FONT_MONO, color: A3.INK_2 }}>{tmpl.rev}</div>
        </div>
      </div>

      {/* tabs */}
      <div style={{ display: "flex" }}>
        {tmpl.tabs.map(function (t, i) {
          const ts = tabScore(t);
          return (
            <button key={t.tab} onClick={function () { setActiveTab(i); }} style={tabBtnStyle(activeTab === i)}>
              {t.tab}
              <span style={{ marginLeft: 8, color: ts == null ? A3.INK_3 : a3ScoreColor(ts), fontWeight: 600 }}>
                {ts == null ? "—" : ts + "%"}
              </span>
              <span style={{ marginLeft: 6, color: A3.INK_3 }}>({t.criteria.length})</span>
            </button>
          );
        })}
      </div>

      <_VendorTabBody tab={tmpl.tabs[activeTab]} scores={scores} notes={notes} setScore={setScore} setNote={setNote} />

      <_VendorFooter tmpl={tmpl} tabScore={tabScore} overall={overall} legalScore={legalScore} legalGate={legalGate} onSubmit={onSubmit} />

      {flash ? (
        <div style={_A3_FLASH_STYLE}>
          {flash}
        </div>
      ) : null}
    </div>
  );
}

// ───────────────────────────────────────────────────── S16 helpers
function _VendorTabBody({ tab, scores, notes, setScore, setNote }) {
  return (
    <div style={{ background: A3.BG, border: "1px solid " + A3.LINE, borderTop: 0, borderRadius: "0 0 4px 4px", padding: 18, marginBottom: 20 }}>
      <div style={{ marginBottom: 12, color: A3.INK_3, fontSize: 12 }}>
        {tab.tab} · {tab.criteria.length} criteria.
        Score 0 = absent, 1 = partial, 2 = adequate, 3 = best-in-class.
      </div>
      <div>
        {tab.criteria.map(function (c, idx) {
          const cur = scores[c.id];
          return (
            <div key={c.id} style={_a3VendorRowStyle(idx >= tab.criteria.length - 1)}>
              <span style={{ fontFamily: A3.FONT_MONO, color: A3.INK_3, fontSize: 12 }}>{c.id}</span>
              <span style={{ fontSize: 13 }}>{c.text}</span>
              <div style={{ display: "flex", gap: 4 }}>
                {[0, 1, 2, 3].map(function (v) {
                  const sel = cur === v;
                  const palette = ["#b04444", "#c08538", "#7a8c4d", "#3f8a4f"];
                  return (
                    <button key={v} onClick={function () { setScore(c.id, v); }}
                      style={_a3VendorScoreBtnStyle(sel, palette[v])}>{v}</button>
                  );
                })}
              </div>
              <input value={notes[c.id] || ""} onChange={function (e) { setNote(c.id, e.target.value); }}
                placeholder="Note…"
                id={"vendor-note-" + c.id} name={"vendor-note-" + c.id}
                aria-label={"Note for " + c.text}
                style={{
                  padding: "6px 8px", border: "1px solid " + A3.LINE,
                  background: A3.BG, fontSize: 12, fontFamily: A3.FONT_UI,
                }} />
              <div tabIndex={-1} aria-hidden="true" style={_A3_DROP_STYLE}>drop file</div>
            </div>
          );
        })}
      </div>
    </div>
  );
}

function _VendorFooter({ tmpl, tabScore, overall, legalScore, legalGate, onSubmit }) {
  return (
    <div style={_A3_VENDOR_FOOTER_STYLE}>
      <div style={{ display: "flex", gap: 22 }}>
        {tmpl.tabs.map(function (t) {
          const ts = tabScore(t);
          return (
            <div key={t.tab}>
              <div style={a3MonoSmall()}>{t.tab.split(" ")[0]}</div>
              <div style={_a3TabScoreStyle(ts)}>{ts == null ? "—" : ts + "%"}</div>
            </div>
          );
        })}
        <div style={{ borderLeft: "1px solid " + A3.LINE, paddingLeft: 22 }}>
          <div style={a3MonoSmall()}>Overall</div>
          <div style={_a3OverallScoreStyle(overall)}>{overall == null ? "—" : overall + "%"}</div>
        </div>
        <div style={{ paddingLeft: 22, alignSelf: "center" }}>
          {legalScore == null ? a3Badge("legal-not-scored", A3.INK_3) :
            (legalGate ? a3Badge("legal gate · cleared", A3.OK) : a3Badge("legal gate · " + legalScore + "%", A3.BAD))}
        </div>
      </div>
      <div style={{ display: "flex", gap: 10 }}>
        <button onClick={function () { if (typeof navigate === "function") navigate("/forge/suppliers"); }}
          style={_a3VendorCancelStyle}>Cancel</button>
        <button onClick={onSubmit}
          disabled={overall == null}
          style={_a3VendorSubmitStyle(overall)}>Save audit →</button>
      </div>
    </div>
  );
}

// ───────────────────────────────────────────────────── S17: SupplierAuditDetail
function ScreenSupplierAuditDetail() {
  const tenant = useActiveTenant();
  const auditCase = tenant && tenant.audit_case;
  const tmpl = tenant && tenant.vendor_audit_template;
  const suppliers = (tenant && tenant.suppliers) || [];

  // ALL useState hooks must come before any conditional return (Rules of Hooks).
  const [activeTab, setActiveTab] = uSA3(0);

  // reset active tab when tenant switches
  uEA3(function () {
    if (typeof window === "undefined") return;
    function onTenantChange() { setActiveTab(0); }
    window.addEventListener("forge:tenant-change", onTenantChange);
    return function () { window.removeEventListener("forge:tenant-change", onTenantChange); };
  }, []);

  // figure out target supplier id
  const supplierId = uMA3(function () {
    if (typeof window === "undefined") return null;
    if (window.__a3AuditSupplierId) return window.__a3AuditSupplierId;
    const h = window.location.hash || "";
    const m = h.match(/\/forge\/audit\/?([^?#]+)?/);
    return (m && m[1]) || null;
  }, []);

  const isHelios = !supplierId || supplierId === "helios";
  const synthSupplier = !isHelios && suppliers.find(function (s) { return s.id === supplierId || s.name.toLowerCase().includes(String(supplierId).toLowerCase()); });

  if (!tmpl) {
    return (
      <div style={{ padding: 32, fontFamily: A3.FONT_UI, color: A3.INK_3 }}>
        Audit template not loaded.
      </div>
    );
  }

  // synthesize result for non-helios suppliers
  const synthCase = uMA3(function () {
    if (!synthSupplier) return null;
    const seedBase = a3Hash(synthSupplier.name);
    const rng = function (i) { return ((seedBase >> ((i % 16) * 2)) & 0xff) / 255; };
    let pass = 0, partial = 0, fail = 0, ix = 0;
    const tabs = tmpl.tabs.map(function (t, ti) {
      const findings = t.criteria.map(function (c) {
        const r = rng(ix++);
        let result;
        if (ti === 0 && synthSupplier.audit_score_pct >= 90) result = "pass";
        else if (r > 0.85) result = "fail";
        else if (r > 0.72) result = "partial";
        else result = "pass";
        if (result === "pass") pass++;
        else if (result === "partial") partial++;
        else fail++;
        return { id: c.id, result: result, note: result === "fail" ? "Gap noted" : (result === "partial" ? "Partial coverage" : "") };
      });
      const sc = Math.round(((findings.filter(function (f) { return f.result === "pass"; }).length +
                             findings.filter(function (f) { return f.result === "partial"; }).length * 0.5) /
                             findings.length) * 100);
      return { tab: t.tab, score_pct: sc, findings: findings };
    });
    return {
      supplier: synthSupplier.name,
      auditor: ["Karan V.", "Priya I.", "Devansh A."][seedBase % 3],
      score_pct: synthSupplier.audit_score_pct,
      status: synthSupplier.status,
      date: synthSupplier.last_audit,
      notes: "Synthesised from on-file audit dated " + synthSupplier.last_audit + ". Pass " + pass + " · partial " + partial + " · fail " + fail + ".",
      tabs: tabs,
      _synthetic: true,
    };
  }, [synthSupplier, tmpl]);

  const audit = isHelios ? auditCase : synthCase;

  if (!audit) {
    return (
      <div style={{ padding: 32, fontFamily: A3.FONT_UI, color: A3.INK_3 }}>
        No audit on file for supplier <code>{String(supplierId)}</code>.
      </div>
    );
  }

  // 60-day plan items (only for Helios case)
  const helios60Plan = [
    { id: "P-1", text: "Stand up MSA on Ø17.98 rotor shaft (CTQ).",                    owner: "QA-lead",  due_d: 21, status: "in-progress" },
    { id: "P-2", text: "Implement SPC on stator bore Ø119.94 with X̄-R charts.",        owner: "Process",  due_d: 28, status: "open" },
    { id: "P-3", text: "Reduce CAPA closure SLA from 38d → 21d (process redesign).",   owner: "QA-mgr",   due_d: 45, status: "open" },
    { id: "P-4", text: "Refresh training matrix to current org · sign-offs.",          owner: "HR",       due_d: 35, status: "open" },
    { id: "P-5", text: "Tool-life log on lathe-3 + extend across 8 machines.",         owner: "Maint",    due_d: 30, status: "in-progress" },
    { id: "P-6", text: "Hazardous waste manifest reconciled · Feb-25 gap closed.",     owner: "EHS",      due_d: 14, status: "in-progress" },
    { id: "P-7", text: "Inspection cadence harmonised across 1st & 2nd shift.",        owner: "Process",  due_d: 21, status: "open" },
  ];

  const signOffChain = [
    { role: "Supplier QA",    name: "Internal QA Head",   at: "2026-04-10", status: "signed",   color: A3.OK   },
    { role: "Forge Auditor",  name: "Priya I.",           at: "2026-04-10", status: "signed",   color: A3.OK   },
    { role: "QA Manager",     name: "Karan V.",           at: "2026-04-12", status: "signed",   color: A3.OK   },
    { role: "Plant Director", name: "Meera S.",           at: "2026-04-14", status: "signed",   color: A3.OK   },
    { role: "Customer Rep",   name: "Helios AgriFlow",    at: "2026-04-18", status: "pending",  color: A3.WARN },
  ];

  const root = {
    background: A3.BG, color: A3.INK, minHeight: "100%",
    fontFamily: A3.FONT_UI, fontSize: 13, padding: "20px 28px 60px",
  };

  return (
    <div style={root}>
      <div style={{ display: "flex", justifyContent: "space-between", alignItems: "flex-start", marginBottom: 16 }}>
        <div>
          <div style={a3MonoSmall({ marginBottom: 4 })}>
            forge:// audit · {audit._synthetic ? "synthesised summary" : "VQP 2.0 full report"}
          </div>
          <div style={{ fontFamily: A3.FONT_SER, fontSize: 26, letterSpacing: "-0.01em" }}>
            {audit.supplier}
          </div>
          <div style={{ marginTop: 6, fontSize: 12, color: A3.INK_3 }}>
            Auditor <span style={{ color: A3.INK_2 }}>{audit.auditor}</span> ·
            Date <span style={{ fontFamily: A3.FONT_MONO, color: A3.INK_2 }}> {audit.date}</span>
            {audit._synthetic ? <span style={{ marginLeft: 8, color: A3.INK_3 }}>· audit on file</span> : null}
          </div>
        </div>
        <div style={a3Card({ minWidth: 220, textAlign: "center" })}>
          <div style={a3MonoSmall({ marginBottom: 6 })}>Overall</div>
          <div style={{
            fontFamily: A3.FONT_MONO, fontSize: 36, fontWeight: 600, fontVariantNumeric: "tabular-nums",
            color: a3ScoreColor(audit.score_pct), lineHeight: 1.0,
          }}>{audit.score_pct}%</div>
          <div style={{ marginTop: 8 }}>{a3Badge(audit.status, a3StatusTone(audit.status))}</div>
        </div>
      </div>

      {/* tab selector */}
      <div style={{ display: "flex", borderBottom: "1px solid " + A3.LINE, marginBottom: 0 }}>
        {audit.tabs.map(function (t, i) {
          const active = activeTab === i;
          return (
            <button key={t.tab} onClick={function () { setActiveTab(i); }}
              style={_a3TabBtnStyle(active)}>
              {t.tab}
              <span style={{ marginLeft: 6, color: a3ScoreColor(t.score_pct), fontWeight: 600, fontVariantNumeric: "tabular-nums" }}>
                {t.score_pct}%
              </span>
            </button>
          );
        })}
      </div>

      {/* tab body */}
      <div style={Object.assign(a3Card({ marginBottom: 18, marginTop: 0 }), { borderTop: 0, borderRadius: "0 0 4px 4px" })}>
        {(function () {
          const tab = audit.tabs[activeTab];
          const tmplTab = tmpl.tabs[activeTab];
          return tmplTab.criteria.map(function (c, idx) {
            const finding = tab.findings.find(function (f) { return f.id === c.id; }) || { result: "—", note: "" };
            const tone = finding.result === "pass" ? A3.OK
                     : finding.result === "partial" ? A3.WARN
                     : finding.result === "fail" ? A3.BAD
                     : A3.INK_3;
            return (
              <div key={c.id} style={{
                display: "grid", gridTemplateColumns: "60px 1fr 100px 1fr",
                gap: 12, padding: "8px 4px",
                borderBottom: idx < tmplTab.criteria.length - 1 ? "1px solid " + A3.LINE_SOFT : "0",
                alignItems: "center",
              }}>
                <span style={{ fontFamily: A3.FONT_MONO, color: A3.INK_3, fontSize: 12 }}>{c.id}</span>
                <span style={{ fontSize: 13 }}>{c.text}</span>
                <span style={{
                  fontFamily: A3.FONT_MONO, fontSize: 12, color: tone,
                  textTransform: "uppercase", fontWeight: 600,
                }}>{finding.result}</span>
                <span style={{ fontSize: 12, color: A3.INK_3 }}>{finding.note || "—"}</span>
              </div>
            );
          });
        })()}
      </div>

      {/* notes */}
      <div style={Object.assign(a3Card({ marginBottom: 18 }), { background: A3.BG_2 })}>
        <div style={a3MonoSmall({ marginBottom: 6 })}>Auditor's note</div>
        <div style={{ fontFamily: A3.FONT_SER, fontSize: 14, lineHeight: 1.55, color: A3.INK_2 }}>
          “{audit.notes}”
        </div>
      </div>

      {/* decision panel + 60d plan + sign-off */}
      <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 16, marginBottom: 18 }}>
        <div style={a3Card()}>
          <div style={{ display: "flex", justifyContent: "space-between", marginBottom: 10 }}>
            <span style={a3MonoSmall()}>Decision</span>
            {a3Badge(audit.status, a3StatusTone(audit.status))}
          </div>
          <div style={{ fontSize: 13, color: A3.INK_2, marginBottom: 12 }}>
            {audit.status === "approved" ? "Full approval. Annual recertification required." :
              audit.status === "conditional" ? "Conditional approval. 60-day improvement plan attached. Re-audit on closure of all open items." :
              audit.status === "blocked" ? "Blocked from new POs until corrective actions complete." :
              "Decision pending."}
          </div>
          <div style={a3MonoSmall({ marginBottom: 6 })}>60-day improvement plan</div>
          {(isHelios ? helios60Plan : []).map(function (p, i) {
            return (
              <div key={p.id} style={{
                display: "grid", gridTemplateColumns: "44px 1fr 90px 70px 90px",
                gap: 8, padding: "6px 0",
                borderBottom: i < helios60Plan.length - 1 ? "1px solid " + A3.LINE_SOFT : "0",
                alignItems: "center", fontSize: 12,
              }}>
                <span style={{ fontFamily: A3.FONT_MONO, color: A3.INK_3 }}>{p.id}</span>
                <span>{p.text}</span>
                <span style={{ fontFamily: A3.FONT_MONO, fontSize: 12, color: A3.INK_3 }}>{p.owner}</span>
                <span style={{ fontFamily: A3.FONT_MONO, fontSize: 12, color: A3.INK_3 }}>+{p.due_d}d</span>
                <span>{a3Badge(p.status, a3StatusTone(p.status))}</span>
              </div>
            );
          })}
          {!isHelios ? (
            <div style={{ color: A3.INK_3, fontSize: 12, fontStyle: "italic" }}>
              No active improvement plan recorded. See QA-mgr to start one.
            </div>
          ) : null}
        </div>

        <div style={a3Card()}>
          <div style={a3MonoSmall({ marginBottom: 10 })}>Sign-off chain</div>
          {signOffChain.map(function (s, i) {
            return (
              <div key={s.role} style={{
                display: "flex", alignItems: "center", gap: 12,
                padding: "10px 0",
                borderBottom: i < signOffChain.length - 1 ? "1px solid " + A3.LINE_SOFT : "0",
              }}>
                <div style={_a3SignOffDot(s)}>
                  {s.status === "signed" ? "✓" : (i + 1)}
                </div>
                <div style={{ flex: 1 }}>
                  <div style={{ fontWeight: 600, fontSize: 13 }}>{s.role}</div>
                  <div style={{ fontSize: 12, color: A3.INK_3 }}>{s.name}</div>
                </div>
                <div style={{ textAlign: "right" }}>
                  <div style={{ fontFamily: A3.FONT_MONO, fontSize: 12, color: A3.INK_3 }}>{s.at}</div>
                  {a3Badge(s.status, s.color)}
                </div>
              </div>
            );
          })}
        </div>
      </div>

      {/* approval timeline at bottom */}
      <div style={a3Card()}>
        <div style={a3MonoSmall({ marginBottom: 10 })}>Approval timeline</div>
        <div style={{ position: "relative", height: 80 }}>
          <div style={{ position: "absolute", top: 26, left: 0, right: 0, height: 2, background: A3.LINE }} />
          {signOffChain.map(function (s, i) {
            const x = (i / (signOffChain.length - 1)) * 100;
            return (
              <div key={s.role} style={{
                position: "absolute", left: "calc(" + x + "% - 14px)", top: 0,
                textAlign: "center", width: 120, marginLeft: -46,
              }}>
                <div style={{
                  width: 12, height: 12, borderRadius: 999,
                  background: s.color, border: "3px solid " + A3.BG,
                  margin: "20px auto 6px",
                  boxShadow: "0 0 0 1px " + s.color,
                }} />
                <div style={{ fontFamily: A3.FONT_MONO, fontSize: 12, color: A3.INK_3 }}>{s.at}</div>
                <div style={{ fontSize: 12, color: A3.INK_2, marginTop: 2 }}>{s.role}</div>
              </div>
            );
          })}
        </div>
      </div>
    </div>
  );
}

// ───────────────────────────────────────────────── S18: ToolingReadiness
function ScreenToolingReadiness() {
  const tenant = useActiveTenant();
  const program = (tenant && tenant.program) || { code: "M-27418" };
  const stations = (tenant && tenant.routing) || [];

  const [flash, setFlash] = uSA3(null);
  const a3FlashTimer = React.useRef(null);
  function fireFlash(msg) {
    setFlash(msg);
    if (a3FlashTimer.current) clearTimeout(a3FlashTimer.current);
    a3FlashTimer.current = setTimeout(function () {
      a3FlashTimer.current = null;
      setFlash(null);
    }, 1600);
  }
  uEA3(function () {
    return function () {
      if (a3FlashTimer.current) { clearTimeout(a3FlashTimer.current); a3FlashTimer.current = null; }
    };
  }, []);

  // 12 tooling items invented (covers the 7 stations).
  const tooling = [
    { id: "T-01", station: "s4", item: "Stator stamping die · 0.35mm CRGO · 200T press", status: "ready",     owner: "Aryan M.",  ready_by: "—",         step: "STEP-DIE-0341.stp",   life_pct: 0.42, calib_due: "2026-08-15" },
    { id: "T-02", station: "s4", item: "Rotor cage Al die-cast jig",                     status: "ready",     owner: "Rohit B.",  ready_by: "—",         step: "STEP-JIG-0508.stp",   life_pct: 0.71, calib_due: "2026-06-04" },
    { id: "T-03", station: "s4", item: "Shaft turning fixture · Ø17.98",                 status: "in-prep",   owner: "Rohit B.",  ready_by: "2026-05-08", step: "STEP-FIX-0612.stp",   life_pct: 0.18, calib_due: "2026-09-12" },
    { id: "T-04", station: "s5", item: "Stator press-fit jig · 12-18 kN",                status: "ready",     owner: "Neha G.",   ready_by: "—",         step: "STEP-JIG-0709.stp",   life_pct: 0.55, calib_due: "2026-07-21" },
    { id: "T-05", station: "s5", item: "Winding bobbin · 240t / 120SL",                  status: "in-prep",   owner: "Neha G.",   ready_by: "2026-05-10", step: "STEP-BOB-0822.stp",   life_pct: 0.04, calib_due: "2027-01-30" },
    { id: "T-06", station: "s5", item: "Hipot tester 1500V AC · cert IS 996",            status: "ready",     owner: "Neha G.",   ready_by: "—",         step: "—",                   life_pct: 0.61, calib_due: "2026-05-02" },
    { id: "T-07", station: "s6", item: "Dynamic balance fixture · impeller W42",         status: "blocked",   owner: "Rohit B.",  ready_by: "2026-05-22", step: "STEP-BAL-0915.stp",   life_pct: 0.0,  calib_due: "—",         note: "Spire NRV finding upstream; balance rig pending part swap" },
    { id: "T-08", station: "s6", item: "Hydro test rig · 1.5× pressure · 30bar",         status: "ready",     owner: "Neha G.",   ready_by: "—",         step: "STEP-HYD-1004.stp",   life_pct: 0.38, calib_due: "2026-06-30" },
    { id: "T-09", station: "s4", item: "GM bushing press-fit jig · 22×28×30",            status: "ready",     owner: "Rohit B.",  ready_by: "—",         step: "STEP-PRS-1118.stp",   life_pct: 0.49, calib_due: "2026-10-08" },
    { id: "T-10", station: "s7", item: "Adapter torque tool · 18-22 Nm pneumatic",       status: "in-prep",   owner: "Aryan M.",  ready_by: "2026-05-05", step: "—",                   life_pct: 0.0,  calib_due: "2026-12-01" },
    { id: "T-11", station: "s7", item: "Brand-artwork stencil · Helios rev-B",           status: "ready",     owner: "Priya I.",  ready_by: "—",         step: "STEP-STN-1207.stp",   life_pct: 0.12, calib_due: "—" },
    { id: "T-12", station: "s7", item: "Final visual std panel · Class A finish",        status: "ready",     owner: "Priya I.",  ready_by: "—",         step: "—",                   life_pct: 0.0,  calib_due: "2026-11-01" },
  ];

  const ready = tooling.filter(function (t) { return t.status === "ready"; }).length;
  const inPrep = tooling.filter(function (t) { return t.status === "in-prep"; }).length;
  const blocked = tooling.filter(function (t) { return t.status === "blocked"; }).length;

  const root = {
    background: A3.BG, color: A3.INK, minHeight: "100%",
    fontFamily: A3.FONT_UI, fontSize: 13, padding: "20px 28px 60px",
  };

  function stationName(id) {
    const st = stations.find(function (s) { return s.id === id; });
    return st ? st.name : id;
  }

  return (
    <div style={root}>
      {/* header */}
      <div style={{ display: "flex", justifyContent: "space-between", alignItems: "baseline", marginBottom: 14 }}>
        <div>
          <div style={a3MonoSmall({ marginBottom: 4 })}>plan:// tooling · {program.code}</div>
          <div style={{ fontFamily: A3.FONT_SER, fontSize: 26, letterSpacing: "-0.01em" }}>
            Tooling readiness · hero order
          </div>
          <div style={{ color: A3.INK_3, fontSize: 12, marginTop: 4 }}>
            12 jigs / fixtures / instruments across 7 stations · launch dependency
          </div>
        </div>
        <div style={{ display: "flex", gap: 12 }}>
          <div style={a3Card({ textAlign: "center", minWidth: 90 })}>
            <div style={a3MonoSmall()}>Ready</div>
            <div style={{ fontFamily: A3.FONT_MONO, fontSize: 22, fontWeight: 600, fontVariantNumeric: "tabular-nums", color: A3.OK }}>{ready}</div>
          </div>
          <div style={a3Card({ textAlign: "center", minWidth: 90 })}>
            <div style={a3MonoSmall()}>In-prep</div>
            <div style={{ fontFamily: A3.FONT_MONO, fontSize: 22, fontWeight: 600, fontVariantNumeric: "tabular-nums", color: A3.WARN }}>{inPrep}</div>
          </div>
          <div style={a3Card({ textAlign: "center", minWidth: 90 })}>
            <div style={a3MonoSmall()}>Blocked</div>
            <div style={{ fontFamily: A3.FONT_MONO, fontSize: 22, fontWeight: 600, fontVariantNumeric: "tabular-nums", color: A3.BAD }}>{blocked}</div>
          </div>
        </div>
      </div>

      <div style={{ display: "grid", gridTemplateColumns: "1fr 280px", gap: 18 }}>
        {/* main checklist */}
        <div>
          <div style={Object.assign(a3Card(), { padding: 0, overflow: "hidden" })}>
            <div style={{
              display: "grid", gridTemplateColumns: "60px 1fr 130px 110px 110px",
              padding: "10px 12px", background: A3.BG_2,
              borderBottom: "1px solid " + A3.LINE,
            }}>
              <div style={a3MonoSmall()}>id</div>
              <div style={a3MonoSmall()}>item · station</div>
              <div style={a3MonoSmall()}>owner</div>
              <div style={a3MonoSmall()}>ready by</div>
              <div style={a3MonoSmall()}>status</div>
            </div>
            {tooling.map(function (t, i) {
              return (
                <div key={t.id} style={{
                  display: "grid", gridTemplateColumns: "60px 1fr 130px 110px 110px",
                  padding: "10px 12px",
                  borderBottom: i < tooling.length - 1 ? "1px solid " + A3.LINE_SOFT : "0",
                  alignItems: "center",
                }}>
                  <div style={{ fontFamily: A3.FONT_MONO, fontSize: 12, color: A3.INK_3 }}>{t.id}</div>
                  <div>
                    <div style={{ fontSize: 13 }}>{t.item}</div>
                    <div style={{ fontFamily: A3.FONT_MONO, fontSize: 12, color: A3.INK_3, marginTop: 2 }}>
                      {t.station} · {stationName(t.station)}
                    </div>
                    {t.note ? <div style={{ fontSize: 12, color: A3.BAD, marginTop: 4 }}>⚠ {t.note}</div> : null}
                  </div>
                  <div style={{ fontFamily: A3.FONT_MONO, fontSize: 12 }}>{t.owner}</div>
                  <div style={{ fontFamily: A3.FONT_MONO, fontSize: 12, color: A3.INK_3 }}>{t.ready_by}</div>
                  <div>{a3Badge(t.status, a3StatusTone(t.status))}</div>
                </div>
              );
            })}
          </div>

          {/* STEP files */}
          <div style={Object.assign(a3Card({ marginTop: 18 }), {})}>
            <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: 10 }}>
              <span style={a3MonoSmall()}>STEP file references</span>
              <button onClick={function () {
                var _q = function (err) { return err && (err.status === 404 || err.status === 400); };
                if (window.forgeApi && typeof window.forgeApi.mutate === "function") {
                  window.forgeApi.mutate("tool_orders", { op: "add", path: "/-", value: { program: program.code, requested_at: Date.now(), status: "draft" } })
                    .then(function () { fireFlash("Tool order opened · " + program.code); })
                    .catch(function (err) { fireFlash(_q(err) ? "Tool order queued · " + program.code : "Order failed · " + (err && err.message || "unknown")); });
                } else {
                  fireFlash("Tool order queued · " + program.code);
                }
              }} style={_A3_SMALL_BTN_STYLE}>+ Order new tooling</button>
            </div>
            <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 8 }}>
              {tooling.reduce(function (acc, t) { if (t.step !== "—") acc.push(t); return acc; }, []).map(function (t) {
                return (
                  <div key={t.id}
                    role="button"
                    tabIndex={0}
                    onClick={function () { fireFlash("STEP " + t.step + " viewer queued — v2"); }}
                    onKeyDown={function (e) { if (e.key === "Enter" || e.key === " ") { e.preventDefault(); fireFlash("STEP " + t.step + " viewer queued — v2"); } }}
                    style={_A3_STEP_FILE_STYLE}>
                    <span style={{ fontFamily: A3.FONT_MONO, fontSize: 12, color: A3.INK_3 }}>{t.id}</span>
                    <span style={{ fontFamily: A3.FONT_MONO, fontSize: 12, color: A3.COOL, flex: 1 }}>{t.step}</span>
                    <span style={{ fontFamily: A3.FONT_MONO, fontSize: 12, color: A3.INK_3 }}>open ↗</span>
                  </div>
                );
              })}
            </div>
          </div>
        </div>

        {/* right rail */}
        <div>
          <div style={a3Card()}>
            <div style={a3MonoSmall({ marginBottom: 8 })}>Die / fixture lifecycle</div>
            {tooling.filter(function (t) { return t.life_pct > 0; }).slice(0, 6).map(function (t) {
              const usage = t.life_pct;
              const tone = usage > 0.8 ? A3.BAD : usage > 0.6 ? A3.WARN : A3.OK;
              return (
                <div key={t.id} style={{ marginBottom: 10 }}>
                  <div style={{ display: "flex", justifyContent: "space-between", fontSize: 12, marginBottom: 3 }}>
                    <span style={{ color: A3.INK_2 }}>{t.id} · {t.item.split("·")[0]}</span>
                    <span style={{ fontFamily: A3.FONT_MONO, color: tone, fontVariantNumeric: "tabular-nums" }}>{Math.round(usage * 100)}%</span>
                  </div>
                  <div style={{ height: 5, background: A3.BG_2, borderRadius: 2, overflow: "hidden" }}>
                    <div style={{ width: (usage * 100) + "%", height: "100%", background: tone }} />
                  </div>
                </div>
              );
            })}
          </div>

          <div style={Object.assign(a3Card({ marginTop: 12 }), {})}>
            <div style={a3MonoSmall({ marginBottom: 8 })}>Calibration due</div>
            {tooling.filter(function (t) { return t.calib_due !== "—"; }).slice(0, 8).map(function (t, i) {
              return (
                <div key={t.id} style={{
                  display: "flex", justifyContent: "space-between",
                  padding: "5px 0", fontSize: 12,
                  borderBottom: i < 7 ? "1px solid " + A3.LINE_SOFT : "0",
                }}>
                  <span style={{ color: A3.INK_2 }}>{t.id}</span>
                  <span style={{ fontFamily: A3.FONT_MONO, fontSize: 12, color: A3.INK_3 }}>{t.calib_due}</span>
                </div>
              );
            })}
          </div>

          <div style={Object.assign(a3Card({ marginTop: 12 }), { background: A3.BG_2 })}>
            <div style={a3MonoSmall({ marginBottom: 6 })}>Launch gate</div>
            <div style={{ fontSize: 12, color: A3.INK_3, lineHeight: 1.5 }}>
              All 12 tooling items must show <b style={{ color: A3.OK }}>ready</b> before WO-44219 enters mass production. Currently <b style={{ color: blocked > 0 ? A3.BAD : A3.OK }}>{blocked}</b> blocked, <b style={{ color: A3.WARN }}>{inPrep}</b> in-prep.
            </div>
          </div>
        </div>
      </div>
      {flash ? (
        <div style={_A3_FLASH_STYLE}>{flash}</div>
      ) : null}
    </div>
  );
}

// ───────────────────────────────────────────────────────── S19: NPIPlan
function ScreenNPIPlan() {
  const tenant = useActiveTenant();
  const wos = (tenant && tenant.work_orders) || [];
  const wo = wos.find(function (w) { return w.id === "WO-44221"; }) || (wos[2] || {});
  const stations = (tenant && tenant.routing) || [];

  const [flash, setFlash] = uSA3(null);
  const a3FlashTimer = React.useRef(null);
  function fireFlash(msg) {
    setFlash(msg);
    if (a3FlashTimer.current) clearTimeout(a3FlashTimer.current);
    a3FlashTimer.current = setTimeout(function () {
      a3FlashTimer.current = null;
      setFlash(null);
    }, 1600);
  }
  uEA3(function () {
    return function () {
      if (a3FlashTimer.current) { clearTimeout(a3FlashTimer.current); a3FlashTimer.current = null; }
    };
  }, []);

  // 8-station NPI plan with pass/fail per pilot unit (10 units).
  // Receiving + Incoming + Storage + Machine + Motor Assy + Hipot + Hydro + Final
  const npiStations = [
    { id: "n1", seq: 1, name: "Receiving",         maps_to: "s1" },
    { id: "n2", seq: 2, name: "Incoming Inspect",  maps_to: "s2" },
    { id: "n3", seq: 3, name: "Storage",           maps_to: "s3" },
    { id: "n4", seq: 4, name: "Machine Shop",      maps_to: "s4" },
    { id: "n5", seq: 5, name: "Motor Assy",        maps_to: "s5" },
    { id: "n6", seq: 6, name: "Hipot",             maps_to: "s5" },
    { id: "n7", seq: 7, name: "Hydro",             maps_to: "s6" },
    { id: "n8", seq: 8, name: "Final Pump Assy",   maps_to: "s7" },
  ];

  // Synthesise per-unit results based on station_progress
  const units = uMA3(function () {
    const arr = [];
    const sp = wo.station_progress || {};
    for (let i = 0; i < 10; i++) {
      const u = { serial: "TPX-P-" + String(i + 1).padStart(4, "0"), results: {} };
      npiStations.forEach(function (st) {
        const p = sp[st.maps_to] != null ? sp[st.maps_to] : 0;
        // unit i passes a station if i / 10 < p; else if i / 10 < p+0.1 → in-progress; else not started
        const ratio = (i + 1) / 10;
        let r = "—";
        if (p >= 1) r = "pass";
        else if (ratio <= p) r = "pass";
        else if (ratio <= p + 0.1) r = "in-progress";
        else r = "—";
        // sprinkle one fail at deterministic spot
        if (st.id === "n5" && i === 5) r = "fail"; // mirror travelers TPX-H-0006 hold pattern
        u.results[st.id] = r;
      });
      arr.push(u);
    }
    return arr;
  }, [wo, npiStations]);

  let totalPass = 0, totalFail = 0;
  units.forEach(function (u) {
    const finalRes = u.results.n8;
    if (finalRes === "pass") totalPass++;
    if (Object.keys(u.results).some(function (k) { return u.results[k] === "fail"; })) totalFail++;
  });

  const stationGateDecision = npiStations.map(function (st) {
    let p = 0, f = 0, ip = 0;
    units.forEach(function (u) {
      const r = u.results[st.id];
      if (r === "pass") p++; else if (r === "fail") f++; else if (r === "in-progress") ip++;
    });
    return Object.assign({}, st, { pass: p, fail: f, in_progress: ip,
      decision: f > 0 ? "block" : (p === 10 ? "approved" : (ip > 0 ? "in-progress" : "pending")) });
  });

  const root = {
    background: A3.BG, color: A3.INK, minHeight: "100%",
    fontFamily: A3.FONT_UI, fontSize: 13, padding: "20px 28px 60px",
  };

  function resultCell(r) {
    if (r === "pass") return { c: A3.OK, t: "✓" };
    if (r === "fail") return { c: A3.BAD, t: "✗" };
    if (r === "in-progress") return { c: A3.WARN, t: "·" };
    return { c: A3.INK_3, t: "—" };
  }

  const allUnitsPassed = totalPass === 10;

  return (
    <div style={root}>
      {/* header */}
      <div style={{ display: "flex", justifyContent: "space-between", alignItems: "baseline", marginBottom: 14 }}>
        <div>
          <div style={a3MonoSmall({ marginBottom: 4 })}>plan:// npi · {wo.id || "WO-44221"} · {wo.sku || "M-31507"}</div>
          <div style={{ fontFamily: A3.FONT_SER, fontSize: 26, letterSpacing: "-0.01em" }}>
            NPI · 5HP scale-up pilot
          </div>
          <div style={{ color: A3.INK_3, fontSize: 12, marginTop: 4 }}>
            10-unit pilot lot · 8 station gates · First Article Reports per station
          </div>
        </div>
        <div style={{ display: "flex", gap: 12 }}>
          <div style={a3Card({ textAlign: "center", minWidth: 100 })}>
            <div style={a3MonoSmall()}>Pilot pass</div>
            <div style={{ fontFamily: A3.FONT_MONO, fontSize: 22, fontWeight: 600, fontVariantNumeric: "tabular-nums", color: A3.OK }}>
              {totalPass}<span style={{ color: A3.INK_4 }}>/10</span>
            </div>
          </div>
          <div style={a3Card({ textAlign: "center", minWidth: 100 })}>
            <div style={a3MonoSmall()}>On-hold</div>
            <div style={{ fontFamily: A3.FONT_MONO, fontSize: 22, fontWeight: 600, fontVariantNumeric: "tabular-nums", color: A3.BAD }}>{totalFail}</div>
          </div>
          <div style={a3Card({ textAlign: "center", minWidth: 100 })}>
            <div style={a3MonoSmall()}>Days to release</div>
            <div style={{ fontFamily: A3.FONT_MONO, fontSize: 22, fontWeight: 600, fontVariantNumeric: "tabular-nums", color: A3.WARN }}>21d</div>
          </div>
        </div>
      </div>

      <div style={{ display: "grid", gridTemplateColumns: "1fr 280px", gap: 18 }}>
        <div>
          {/* gate plan (column-wise station -> unit grid) */}
          <div style={Object.assign(a3Card(), { padding: 0, overflow: "auto" })}>
            <div style={{ padding: "10px 14px", borderBottom: "1px solid " + A3.LINE, background: A3.BG_2, display: "flex", justifyContent: "space-between" }}>
              <span style={a3MonoSmall()}>Pilot gate matrix · units × stations</span>
              <span style={{ fontFamily: A3.FONT_MONO, fontSize: 12, color: A3.INK_3 }}>
                ✓ pass · · in-prog · ✗ fail
              </span>
            </div>
            <div style={{
              display: "grid",
              gridTemplateColumns: "120px repeat(" + npiStations.length + ", 1fr)",
              fontFamily: A3.FONT_MONO, fontSize: 12,
            }}>
              <div style={{ padding: "8px 12px", borderBottom: "1px solid " + A3.LINE, background: A3.BG_2 }}>unit ↓</div>
              {npiStations.map(function (st) {
                return (
                  <div key={st.id} style={{
                    padding: "8px 6px", textAlign: "center",
                    borderBottom: "1px solid " + A3.LINE,
                    borderLeft: "1px solid " + A3.LINE_SOFT,
                    background: A3.BG_2,
                    color: A3.INK_3,
                  }}>{st.seq}. {st.name}</div>
                );
              })}
              {units.map(function (u, ui) {
                const cells = [
                  <div key={u.serial + "-h"} style={{
                    padding: "10px 12px",
                    borderBottom: ui < units.length - 1 ? "1px solid " + A3.LINE_SOFT : "0",
                    color: A3.INK_2,
                  }}>{u.serial}</div>
                ];
                npiStations.forEach(function (st) {
                  const r = u.results[st.id];
                  const cell = resultCell(r);
                  cells.push(
                    <div key={u.serial + "-" + st.id} style={{
                      padding: "10px 6px", textAlign: "center",
                      borderBottom: ui < units.length - 1 ? "1px solid " + A3.LINE_SOFT : "0",
                      borderLeft: "1px solid " + A3.LINE_SOFT,
                      color: cell.c, fontWeight: 600, fontSize: 14,
                    }}>{cell.t}</div>
                  );
                });
                return cells;
              })}
            </div>
          </div>

          {/* per-station gate decision */}
          <div style={Object.assign(a3Card({ marginTop: 18 }), {})}>
            <div style={a3MonoSmall({ marginBottom: 10 })}>Gate decisions</div>
            <div style={{ display: "grid", gridTemplateColumns: "repeat(8, 1fr)", gap: 8 }}>
              {stationGateDecision.map(function (st) {
                return (
                  <div key={st.id} style={{
                    border: "1px solid " + A3.LINE, borderRadius: 3,
                    padding: 10, textAlign: "center", background: A3.BG_3,
                  }}>
                    <div style={{ fontFamily: A3.FONT_MONO, fontSize: 12, color: A3.INK_3 }}>{st.seq}</div>
                    <div style={{ fontSize: 12, color: A3.INK_2, marginBottom: 6, minHeight: 28 }}>{st.name}</div>
                    <div style={{
                      fontFamily: A3.FONT_MONO, fontSize: 12,
                      color: a3StatusTone(st.decision),
                      textTransform: "uppercase", fontWeight: 600,
                    }}>{st.decision}</div>
                    <div style={{ fontFamily: A3.FONT_MONO, fontSize: 12, color: A3.INK_3, marginTop: 4, fontVariantNumeric: "tabular-nums" }}>
                      {st.pass}p · {st.in_progress}i · {st.fail}f
                    </div>
                  </div>
                );
              })}
            </div>
          </div>

          {/* FAR links */}
          <div style={Object.assign(a3Card({ marginTop: 18 }), {})}>
            <div style={a3MonoSmall({ marginBottom: 10 })}>First Article Reports (FAR)</div>
            <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 8 }}>
              {npiStations.map(function (st) {
                return (
                  <div key={st.id}
                    role="button"
                    tabIndex={0}
                    onClick={function () { fireFlash("FAR-" + wo.id + "-" + st.id + " viewer queued — v2"); }}
                    onKeyDown={function (e) { if (e.key === "Enter" || e.key === " ") { e.preventDefault(); fireFlash("FAR-" + wo.id + "-" + st.id + " viewer queued — v2"); } }}
                    style={{
                    display: "flex", justifyContent: "space-between",
                    padding: "8px 10px", border: "1px dashed " + A3.LINE,
                    borderRadius: 3, background: A3.BG_3, cursor: "pointer",
                  }}>
                    <div>
                      <div style={{ fontFamily: A3.FONT_MONO, fontSize: 12, color: A3.INK_3 }}>FAR-{wo.id}-{st.id}</div>
                      <div style={{ fontSize: 12, color: A3.INK_2 }}>{st.name}</div>
                    </div>
                    <span style={{ fontFamily: A3.FONT_MONO, fontSize: 12, color: A3.COOL, alignSelf: "center" }}>open ↗</span>
                  </div>
                );
              })}
            </div>
          </div>
        </div>

        {/* right rail */}
        <div>
          <div style={a3Card()}>
            <div style={a3MonoSmall({ marginBottom: 8 })}>Pilot status</div>
            <div style={{ fontSize: 12, marginBottom: 8 }}>
              <div style={{ display: "flex", justifyContent: "space-between", marginBottom: 4 }}>
                <span>SKU</span><span style={{ fontFamily: A3.FONT_MONO }}>{wo.sku || "M-31507"}</span>
              </div>
              <div style={{ display: "flex", justifyContent: "space-between", marginBottom: 4 }}>
                <span>Quantity</span><span style={{ fontFamily: A3.FONT_MONO }}>10 units</span>
              </div>
              <div style={{ display: "flex", justifyContent: "space-between", marginBottom: 4 }}>
                <span>Started</span><span style={{ fontFamily: A3.FONT_MONO, fontSize: 12 }}>{wo.scheduled_start || "2026-04-15"}</span>
              </div>
              <div style={{ display: "flex", justifyContent: "space-between" }}>
                <span>Target close</span><span style={{ fontFamily: A3.FONT_MONO, fontSize: 12 }}>{wo.scheduled_end || "2026-05-05"}</span>
              </div>
            </div>
          </div>

          <div style={Object.assign(a3Card({ marginTop: 12 }), {})}>
            <div style={a3MonoSmall({ marginBottom: 8 })}>Convert pilot to series</div>
            <div style={{ fontSize: 12, color: A3.INK_3, marginBottom: 10 }}>
              Once all 10 pilot units pass the final gate, this WO can be promoted to a full series production order with auto-cloned routing & gates.
            </div>
            <button
              disabled={!allUnitsPassed}
              onClick={allUnitsPassed ? function () {
                var _q = function (err) { return err && (err.status === 404 || err.status === 400); };
                if (window.forgeApi && typeof window.forgeApi.mutate === "function") {
                  window.forgeApi.mutate("work_orders", { op: "replace", path: "/" + encodeURIComponent(wo.id) + "/status", value: "pilot-passed" })
                    .then(function () { fireFlash("Pilot promoted · " + wo.id + " → series"); })
                    .catch(function (err) { fireFlash(_q(err) ? "Pilot promoted · " + wo.id + " queued" : "Promote failed · " + (err && err.message || "unknown")); });
                } else {
                  fireFlash("Pilot promoted · " + wo.id + " queued");
                }
              } : undefined}
              style={_a3PromoteBtnStyle(allUnitsPassed)}>
              Convert to series →
            </button>
            {!allUnitsPassed ? (
              <div style={{ marginTop: 8, fontSize: 12, color: A3.INK_3, lineHeight: 1.4 }}>
                Disabled · pilot at 30%, {10 - totalPass} unit{10 - totalPass === 1 ? "" : "s"} still in-flight, {totalFail} on hold.
              </div>
            ) : null}
          </div>

          <div style={Object.assign(a3Card({ marginTop: 12 }), { background: A3.BG_2 })}>
            <div style={a3MonoSmall({ marginBottom: 6 })}>Risk register</div>
            <div style={{ fontSize: 12, color: A3.INK_3, lineHeight: 1.5 }}>
              <div>• 5HP rotor shaft Ø22: CTQ MSA pending at Vega Shafts.</div>
              <div>• Stator 180SL stamping: Elara die life at 71%, replacement scheduled.</div>
              <div>• NRV 2" SG-400: supplier under review (Spire EHS finding).</div>
            </div>
          </div>
        </div>
      </div>
      {flash ? (
        <div style={_A3_FLASH_STYLE}>{flash}</div>
      ) : null}
    </div>
  );
}

// ───────────────────────────────────────────────────────── S20: PFMEAPanel
function ScreenPFMEAPanel() {
  const tenant = useActiveTenant();
  const pfmea = (tenant && tenant.pfmea) || [];
  const stations = (tenant && tenant.routing) || [];

  const [sortKey, setSortKey] = uSA3("RPN");
  const [sortDir, setSortDir] = uSA3("desc");
  const [rpnFilter, setRpnFilter] = uSA3("all");        // all | crit (>=100) | mid (50-99) | low (<50)
  const [stationFilter, setStationFilter] = uSA3("all"); // station id or "all"
  const [sevFilter, setSevFilter] = uSA3(false);         // S>=7
  const [active, setActive] = uSA3(null);
  const [flash, setFlash] = uSA3(null);
  const a3FlashTimer = React.useRef(null);
  function fireFlash(msg) {
    setFlash(msg);
    if (a3FlashTimer.current) clearTimeout(a3FlashTimer.current);
    a3FlashTimer.current = setTimeout(function () {
      a3FlashTimer.current = null;
      setFlash(null);
    }, 1600);
  }
  uEA3(function () {
    return function () {
      if (a3FlashTimer.current) { clearTimeout(a3FlashTimer.current); a3FlashTimer.current = null; }
    };
  }, []);

  // reset local UI state when tenant switches
  uEA3(function () {
    if (typeof window === "undefined") return;
    function onTenantChange() {
      setSortKey("RPN");
      setSortDir("desc");
      setRpnFilter("all");
      setStationFilter("all");
      setSevFilter(false);
      setActive(null);
      setFlash(null);
    }
    window.addEventListener("forge:tenant-change", onTenantChange);
    return function () { window.removeEventListener("forge:tenant-change", onTenantChange); };
  }, []);

  // map mode → stations (heuristic by keywords)
  function modeStations(mode) {
    const txt = (mode.mode + " " + mode.cause + " " + (mode.current_control || "")).toLowerCase();
    const out = [];
    if (/winding|coil|stator|insulation|inter-turn|turns|surge|hipot|ir test/.test(txt)) out.push("s5");
    if (/balance|impeller/.test(txt)) out.push("s6");
    if (/nrv|leak|hydro/.test(txt)) out.push("s6");
    if (/torque|adapter|seal|cable|rotation|brand|label|artwork/.test(txt)) out.push("s7");
    if (/stamping|press|machining|die-cast|porosity|x-ray|foot|casting/.test(txt)) out.push("s4");
    if (/incoming|aql|class/.test(txt)) out.push("s2");
    if (out.length === 0) out.push("s5");
    return Array.from(new Set(out));
  }

  // map mode → quality gates (heuristic by current control text)
  function modeGates(mode) {
    const txt = (mode.current_control || "").toUpperCase();
    const re = /QG-\d+/g;
    return txt.match(re) || [];
  }

  const filtered = uMA3(function () {
    let arr = pfmea.slice().map(function (m, i) {
      return Object.assign({}, m, {
        _ix: i,
        _stations: modeStations(m),
        _gates: modeGates(m),
      });
    });
    if (rpnFilter === "crit") arr = arr.filter(function (m) { return m.RPN >= 100; });
    else if (rpnFilter === "mid") arr = arr.filter(function (m) { return m.RPN >= 50 && m.RPN < 100; });
    else if (rpnFilter === "low") arr = arr.filter(function (m) { return m.RPN < 50; });
    if (stationFilter !== "all") arr = arr.filter(function (m) { return m._stations.indexOf(stationFilter) >= 0; });
    if (sevFilter) arr = arr.filter(function (m) { return m.S >= 7; });
    arr.sort(function (a, b) {
      const av = a[sortKey], bv = b[sortKey];
      if (typeof av === "number") return sortDir === "asc" ? av - bv : bv - av;
      return sortDir === "asc" ? String(av).localeCompare(String(bv)) : String(bv).localeCompare(String(av));
    });
    return arr;
  }, [pfmea, rpnFilter, stationFilter, sevFilter, sortKey, sortDir]);

  function rpnColor(rpn) {
    if (rpn >= 100) return A3.BAD;
    if (rpn >= 50) return A3.WARN;
    return A3.OK;
  }

  function toggleSort(k) {
    if (sortKey === k) setSortDir(sortDir === "asc" ? "desc" : "asc");
    else { setSortKey(k); setSortDir(k === "mode" ? "asc" : "desc"); }
  }

  function stationName(id) {
    const st = stations.find(function (s) { return s.id === id; });
    return st ? st.name : id;
  }

  const root = {
    background: A3.BG, color: A3.INK, minHeight: "100%",
    fontFamily: A3.FONT_UI, fontSize: 13, padding: "20px 28px 60px",
  };

  const colTpl = "1.6fr 1.6fr 1.4fr 36px 36px 36px 60px 1.3fr 1.3fr";

  const sortHead = function (k, label, align) {
    const isActive = sortKey === k;
    return (
      <div role="button" tabIndex={0} onClick={function () { toggleSort(k); }} onKeyDown={function (e) { if (e.key === "Enter" || e.key === " ") { e.preventDefault(); toggleSort(k); } }} style={{
        cursor: "pointer", display: "flex", alignItems: "center", gap: 4,
        justifyContent: align === "right" ? "flex-end" : align === "center" ? "center" : "flex-start",
        color: isActive ? A3.INK : A3.INK_3,
      }}>
        {label}
        {isActive ? <span style={{ fontSize: 12 }}>{sortDir === "asc" ? "▲" : "▼"}</span> : null}
      </div>
    );
  };

  return (
    <div style={root}>
      {/* header */}
      <div style={{ display: "flex", justifyContent: "space-between", alignItems: "baseline", marginBottom: 14 }}>
        <div>
          <div style={a3MonoSmall({ marginBottom: 4 })}>build:// pfmea</div>
          <div style={{ fontFamily: A3.FONT_SER, fontSize: 26, letterSpacing: "-0.01em" }}>
            Process FMEA · {pfmea.length} modes
          </div>
          <div style={{ color: A3.INK_3, fontSize: 12, marginTop: 4 }}>
            S × O × D → RPN. Modes ≥100 require live containment.
          </div>
        </div>
        <div style={{ display: "flex", gap: 8 }}>
          <button onClick={function () {
            if (window.forgeApi && typeof window.forgeApi.exportAuditUrl === "function") {
              window.location.href = window.forgeApi.exportAuditUrl("csv");
              fireFlash("FMEA export started · audit CSV");
            } else {
              fireFlash("Export FMEA queued — v2");
            }
          }} style={_A3_HEADER_GHOST_BTN_STYLE}>Export FMEA</button>
          <button onClick={function () {
            var _q = function (err) { return err && (err.status === 404 || err.status === 400); };
            if (window.forgeApi && typeof window.forgeApi.mutate === "function") {
              window.forgeApi.mutate("pfmea_modes", { op: "add", path: "/-", value: { added_at: Date.now(), status: "draft" } })
                .then(function () { fireFlash("New mode added · draft"); })
                .catch(function (err) { fireFlash(_q(err) ? "New mode queued · draft" : "Add failed · " + (err && err.message || "unknown")); });
            } else {
              fireFlash("New mode queued · draft");
            }
          }} style={_A3_HEADER_INK_BTN_STYLE}>+ Add new mode</button>
        </div>
      </div>

      {/* filter chips */}
      <div style={Object.assign(a3Card({ marginBottom: 16 }), { display: "flex", gap: 14, flexWrap: "wrap", alignItems: "center" })}>
        <div style={{ display: "flex", gap: 6, alignItems: "center" }}>
          <span style={a3MonoSmall()}>RPN</span>
          {[["all", "all"], ["crit", "≥100"], ["mid", "50–99"], ["low", "<50"]].map(function (pair) {
            const k = pair[0], l = pair[1], active = rpnFilter === k;
            const tone = k === "crit" ? A3.BAD : k === "mid" ? A3.WARN : k === "low" ? A3.OK : A3.INK_2;
            return (
              <button key={k} onClick={function () { setRpnFilter(k); }} style={_a3PillBtnStyle(active, tone, tone, A3.BG)}>{l}</button>
            );
          })}
        </div>
        <div style={{ display: "flex", gap: 6, alignItems: "center" }}>
          <span style={a3MonoSmall()}>Station</span>
          <select value={stationFilter} onChange={function (e) { setStationFilter(e.target.value); }}
            id="pfmea-station-filter" name="pfmea-station-filter"
            aria-label="Filter by station"
            style={{
              padding: "4px 8px", border: "1px solid " + A3.LINE,
              background: A3.BG_3, fontFamily: A3.FONT_MONO, fontSize: 12,
            }}>
            <option value="all">all</option>
            {stations.map(function (s) { return <option key={s.id} value={s.id}>{s.id} · {s.name}</option>; })}
          </select>
        </div>
        <label style={{ display: "flex", gap: 6, alignItems: "center", cursor: "pointer" }}>
          <input type="checkbox" id="pfmea-severity-filter" name="pfmea-severity-filter" checked={sevFilter} onChange={function (e) { setSevFilter(e.target.checked); }} />
          <span style={a3MonoSmall()}>severity ≥ 7</span>
        </label>
        <div style={{ flex: 1 }} />
        <span style={{ fontFamily: A3.FONT_MONO, fontSize: 12, color: A3.INK_3 }}>
          {filtered.length} of {pfmea.length} modes
        </span>
      </div>

      <div style={{ display: "grid", gridTemplateColumns: active ? "1fr 360px" : "1fr", gap: 18 }}>
        {/* table */}
        <div style={Object.assign(a3Card(), { padding: 0, overflow: "hidden" })}>
          <div style={_a3PfmeaHeaderStyle(colTpl)}>
            {sortHead("mode", "Mode")}
            {sortHead("effect", "Effect")}
            {sortHead("cause", "Cause")}
            {sortHead("S", "S", "right")}
            {sortHead("O", "O", "right")}
            {sortHead("D", "D", "right")}
            {sortHead("RPN", "RPN", "center")}
            <div>Current control</div>
            <div>Recommended action</div>
          </div>
          {filtered.map(function (m, i) {
            const sel = active && active._ix === m._ix;
            return (
              <div key={m._ix}
                role="button"
                tabIndex={0}
                onClick={function () { setActive(m); }}
                onKeyDown={function (e) { if (e.key === "Enter" || e.key === " ") { e.preventDefault(); setActive(m); } }}
                style={_a3PfmeaRowStyle(colTpl, sel, i >= filtered.length - 1)}>
                <div style={{ fontSize: 12, fontWeight: 600, color: A3.INK }}>{m.mode}</div>
                <div style={{ fontSize: 12, color: A3.INK_2 }}>{m.effect}</div>
                <div style={{ fontSize: 12, color: A3.INK_3 }}>{m.cause}</div>
                <div style={{ fontFamily: A3.FONT_MONO, fontSize: 12, textAlign: "right", fontVariantNumeric: "tabular-nums" }}>{m.S}</div>
                <div style={{ fontFamily: A3.FONT_MONO, fontSize: 12, textAlign: "right", fontVariantNumeric: "tabular-nums" }}>{m.O}</div>
                <div style={{ fontFamily: A3.FONT_MONO, fontSize: 12, textAlign: "right", fontVariantNumeric: "tabular-nums" }}>{m.D}</div>
                <div style={_a3RpnBadgeStyle(m.RPN, rpnColor)}>{m.RPN}</div>
                <div style={{ fontSize: 12, color: A3.INK_3 }}>{m.current_control}</div>
                <div style={{ fontSize: 12, color: A3.INK_3 }}>{m.recommended_action}</div>
              </div>
            );
          })}
          {filtered.length === 0 ? (
            <div style={{ padding: 24, textAlign: "center", color: A3.INK_3 }}>
              No PFMEA entries match the current filter.
            </div>
          ) : null}
        </div>

        {active ? <_PFMEADetailPanel active={active} setActive={setActive} rpnColor={rpnColor} stationName={stationName} /> : null}
      </div>

      <_PFMEAFooterSummary pfmea={pfmea} />
      {flash ? (
        <div style={_A3_FLASH_STYLE}>{flash}</div>
      ) : null}
    </div>
  );
}

// ───────────────────────────────────────────────────── S20 helpers
function _PFMEADetailPanel({ active, setActive, rpnColor, stationName }) {
  return (
    <div style={a3Card()}>
      <div style={{ display: "flex", justifyContent: "space-between", marginBottom: 10 }}>
        <span style={a3MonoSmall()}>Mode detail</span>
        <button onClick={function () { setActive(null); }} style={{
          background: "transparent", border: 0, cursor: "pointer",
          color: A3.INK_3, fontFamily: A3.FONT_MONO, fontSize: 12,
        }}>✕</button>
      </div>
      <div style={{ fontFamily: A3.FONT_SER, fontSize: 18, lineHeight: 1.3, marginBottom: 10 }}>
        {active.mode}
      </div>
      <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr 1fr", gap: 8, marginBottom: 14 }}>
        <div style={{ textAlign: "center", padding: "8px 4px", background: A3.BG_2, borderRadius: 3 }}>
          <div style={a3MonoSmall()}>Severity</div>
          <div style={{ fontFamily: A3.FONT_MONO, fontSize: 22, fontWeight: 600, fontVariantNumeric: "tabular-nums", color: active.S >= 7 ? A3.BAD : A3.INK_2 }}>{active.S}</div>
        </div>
        <div style={{ textAlign: "center", padding: "8px 4px", background: A3.BG_2, borderRadius: 3 }}>
          <div style={a3MonoSmall()}>Occurrence</div>
          <div style={{ fontFamily: A3.FONT_MONO, fontSize: 22, fontWeight: 600, fontVariantNumeric: "tabular-nums", color: active.O >= 7 ? A3.BAD : A3.INK_2 }}>{active.O}</div>
        </div>
        <div style={{ textAlign: "center", padding: "8px 4px", background: A3.BG_2, borderRadius: 3 }}>
          <div style={a3MonoSmall()}>Detection</div>
          <div style={{ fontFamily: A3.FONT_MONO, fontSize: 22, fontWeight: 600, fontVariantNumeric: "tabular-nums", color: active.D >= 7 ? A3.BAD : A3.INK_2 }}>{active.D}</div>
        </div>
      </div>
      <div style={{ marginBottom: 12 }}>
        <div style={a3MonoSmall({ marginBottom: 4 })}>RPN</div>
        <div style={{ fontFamily: A3.FONT_MONO, fontSize: 30, fontWeight: 600, fontVariantNumeric: "tabular-nums", color: rpnColor(active.RPN) }}>
          {active.RPN}
        </div>
      </div>
      <div style={{ marginBottom: 12 }}>
        <div style={a3MonoSmall({ marginBottom: 4 })}>Effect</div>
        <div style={{ fontSize: 13, color: A3.INK_2 }}>{active.effect}</div>
      </div>
      <div style={{ marginBottom: 12 }}>
        <div style={a3MonoSmall({ marginBottom: 4 })}>Cause</div>
        <div style={{ fontSize: 13, color: A3.INK_2 }}>{active.cause}</div>
      </div>
      <div style={{ marginBottom: 12 }}>
        <div style={a3MonoSmall({ marginBottom: 4 })}>Current control</div>
        <div style={{ fontSize: 12, color: A3.INK_3 }}>{active.current_control}</div>
      </div>
      <div style={{ marginBottom: 14 }}>
        <div style={a3MonoSmall({ marginBottom: 4 })}>Recommended action</div>
        <div style={{ fontSize: 12, color: A3.INK_3 }}>{active.recommended_action}</div>
      </div>

      <div style={{ marginBottom: 14 }}>
        <div style={a3MonoSmall({ marginBottom: 6 })}>Stations affected</div>
        <div style={{ display: "flex", gap: 6, flexWrap: "wrap" }}>
          {active._stations.map(function (sid) {
            return (
              <button key={sid}
                onClick={function () { if (typeof navigate === "function") navigate("/build/routing"); }}
                style={_a3StationChipStyle(A3.COOL)}>{sid} · {stationName(sid)} ↗</button>
            );
          })}
        </div>
      </div>

      <div>
        <div style={a3MonoSmall({ marginBottom: 6 })}>Quality gates</div>
        <div style={{ display: "flex", gap: 6, flexWrap: "wrap" }}>
          {active._gates.length ? active._gates.map(function (g) {
            return (
              <button key={g}
                onClick={function () { if (typeof navigate === "function") navigate("/build/gates"); }}
                style={_a3StationChipStyle(A3.ACCENT)}>{g} ↗</button>
            );
          }) : <span style={{ fontSize: 12, color: A3.INK_3 }}>No gate currently mapped; recommend adding one.</span>}
        </div>
      </div>
    </div>
  );
}

function _PFMEAFooterSummary({ pfmea }) {
  return (
    <div style={Object.assign(a3Card({ marginTop: 18 }), {
      background: A3.BG_2, display: "grid", gridTemplateColumns: "repeat(4, 1fr)", gap: 18, textAlign: "center",
    })}>
      <div>
        <div style={a3MonoSmall()}>Modes ≥100 RPN</div>
        <div style={{ fontFamily: A3.FONT_MONO, fontSize: 22, fontWeight: 600, fontVariantNumeric: "tabular-nums", color: A3.BAD }}>
          {pfmea.filter(function (m) { return m.RPN >= 100; }).length}
        </div>
      </div>
      <div>
        <div style={a3MonoSmall()}>Modes 50–99</div>
        <div style={{ fontFamily: A3.FONT_MONO, fontSize: 22, fontWeight: 600, fontVariantNumeric: "tabular-nums", color: A3.WARN }}>
          {pfmea.filter(function (m) { return m.RPN >= 50 && m.RPN < 100; }).length}
        </div>
      </div>
      <div>
        <div style={a3MonoSmall()}>Severity ≥ 7</div>
        <div style={{ fontFamily: A3.FONT_MONO, fontSize: 22, fontWeight: 600, fontVariantNumeric: "tabular-nums", color: A3.BAD }}>
          {pfmea.filter(function (m) { return m.S >= 7; }).length}
        </div>
      </div>
      <div>
        <div style={a3MonoSmall()}>Avg RPN</div>
        <div style={{ fontFamily: A3.FONT_MONO, fontSize: 22, fontWeight: 600, fontVariantNumeric: "tabular-nums", color: A3.INK_2 }}>
          {pfmea.length ? Math.round(pfmea.reduce(function (a, b) { return a + b.RPN; }, 0) / pfmea.length) : 0}
        </div>
      </div>
    </div>
  );
}

// ────────────────────────────────────────────────────── route registration
if (typeof registerPumpRoute === "function") {
  registerPumpRoute({ path: "/forge/suppliers",      mode: "forge", title: "Suppliers",        renderer: function () { return React.createElement(ScreenSupplierList); } });
  registerPumpRoute({ path: "/forge/vendor-onboard", mode: "forge", title: "Vendor onboarding",renderer: function () { return React.createElement(ScreenVendorOnboarding); } });
  registerPumpRoute({ path: "/forge/audit",          mode: "forge", title: "Audit detail",     renderer: function () { return React.createElement(ScreenSupplierAuditDetail); } });
  registerPumpRoute({ path: "/plan/tooling",         mode: "plan",  title: "Tooling readiness",renderer: function () { return React.createElement(ScreenToolingReadiness); } });
  registerPumpRoute({ path: "/plan/npi",             mode: "plan",  title: "NPI plan",         renderer: function () { return React.createElement(ScreenNPIPlan); } });
  registerPumpRoute({ path: "/build/pfmea",          mode: "build", title: "PFMEA",            renderer: function () { return React.createElement(ScreenPFMEAPanel); } });
}

if (typeof window !== "undefined") {
  window.ScreenSupplierList         = ScreenSupplierList;
  window.ScreenVendorOnboarding     = ScreenVendorOnboarding;
  window.ScreenSupplierAuditDetail  = ScreenSupplierAuditDetail;
  window.ScreenToolingReadiness     = ScreenToolingReadiness;
  window.ScreenNPIPlan              = ScreenNPIPlan;
  window.ScreenPFMEAPanel           = ScreenPFMEAPanel;
}
