(function(){
/* FORGE — Aetherion (Space) tenant · Act-3 screens
 * Wave A1, Agent #5. Babel-standalone, NO ES imports / exports.
 * Globals expected:
 *   React, getActiveTenant, useActiveTenant, navigate, registerSpaceRoute,
 *   Icons, ui.jsx primitives (Pill, Btn, Panel, StatPill).
 *
 * Five screens for the KESTREL-3 12U bus program:
 *   ScreenAetherionSuppliers    /forge/suppliers       flight-heritage panel
 *   ScreenAetherionVendorOnboard /forge/vendor-onboard  AS9100 + ITAR wizard
 *   ScreenAetherionQualReview   /forge/audit           qualification deep-dive
 *   ScreenAetherionNPI          /forge/npi             9-stage SRR..LAUNCH
 *   ScreenAetherionPFMEA        /build/pfmea           ECO-AET-0042 hinge
 *
 * Aesthetic: cool blues over deep navy (no neon), monospace digits, units
 * always rendered (g, W, V, mA, mm, krad). No emoji. No glyph stand-ins.
 *
 * ITAR data segregation note: every screen renders an ITAR-aware banner.
 * The qual / heritage columns and the radiation TID artefacts are
 * marked as US-persons-only — non-US viewers see redacted cells. The
 * route reads `tenant.itar === true` (default true for aetherion).
 *
 * Fixtures in this file are defensive: each screen first looks at
 * useActiveTenant(); if the active tenant id is "aetherion" and the
 * relevant slice (suppliers / qual_artifacts / pfmea / npi) is present
 * we use it. Otherwise the embedded constants from tenant-spec/space.md
 * §3, §6, §7 are used directly so the screens render standalone during
 * the wave-A1 build before fixtures-aetherion.jsx lands. */

const { useState: uSAE3, useMemo: uMAE3, useEffect: uEAE3, useRef: uRAE3 } = React;

// ──────────────────────────────────────────────────────────── ink atoms
// Wave 12D · w12d-aet-light-rest — rebound to canonical light tokens so
// these screens read as siblings of dashboard.jsx (cream surface, dark ink).
const AE = {
  INK:        "var(--bg-0)",     // cream page bg (was deep navy)
  INK_2:      "var(--bg-2)",     // elevated surface (was deep navy 2)
  INK_3:      "var(--bg-1)",     // card surface (was navy line)
  INK_4:      "var(--bg-3)",     // dim elevated (was deeper navy)
  SLATE:      "var(--ink-3)",    // muted labels (was navy slate)
  SLATE_2:    "var(--ink-4)",    // dimmer slate
  PAPER:      "var(--bg-1)",     // card surface
  PAPER_2:    "var(--bg-2)",     // alt card surface
  PAPER_3:    "var(--bg-inset)", // inset surface
  ACCENT:     "#2D5BEA",         // saturated blue that reads on cream
  ACCENT_2:   "#1F4AC8",         // deeper blue
  ACCENT_DIM: "#9DB5F0",         // soft blue tint
  MONO:       "var(--ink)",      // primary text (dark)
  OK:         "var(--ok)",
  WARN:       "var(--warn)",
  BAD:        "var(--err)",
  CRIT:       "var(--err)",
  LINE:       "var(--line)",
  LINE_SOFT:  "var(--line-soft)",
  FONT_UI:    "var(--font-ui)",
  FONT_MONO:  "var(--font-mono)",
  FONT_SER:   "var(--font-serif)",
};

// Hoisted style atoms — extracted from inline JSX for react-doctor compliance.
const _ae3_pillBase = {
  display: "inline-flex", alignItems: "center", gap: 5, height: 20,
  padding: "0 8px", borderRadius: 999,
  fontFamily: AE.FONT_MONO, fontSize: 12, letterSpacing: "0.08em",
  textTransform: "uppercase",
  background: "transparent",
};
const _ae3_itarBannerBase = {
  display: "flex", alignItems: "center", gap: 10,
  padding: "6px 12px", marginBottom: 12,
  border: "1px solid " + AE.ACCENT_DIM,
  borderLeft: "3px solid " + AE.ACCENT,
  borderRadius: 3,
  fontFamily: AE.FONT_MONO, fontSize: 12, letterSpacing: "0.08em",
  textTransform: "uppercase",
  color: AE.MONO,
};
const _ae3_primaryBtnBase = {
  background: AE.ACCENT, color: AE.INK, padding: "8px 14px",
  borderRadius: 4, border: 0, fontFamily: AE.FONT_MONO, fontSize: 12,
  letterSpacing: "0.05em", textTransform: "uppercase", cursor: "pointer", fontWeight: 600,
};
const _ae3_chipBase = {
  padding: "4px 10px", borderRadius: 999,
  fontFamily: AE.FONT_MONO, fontSize: 12, textTransform: "uppercase",
  letterSpacing: "0.06em", cursor: "pointer",
};
const _ae3_heritageNoteBase = {
  fontSize: 12, color: AE.SLATE, marginBottom: 10,
  fontFamily: AE.FONT_MONO, lineHeight: 1.45,
  background: AE.INK_3, padding: "6px 8px", borderRadius: 3,
  borderLeft: "2px solid " + AE.ACCENT_DIM,
};
const _ae3_supplierFooterBase = {
  marginTop: 10, paddingTop: 8,
  borderTop: "1px solid " + AE.LINE_SOFT,
  display: "flex", justifyContent: "space-between",
  fontSize: 12, color: AE.SLATE_2, fontFamily: AE.FONT_MONO,
};
const _ae3_partsLineBase = {
  marginTop: 8, fontSize: 12,
  color: AE.ACCENT, fontFamily: AE.FONT_MONO,
  textTransform: "uppercase", letterSpacing: "0.06em",
};
const _ae3_qualifyBtnFull = {
  width: "100%", padding: "8px 12px", borderRadius: 4,
  background: AE.ACCENT, color: AE.INK, border: 0,
  fontFamily: AE.FONT_MONO, fontSize: 12, letterSpacing: "0.05em",
  textTransform: "uppercase", cursor: "pointer", fontWeight: 600,
};
const _ae3_backBtn = {
  background: AE.INK_3, color: AE.MONO, padding: "6px 12px", borderRadius: 4,
  border: "1px solid " + AE.LINE, fontFamily: AE.FONT_MONO, fontSize: 12,
  letterSpacing: "0.05em", textTransform: "uppercase", cursor: "pointer",
};
const _ae3_inputBase = {
  width: "100%", padding: "6px 8px",
  border: "1px solid " + AE.LINE, background: AE.INK_3,
  fontSize: 13, color: AE.MONO, borderRadius: 3,
};
const _ae3_criteriaRowBase = {
  display: "grid",
  gridTemplateColumns: "60px 1fr 220px 220px 80px",
  gap: 12, padding: "10px 6px",
  alignItems: "center",
};
const _ae3_scoreBtnBase = {
  flex: 1, padding: "6px 0",
  fontFamily: AE.FONT_MONO, fontSize: 12, fontWeight: 600,
  cursor: "pointer", borderRadius: 3,
};
const _ae3_dropFileBase = {
  border: "1px dashed " + AE.LINE, borderRadius: 3,
  padding: "8px 0", textAlign: "center",
  fontFamily: AE.FONT_MONO, fontSize: 12, color: AE.SLATE_2,
  cursor: "default",
};
const _ae3_stickyFooter = {
  position: "sticky", bottom: 0,
  background: AE.INK, borderTop: "2px solid " + AE.ACCENT,
  padding: "14px 18px", display: "flex",
  justifyContent: "space-between", alignItems: "center",
};
const _ae3_cancelBtn = {
  padding: "10px 16px", border: "1px solid " + AE.LINE,
  background: AE.INK_3, color: AE.MONO,
  borderRadius: 4, fontFamily: AE.FONT_MONO, fontSize: 12,
  textTransform: "uppercase", cursor: "pointer",
};
const _ae3_saveBtnBase = {
  padding: "10px 18px", border: 0,
  color: AE.INK, borderRadius: 4,
  fontFamily: AE.FONT_MONO, fontSize: 12,
  textTransform: "uppercase", letterSpacing: "0.05em",
  fontWeight: 600,
};
const _ae3_flashToast = {
  position: "fixed", bottom: 24, right: 28,
  background: AE.ACCENT, color: AE.INK, padding: "12px 16px", borderRadius: 4,
  fontFamily: AE.FONT_MONO, fontSize: 12, letterSpacing: "0.05em",
  boxShadow: "0 6px 20px rgba(79,143,255,0.20)", maxWidth: 380, fontWeight: 600,
};
const _ae3_exportBtn = {
  padding: "8px 14px", borderRadius: 4,
  border: "1px solid " + AE.LINE, background: AE.INK_3,
  fontFamily: AE.FONT_MONO, fontSize: 12, textTransform: "uppercase",
  color: AE.MONO, cursor: "pointer",
};
const _ae3_artifactFooterBase = {
  marginTop: 8, paddingTop: 6,
  borderTop: "1px solid " + AE.LINE_SOFT,
  fontSize: 12, color: AE.SLATE_2, fontFamily: AE.FONT_MONO,
  display: "flex", justifyContent: "space-between",
};
const _ae3_restrictedNote = {
  padding: 14, border: "1px dashed " + AE.LINE,
  borderRadius: 3, color: AE.SLATE, fontSize: 12,
  background: AE.INK_3, fontFamily: AE.FONT_MONO, lineHeight: 1.5,
};
const _ae3_resultBadgeBase = {
  display: "inline-block",
  padding: "2px 8px",
  borderRadius: 3,
  fontFamily: AE.FONT_MONO, fontSize: 12,
  color: AE.INK, fontWeight: 700, textAlign: "center",
};
const _ae3_acceptanceCallout = {
  marginTop: 14, padding: "10px 12px",
  background: AE.INK_3, border: "1px dashed " + AE.LINE,
  borderRadius: 3, fontSize: 12, color: AE.SLATE, lineHeight: 1.5,
};
const _ae3_npiStageHeaderRow = {
  display: "grid", gridTemplateColumns: "60px 110px 1fr 140px 110px",
  padding: "10px 14px", background: AE.INK_3,
  borderBottom: "1px solid " + AE.LINE,
};
const _ae3_npiStageRowBase = {
  display: "grid", gridTemplateColumns: "60px 110px 1fr 140px 110px",
  padding: "12px 14px",
  cursor: "pointer", alignItems: "center",
};
const _ae3_ecoBannerCallout = {
  padding: "10px 12px",
  border: "1px solid " + AE.WARN, borderRadius: 3,
  fontSize: 12, color: AE.MONO, lineHeight: 1.5, marginBottom: 12,
  background: AE.INK_3,
};
const _ae3_pfmeaEcoBanner = {
  background: AE.INK_2,
  border: "1px solid " + AE.WARN, borderLeft: "4px solid " + AE.WARN,
  borderRadius: 3, padding: "12px 16px", marginBottom: 16,
  display: "flex", alignItems: "center", gap: 14,
};
const _ae3_pfmeaTableHeader = {
  padding: "10px 12px", background: AE.INK_3,
  borderBottom: "1px solid " + AE.LINE,
  fontSize: 12, textTransform: "uppercase",
  fontFamily: AE.FONT_MONO, letterSpacing: "0.06em", gap: 8,
};
const _ae3_pfmeaRowBase = {
  gap: 8,
  padding: "12px 12px",
  alignItems: "center", cursor: "pointer",
};
const _ae3_pfmeaScoreInput = {
  width: "100%", padding: "4px 0",
  color: AE.MONO,
  fontFamily: AE.FONT_MONO, fontSize: 12, textAlign: "center", borderRadius: 3,
};
const _ae3_pfmeaRpnCell = {
  fontFamily: AE.FONT_MONO, fontSize: 13, fontWeight: 700,
  textAlign: "center", borderRadius: 3, padding: "4px 6px",
};
const _ae3_ecoLinkChip = {
  display: "inline-block", marginTop: 4,
  padding: "1px 6px", borderRadius: 3,
  background: "rgba(224,162,74,0.18)", color: AE.WARN,
  fontFamily: AE.FONT_MONO, fontSize: 12,
};
const _ae3_pfmeaRpnPanel = {
  padding: "12px 14px", marginBottom: 14,
  background: AE.INK_3, borderRadius: 3,
  border: "1px solid " + AE.LINE, textAlign: "center",
};
const _ae3_linkedEcoCard = {
  padding: "10px 12px", background: "rgba(224,162,74,0.10)",
  border: "1px solid " + AE.WARN, borderRadius: 3, marginBottom: 12,
};
const _ae3_openEcoBtn = {
  marginTop: 8, padding: "5px 10px",
  background: "transparent", color: AE.WARN,
  border: "1px solid " + AE.WARN, borderRadius: 3,
  fontFamily: AE.FONT_MONO, fontSize: 12, cursor: "pointer",
};
const _ae3_actionPill = {
  fontFamily: AE.FONT_MONO, fontSize: 12, color: AE.WARN,
  padding: "2px 10px", borderRadius: 3,
  background: "rgba(224,162,74,0.10)", border: "1px solid " + AE.WARN,
};
const _ae3_npiOpenReviewBtn = {
  width: "100%", padding: "10px 12px", borderRadius: 4,
  background: AE.ACCENT, color: AE.INK, border: 0,
  fontFamily: AE.FONT_MONO, fontSize: 12, letterSpacing: "0.05em",
  textTransform: "uppercase", cursor: "pointer", fontWeight: 600,
};
const _ae3_pfmeaOpenEcoBtn = {
  padding: "8px 14px", borderRadius: 4, border: "1px solid " + AE.WARN,
  background: "transparent", color: AE.WARN, fontFamily: AE.FONT_MONO,
  fontSize: 12, textTransform: "uppercase", cursor: "pointer", fontWeight: 600,
};

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

function aeCard(extra) {
  return Object.assign({
    background: AE.INK_2,
    border: "1px solid " + AE.LINE,
    borderRadius: 4,
    padding: 14,
    color: AE.MONO,
  }, extra || {});
}

function aePill(label, tone) {
  const c = tone || AE.SLATE;
  return (
    <span style={{ ..._ae3_pillBase, border: "1px solid " + c, color: c }}>
      <span style={{ width: 5, height: 5, borderRadius: 999, background: c }} />
      {label}
    </span>
  );
}

function aeQualTone(qual) {
  const q = String(qual || "").toLowerCase();
  if (q === "qual-passed" || q === "trl-9" || /trl-9/.test(q)) return AE.OK;
  if (q === "flight-spare" || q.indexOf("trl-8") >= 0) return AE.ACCENT;
  if (q === "engineering-model" || q.indexOf("trl-7") >= 0) return AE.WARN;
  if (q === "qual-pending" || q.indexOf("trl-6") >= 0) return AE.WARN;
  if (q.indexOf("waiver") >= 0) return AE.BAD;
  return AE.SLATE;
}

function aeStatusTone(status) {
  const s = String(status || "").toLowerCase();
  if (s === "passed" || s === "approved" || s === "ready" || s === "ok" || s === "qual-passed") return AE.OK;
  if (s === "in-flight" || s === "in-progress" || s === "in-prep" || s === "partial" || s === "conditional" || s === "re-test") return AE.WARN;
  if (s === "fail" || s === "blocked" || s === "rejected" || s === "critical") return AE.BAD;
  if (s === "upcoming" || s === "pending") return AE.SLATE_2;
  return AE.SLATE;
}

function aeSevTone(s) {
  if (s >= 9) return AE.CRIT;
  if (s >= 7) return AE.BAD;
  if (s >= 5) return AE.WARN;
  return AE.OK;
}

function aeRpnTone(r) {
  if (r >= 100) return AE.BAD;
  if (r >= 50) return AE.WARN;
  return AE.OK;
}

function aeHash(s) {
  let h = 2166136261;
  for (let i = 0; i < (s || "").length; i++) {
    h ^= s.charCodeAt(i);
    h = (h * 16777619) >>> 0;
  }
  return h;
}

// ITAR banner — sits above the page header on every screen.
function AEItarBanner(props) {
  const segregated = props && props.segregated !== false;
  return (
    <div style={{
      ..._ae3_itarBannerBase,
      background: "linear-gradient(90deg, " + AE.INK_3 + " 0%, " + AE.INK_2 + " 100%)",
    }}>
      <span style={{ color: AE.ACCENT, fontWeight: 600 }}>ITAR</span>
      <span style={{ color: AE.SLATE_2 }}>plane</span>
      <span style={{ color: AE.MONO, fontWeight: 600 }}>aetherion-itar</span>
      <span style={{ color: AE.SLATE_2 }}>· US-persons only · S3 us-east · no MCP egress · no AI-call egress</span>
      <span style={{ marginLeft: "auto", color: segregated ? AE.OK : AE.BAD }}>
        {segregated ? "segregated" : "OPEN"}
      </span>
    </div>
  );
}

// Embedded fallbacks pulled directly from tenant-spec/space.md
const AE_SUPPLIERS_FALLBACK = [
  {
    id: "AE-SUP-01", name: "Honeybee Robotics", category: "Mechanisms · hinges",
    location: "Longmont, CO", country: "US", as9100: true, itar: true,
    heritage: "Mars 2020 SHERLOC · Lucy SA mech", trl: 9, qual: "qual-passed",
    parts: ["KESTREL-3.60.HG", "KESTREL-3.60.HG.03"], lead_time_days: 56,
    audit_score_pct: 96, last_audit: "2025-11-12",
    note: "Sole-source on solar-array hinge sub. Subject of ECO-AET-0042.",
  },
  {
    id: "AE-SUP-02", name: "ISIS · Innovative Solutions In Space",
    category: "Structure · 12U bus base",
    location: "Delft, NL", country: "NL", as9100: true, itar: false,
    heritage: "GomX-3 · NorSat-1 bus · 110+ flown structures", trl: 9,
    qual: "qual-passed", parts: ["KESTREL-3.10.01"], lead_time_days: 42,
    audit_score_pct: 94, last_audit: "2025-09-30",
    note: "EAR99 only. Drawing pull restricted to non-ITAR sub-tree.",
  },
  {
    id: "AE-SUP-03", name: "AAC Clyde Space",
    category: "Avionics · OBC + EPS",
    location: "Glasgow, UK", country: "UK", as9100: true, itar: false,
    heritage: "Sirius OBC TRL-9 · ISS-6Y · UKube-1 EPS", trl: 9,
    qual: "qual-passed", parts: ["KESTREL-3.20.01", "KESTREL-3.20.02"],
    lead_time_days: 49, audit_score_pct: 93, last_audit: "2025-10-21",
    note: "ISS-flown 6 years. OBC + EPS stack drives 8.4 W bus baseline.",
  },
  {
    id: "AE-SUP-04", name: "Sodern", category: "ADCS · star tracker",
    location: "Limeil-Brévannes, FR", country: "FR", as9100: true, itar: false,
    heritage: "Auriga CP · 60+ flown · MetOp · Pleiades", trl: 8,
    qual: "qual-passed", parts: ["KESTREL-3.30.01"], lead_time_days: 84,
    audit_score_pct: 91, last_audit: "2025-08-18",
    note: "TRL-8 in this configuration · longer lead, single-string risk.",
  },
  {
    id: "AE-SUP-05", name: "Blue Canyon Technologies",
    category: "ADCS · reaction wheels",
    location: "Boulder, CO", country: "US", as9100: true, itar: true,
    heritage: "RWp050 on TROPICS · CAPSTONE · 200+ flown", trl: 9,
    qual: "qual-passed", parts: ["KESTREL-3.30.02", "KESTREL-3.30.03", "KESTREL-3.30.04"],
    lead_time_days: 70, audit_score_pct: 95, last_audit: "2025-12-04",
    note: "Three RWp050 wheels · series qualified to flight envelope.",
  },
  {
    id: "AE-SUP-06", name: "Glenair / Amphenol",
    category: "Harness · MIL-DTL-38999",
    location: "Glendale, CA", country: "US", as9100: true, itar: true,
    heritage: "MIL-DTL-38999 series III · ISS / GPS / shuttle", trl: 9,
    qual: "qual-passed", parts: ["KESTREL-3.80.*"], lead_time_days: 35,
    audit_score_pct: 92, last_audit: "2025-11-25",
    note: "Connectors mated only after N₂ bag-and-purge >12h.",
  },
];

const AE_QUAL_ARTIFACTS_FALLBACK = [
  {
    id: "QA-MECH-VIB", name: "Vibration qual report",
    test: "vibration", spec: "Falcon 9 user guide + 3 dB margin · sine + random",
    standard: "GEVS · NASA-STD-7001", status: "passed",
    last_run: "2026-04-09", target_gate: "ACC", us_persons_only: false,
    chamber: "1500 lbf shaker · Anechoic-South",
    history: [
      { run: "VIB-AET-001", date: "2025-09-12", result: "pass", note: "Coupon level qual at GEVS+3 dB" },
      { run: "VIB-AET-002", date: "2026-01-18", result: "pass", note: "Sub-assy stack vibration · OBC+EPS" },
      { run: "VIB-AET-003", date: "2026-04-09", result: "pass", note: "Integrated vehicle · margin 3.1 dB" },
    ],
  },
  {
    id: "QA-MECH-SHK", name: "Shock survival report",
    test: "shock", spec: "pyroshock 2000 g half-sine 0.5 ms",
    standard: "MIL-STD-810H Method 516.8", status: "passed",
    last_run: "2026-04-12", target_gate: "ACC", us_persons_only: false,
    chamber: "Hopkinson bar · Aerospace-North",
    history: [
      { run: "SHK-AET-001", date: "2025-10-04", result: "pass", note: "Bracket level pyroshock · 1800 g" },
      { run: "SHK-AET-002", date: "2026-04-12", result: "pass", note: "Integrated vehicle · 2000 g half-sine 0.5 ms" },
    ],
  },
  {
    id: "QA-ENV-TVAC", name: "TVAC report",
    test: "tvac", spec: "24 cycles −40 / +85 °C · pumpdown to 1e-5 torr",
    standard: "ECSS-E-ST-10-03 · NASA-STD-7001", status: "re-test",
    last_run: "2026-04-22", target_gate: "ACC", us_persons_only: false,
    chamber: "1.5 m TVAC chamber",
    history: [
      { run: "TVAC-AET-013", date: "2025-12-08", result: "pass", note: "Sub-assy stack TVAC · 24 cycles" },
      { run: "TVAC-AET-014", date: "2026-04-22", result: "fail", note: "M3 hinge fastener pre-load loss 50 µm at cycle 14 of 24" },
      { run: "TVAC-AET-014R", date: "2026-05-28", result: "scheduled", note: "Re-test post ECO-AET-0042 · 24 cycles full" },
    ],
  },
  {
    id: "QA-EMI-EMC", name: "EMI / EMC report",
    test: "emi", spec: "MIL-STD-461G · CE / CS / RE / RS",
    standard: "MIL-STD-461G", status: "passed",
    last_run: "2026-04-15", target_gate: "ACC", us_persons_only: false,
    chamber: "Anechoic-South · 4 m × 6 m semi-anechoic",
    history: [
      { run: "EMI-AET-001", date: "2026-02-04", result: "partial", note: "RE102 marginal at 60 MHz · added overbraid" },
      { run: "EMI-AET-002", date: "2026-04-15", result: "pass", note: "Full MIL-STD-461G suite passed with 6 dB margin" },
    ],
  },
  {
    id: "QA-RAD-TID", name: "Radiation TID report",
    test: "radiation_tid",
    spec: "≥30 krad(Si) total dose · displacement damage per LEO 525 km · 5y",
    standard: "ECSS-E-ST-10-04 · MIL-STD-883 Method 1019",
    status: "passed", last_run: "2026-03-02", target_gate: "ACC",
    us_persons_only: true,  // ITAR-restricted dose envelope
    chamber: "Co-60 cell · LBNL bevatron · Ku-band",
    history: [
      { run: "RAD-AET-001", date: "2025-11-19", result: "pass", note: "Component level Co-60 sweep · 35 krad EOL" },
      { run: "RAD-AET-002", date: "2026-03-02", result: "pass", note: "Box level proton SEU/SEL · OBC + EPS clean" },
    ],
  },
  {
    id: "QA-CLEAN", name: "Cleanroom log",
    test: "cleanliness", spec: "ISO 14644-1 Class 7 entry · monthly verification",
    standard: "ISO 14644-2", status: "passed",
    last_run: "2026-05-01", target_gate: "ACC", us_persons_only: false,
    chamber: "Sunnyvale · 14 m² Class 7 cleanroom",
    history: [
      { run: "CLN-AET-Q4", date: "2025-12-30", result: "pass", note: "Q4 verification · particle count nominal" },
      { run: "CLN-AET-Q1", date: "2026-03-31", result: "pass", note: "Q1 verification · 0.5 µm count 8400 / m³" },
      { run: "CLN-AET-MAY", date: "2026-05-01", result: "pass", note: "Pre-FAB-B re-issue · particle count 7200 / m³" },
    ],
  },
];

const AE_NPI_STAGES_FALLBACK = [
  { id: "g1", code: "SRR",    name: "System Requirements Review", date: "2025-03-04", status: "passed",   actions: 7,  note: "7 actions tracked, all closed by PDR" },
  { id: "g2", code: "PDR",    name: "Preliminary Design Review",  date: "2025-06-18", status: "passed",   actions: 4,  note: "Propulsion trade study attached · cold-gas R-236fa selected" },
  { id: "g3", code: "CDR",    name: "Critical Design Review",     date: "2025-10-22", status: "passed",   actions: 2,  note: "Mass margin 11.4% · all 11 subassemblies frozen" },
  { id: "g4", code: "FAB",    name: "Fabrication",                date: "2026-01-30", status: "passed",   actions: 0,  note: "FAB-A complete · FAB-B re-issue 2026-05-05 in flight (4 hinges)" },
  { id: "g5", code: "ASSY",   name: "Assembly",                   date: "in-flight",  status: "in-flight",actions: 0,  note: "Integration ongoing on granite bench · station s2-s3" },
  { id: "g6", code: "I&T",    name: "Integration & Test",         date: "in-flight",  status: "in-flight",actions: 1,  note: "Paused for ECO-AET-0042 re-test · resumes 2026-05-29" },
  { id: "g7", code: "TVAC",   name: "Thermal-vacuum re-test",     date: "2026-05-28", status: "re-test",  actions: 1,  note: "TVAC-AET-014R · 24 cycles −40/+85 · partial pass target" },
  { id: "g8", code: "ACC",    name: "Flight acceptance",          date: "2026-07-15", status: "upcoming", actions: 0,  note: "Mission Director sign-off · CofC + qual artifact pack" },
  { id: "g9", code: "LAUNCH", name: "Launch · manifest lock",     date: "2026-09-10", status: "upcoming", actions: 0,  note: "Falcon 9 Transporter-15 · sun-sync LEO 525 km dawn-dusk" },
];

// PFMEA tied to ECO-AET-0042 hinge fastener.
const AE_PFMEA_FALLBACK = [
  {
    id: "PF-001",
    item: "M3 fastener · solar-array hinge HG-03",
    function: "Retain hinge under TVAC cycling",
    mode: "Pre-load loss > 50 µm at -40 °C cold soak",
    effect: "Hinge mechanism backlash · array deploy mis-pointing",
    cause: "M3 A2-70 fatigue at -40 °C · single Nord-Lock washer insufficient",
    S: 9, O: 6, D: 4, RPN: 216,
    current_control: "Strain-gauge logging during TVAC · QG-AET-22",
    recommended_action: "ECO-AET-0042 · A2-70 → A286 + 4× DIN 2093 Belleville stack",
    owner: "M. Sato · Mech Lead",
    eco_link: "ECO-AET-0042",
    station: "s4",
    target_S: 9, target_O: 2, target_D: 2, target_RPN: 36,
  },
  {
    id: "PF-002",
    item: "Solar-array deploy spring · HG-03",
    function: "Deploy array within 0.45 s window",
    mode: "Deploy timing slip > 100 ms",
    effect: "Sun acquisition delay · 1 orbit power deficit",
    cause: "Spring constant drift after thermal cycling",
    S: 7, O: 3, D: 5, RPN: 105,
    current_control: "Vacuum-deploy rig timing test · QG-AET-19",
    recommended_action: "Add post-TVAC deploy timing audit per build · QG-AET-19R",
    owner: "M. Sato · Mech Lead",
    eco_link: "—",
    station: "s3",
    target_S: 7, target_O: 2, target_D: 3, target_RPN: 42,
  },
  {
    id: "PF-003",
    item: "Star tracker · Auriga CP boresight",
    function: "Maintain ≤25 µm alignment at 2 m to imager focal plane",
    mode: "Boresight drift > 50 µm post-vibration",
    effect: "Imager mis-pointing · GSD degradation > 1.2 m",
    cause: "Stress relief in mounting bracket weld at random vibe",
    S: 8, O: 3, D: 4, RPN: 96,
    current_control: "Leica AT960 laser tracker pre/post vibe · QG-AET-15",
    recommended_action: "Add vibration soak at 110% Falcon-9 envelope before integration",
    owner: "Y. Patel · Optics",
    eco_link: "—",
    station: "s3",
    target_S: 8, target_O: 2, target_D: 3, target_RPN: 48,
  },
  {
    id: "PF-004",
    item: "MIL-DTL-38999 connector · J-OBC-04",
    function: "Maintain electrical continuity after mating",
    mode: "Pin mate-demate cycle wear > 200 cycles",
    effect: "Intermittent OBC bus fault on telemetry uplink",
    cause: "Glenair gold flash plating thinning at flight pin set",
    S: 6, O: 4, D: 3, RPN: 72,
    current_control: "Mate counter logged per CofC · max 50 cycles flight pinset",
    recommended_action: "Switch to 38999-series-III nickel pinset for flight harness",
    owner: "K. Nair · EE",
    eco_link: "—",
    station: "s2",
    target_S: 6, target_O: 2, target_D: 2, target_RPN: 24,
  },
  {
    id: "PF-005",
    item: "X-band downlink TX module · 50 Mbps",
    function: "Transmit 1 m-GSD payload data over Ka contact",
    mode: "TX power droop > 1 dB after 6 months on-orbit",
    effect: "Downlink margin loss · contact time penalty 8 min/pass",
    cause: "PA gallium-nitride junction temp creep at 32 W payload load",
    S: 7, O: 4, D: 4, RPN: 112,
    current_control: "Bench burn-in 168 h at +85 °C · QG-AET-29",
    recommended_action: "Add aerogel-backed heatsink + +5 dB margin allocation",
    owner: "S. Vasquez · Comms",
    eco_link: "—",
    station: "s4",
    target_S: 7, target_O: 2, target_D: 3, target_RPN: 42,
  },
  {
    id: "PF-006",
    item: "Cold-gas thruster · R-236fa propellant valve",
    function: "Open / close 30 m/s deorbit burn",
    mode: "Valve leak-by > 5 sccm in vacuum",
    effect: "Delta-v budget breach · deorbit slip > 90 days",
    cause: "PTFE seat extrusion at + 60 °C tank pressure",
    S: 8, O: 2, D: 5, RPN: 80,
    current_control: "He leak check at +60 °C bake · QG-AET-26",
    recommended_action: "Switch to Vespel SP-1 seat · re-qualify at +85 °C",
    owner: "M. Sato · Mech Lead",
    eco_link: "—",
    station: "s4",
    target_S: 8, target_O: 1, target_D: 4, target_RPN: 32,
  },
  {
    id: "PF-007",
    item: "Battery 80 Wh Li-ion 8s2p",
    function: "Provide 28 V bus during eclipse 38 min",
    mode: "Cell imbalance > 50 mV after 1 year cycling",
    effect: "Eclipse capacity loss · bus brownout risk",
    cause: "BMS drift on cells C3 / C7 at low SoC corner",
    S: 6, O: 5, D: 4, RPN: 120,
    current_control: "Pack-level cell balance log on every charge · QG-AET-23",
    recommended_action: "Tighten BMS drift threshold 50 → 25 mV · alarm to OBC",
    owner: "K. Nair · EE",
    eco_link: "—",
    station: "s2",
    target_S: 6, target_O: 2, target_D: 3, target_RPN: 36,
  },
  {
    id: "PF-008",
    item: "Reaction wheel RWp050 · RW-Y axis",
    function: "Provide 50 mNm torque pointing about Y",
    mode: "Bearing micro-vibration > 2 mNm 1σ",
    effect: "Image smear at GSD 1 m · MTF loss > 12%",
    cause: "Bearing pre-load shift after launch shock",
    S: 7, O: 3, D: 5, RPN: 105,
    current_control: "Post-shock micro-vibe characterisation · QG-AET-24",
    recommended_action: "Add active jitter compensation in star-tracker loop",
    owner: "Y. Patel · Optics",
    eco_link: "—",
    station: "s3",
    target_S: 7, target_O: 2, target_D: 3, target_RPN: 42,
  },
];

// AS9100 audit template — used by ScreenAetherionVendorOnboard.
const AE_AUDIT_TEMPLATE_FALLBACK = {
  name: "AS9100 + ITAR vendor qualification",
  rev: "Rev D · 2026-01",
  tabs: [
    {
      tab: "AS9100 cert",
      criteria: [
        { id: "AS-01", text: "AS9100 Rev D certificate active and unexpired" },
        { id: "AS-02", text: "Last surveillance audit ≤ 12 months · no major NCRs open" },
        { id: "AS-03", text: "Counterfeit parts mitigation per AS5553" },
        { id: "AS-04", text: "FOD program per NAS 412 · monthly walkdown logged" },
        { id: "AS-05", text: "FAI per AS9102 Rev B for first article on qualified line" },
      ],
    },
    {
      tab: "ITAR registration",
      criteria: [
        { id: "IT-01", text: "DDTC registration current · M-number on file" },
        { id: "IT-02", text: "TAA / MLA agreements covering KESTREL-3 scope" },
        { id: "IT-03", text: "Empowered Official designated · trained" },
        { id: "IT-04", text: "Drawing pull control · US-persons-only review log" },
        { id: "IT-05", text: "Foreign-person screening at gate · I-9 + visa class" },
      ],
    },
    {
      tab: "Heritage docs",
      criteria: [
        { id: "HR-01", text: "TRL evidence package · prior flight unit references" },
        { id: "HR-02", text: "Lessons-learned summary from latest 3 missions" },
        { id: "HR-03", text: "Failure-mode history · in-service anomaly log" },
        { id: "HR-04", text: "Cross-program reuse statement · ESCC / NASA-PEM equivalence" },
      ],
    },
    {
      tab: "Qualification artifacts",
      criteria: [
        { id: "QA-01", text: "Mech qual report · vibration sine + random per GEVS" },
        { id: "QA-02", text: "TVAC report · ≥ 24 cycles −40 / +85 °C" },
        { id: "QA-03", text: "EMI / EMC per MIL-STD-461G CE/CS/RE/RS" },
        { id: "QA-04", text: "Radiation TID ≥ 30 krad(Si) per ECSS-E-ST-10-04" },
        { id: "QA-05", text: "Shock survival 2000 g half-sine 0.5 ms" },
        { id: "QA-06", text: "EEE parts derating per ECSS-Q-ST-70" },
        { id: "QA-07", text: "Cleanroom log · ISO 14644 Class 7 monthly verification" },
      ],
    },
  ],
};

// Tenant slice resolver. Returns {tenant, suppliers, qual, npi, pfmea, audit_template}.
function useAeResolve() {
  const tenant = useActiveTenant();
  const isAe = tenant && (tenant.tenant && tenant.tenant.id === "aetherion" ||
                          tenant.id === "aetherion" ||
                          (tenant.tenant && tenant.tenant.id === "htu220"));
  const itar = tenant && (tenant.compliance && tenant.compliance.itar) ||
               tenant && (tenant.itar === true) || isAe || true;
  return {
    tenant: tenant,
    isAe: !!isAe,
    itar: !!itar,
    suppliers: (tenant && Array.isArray(tenant.aetherion_suppliers) && tenant.aetherion_suppliers.length)
      ? tenant.aetherion_suppliers
      : (isAe && Array.isArray(tenant.suppliers) && tenant.suppliers.length && tenant.suppliers[0].heritage)
        ? tenant.suppliers
        : AE_SUPPLIERS_FALLBACK,
    qual_artifacts: (tenant && Array.isArray(tenant.qual_artifacts) && tenant.qual_artifacts.length)
      ? tenant.qual_artifacts : AE_QUAL_ARTIFACTS_FALLBACK,
    npi: (tenant && Array.isArray(tenant.npi_stages) && tenant.npi_stages.length)
      ? tenant.npi_stages
      : (tenant && Array.isArray(tenant.lifecycle) && tenant.lifecycle.length === 9)
        ? tenant.lifecycle : AE_NPI_STAGES_FALLBACK,
    pfmea: (tenant && Array.isArray(tenant.pfmea) && tenant.pfmea.length && tenant.pfmea[0].eco_link)
      ? tenant.pfmea : AE_PFMEA_FALLBACK,
    audit_template: (tenant && tenant.aetherion_audit_template)
      ? tenant.aetherion_audit_template
      : (tenant && tenant.vendor_audit_template && /AS9100|ITAR/i.test(tenant.vendor_audit_template.name || ""))
        ? tenant.vendor_audit_template : AE_AUDIT_TEMPLATE_FALLBACK,
  };
}

// ─────────────────────────────────────────────────── ScreenAetherionSuppliers
function ScreenAetherionSuppliers() {
  const slice = useAeResolve();
  const suppliers = slice.suppliers;

  const [trlFilter, setTrlFilter] = uSAE3("all");      // all | 6 | 7 | 8 | 9
  const [itarFilter, setItarFilter] = uSAE3("all");    // all | itar | non-itar
  const [maxLead, setMaxLead] = uSAE3(120);
  const [hovered, setHovered] = uSAE3(null);

  uEAE3(function () {
    if (typeof window === "undefined") return;
    function onTenantChange() {
      setTrlFilter("all"); setItarFilter("all"); setMaxLead(120); setHovered(null);
    }
    window.addEventListener("forge:tenant-change", onTenantChange);
    return function () { window.removeEventListener("forge:tenant-change", onTenantChange); };
  }, []);

  const filtered = suppliers.filter(function (s) {
    if (trlFilter !== "all" && Number(s.trl) !== Number(trlFilter)) return false;
    if (itarFilter === "itar" && !s.itar) return false;
    if (itarFilter === "non-itar" && s.itar) return false;
    if (s.lead_time_days > maxLead) return false;
    return true;
  });

  function openQual(s) {
    if (typeof window !== "undefined") window.__aeQualSupplierId = s.id;
    if (typeof navigate === "function") navigate("/forge/audit");
  }

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

  return (
    <div style={root}>
      <AEItarBanner />

      {/* header */}
      <div style={{ display: "flex", alignItems: "baseline", justifyContent: "space-between", marginBottom: 14 }}>
        <div>
          <div style={aeMono({ marginBottom: 4, color: AE.ACCENT })}>forge:// suppliers</div>
          <div style={{ fontFamily: AE.FONT_SER, fontSize: 26, letterSpacing: "-0.01em", color: AE.MONO }}>
            Flight-heritage supplier panel
          </div>
          <div style={{ color: AE.SLATE, fontSize: 12, marginTop: 4 }}>
            {suppliers.length} qualified · {filtered.length} shown · KESTREL-3 sub-supplier file
          </div>
        </div>
        <button
          onClick={function () { if (typeof navigate === "function") navigate("/forge/vendor-onboard"); }}
          style={_ae3_primaryBtnBase}>
          + Qualify new supplier
        </button>
      </div>

      {/* filter bar */}
      <div style={Object.assign(aeCard({ marginBottom: 16 }),
                                { display: "flex", gap: 18, alignItems: "center", flexWrap: "wrap" })}>
        <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
          <span style={aeMono()}>TRL</span>
          {["all", "6", "7", "8", "9"].map(function (v) {
            const active = trlFilter === v;
            const tone = v === "9" ? AE.OK : v === "8" ? AE.ACCENT : v === "7" ? AE.WARN : v === "6" ? AE.WARN : AE.SLATE;
            return (
              <button key={v}
                onClick={function () { setTrlFilter(v); }}
                style={{
                  ..._ae3_chipBase,
                  border: "1px solid " + (active ? tone : AE.LINE),
                  background: active ? tone : AE.INK_3,
                  color: active ? AE.INK : AE.MONO,
                }}>{v === "all" ? "all" : "TRL-" + v}</button>
            );
          })}
        </div>
        <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
          <span style={aeMono()}>ITAR</span>
          {[["all", "all"], ["itar", "ITAR"], ["non-itar", "EAR99"]].map(function (pair) {
            const k = pair[0], l = pair[1], active = itarFilter === k;
            return (
              <button key={k}
                onClick={function () { setItarFilter(k); }}
                style={{
                  ..._ae3_chipBase,
                  border: "1px solid " + (active ? AE.ACCENT : AE.LINE),
                  background: active ? AE.ACCENT : AE.INK_3,
                  color: active ? AE.INK : AE.MONO,
                }}>{l}</button>
            );
          })}
        </div>
        <div style={{ display: "flex", alignItems: "center", gap: 8, minWidth: 260 }}>
          <span style={aeMono()}>Lead-time ≤</span>
          <input id="ae-act3-f1" name="ae-act3-f1" type="range" min="14" max="120" value={maxLead}
            onChange={function (e) { setMaxLead(parseInt(e.target.value, 10)); }}
            style={{ flex: 1, accentColor: AE.ACCENT }} />
          <span style={{ fontFamily: AE.FONT_MONO, fontSize: 12, color: AE.MONO, minWidth: 48 }}>{maxLead}d</span>
        </div>
        <div style={{ flex: 1 }} />
        <span style={{ fontFamily: AE.FONT_MONO, fontSize: 12, color: AE.SLATE_2 }}>
          ECO-AET-0042 sole-source: Honeybee Robotics
        </span>
      </div>

      <div style={{ display: "grid", gridTemplateColumns: "1fr 280px", gap: 18 }}>
        {/* supplier cards */}
        <div>
          <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fill, minmax(280px, 1fr))", gap: 12 }}>
            {filtered.map(function (s) {
              const qualTone = aeQualTone("trl-" + s.trl);
              return (
                <div key={s.id}
                  role="button"
                  tabIndex={0}
                  onClick={function () { openQual(s); }}
                  onKeyDown={function (e) { if (e.key === "Enter" || e.key === " ") { e.preventDefault(); openQual(s); } }}
                  onMouseEnter={function () { setHovered(s.id); }}
                  onMouseLeave={function () { setHovered(null); }}
                  style={Object.assign(aeCard({
                    cursor: "pointer",
                    transition: "transform .12s, box-shadow .12s, border-color .12s",
                    borderColor: hovered === s.id ? AE.ACCENT : AE.LINE,
                    boxShadow: hovered === s.id ? "0 6px 18px rgba(79,143,255,0.12)" : "none",
                    transform: hovered === s.id ? "translateY(-1px)" : "translateY(0)",
                  }))}>
                  <div style={{ display: "flex", justifyContent: "space-between", alignItems: "flex-start", marginBottom: 8 }}>
                    <div>
                      <div style={aeMono({ marginBottom: 3, color: AE.SLATE_2 })}>{s.id}</div>
                      <div style={{ fontWeight: 600, fontSize: 14, color: AE.MONO }}>{s.name}</div>
                    </div>
                    {aePill("TRL-" + s.trl, qualTone)}
                  </div>
                  <div style={{ fontSize: 12, color: AE.SLATE, marginBottom: 8, minHeight: 32 }}>
                    {s.category}
                  </div>
                  <div style={{ display: "flex", gap: 6, marginBottom: 10, flexWrap: "wrap" }}>
                    {s.itar ? aePill("ITAR", AE.ACCENT) : aePill("EAR99", AE.SLATE_2)}
                    {s.as9100 ? aePill("AS9100", AE.OK) : aePill("AS9100·gap", AE.BAD)}
                    {aePill(s.country, AE.SLATE_2)}
                  </div>
                  <div style={_ae3_heritageNoteBase}>
                    heritage · {s.heritage}
                  </div>
                  <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginTop: 8 }}>
                    <div>
                      <div style={aeMono()}>Audit score</div>
                      <div style={{
                        fontFamily: AE.FONT_MONO, fontSize: 18,
                        color: s.audit_score_pct >= 92 ? AE.OK : s.audit_score_pct >= 85 ? AE.WARN : AE.BAD,
                        fontWeight: 600,
                      }}>{s.audit_score_pct}%</div>
                    </div>
                    <div>
                      <div style={aeMono()}>Lead-time</div>
                      <div style={{ fontFamily: AE.FONT_MONO, fontSize: 13, color: AE.MONO }}>
                        {s.lead_time_days}<span style={{ color: AE.SLATE }}>d</span>
                      </div>
                    </div>
                  </div>
                  <div style={_ae3_supplierFooterBase}>
                    <span>{s.location}</span>
                    <span>last audit · {s.last_audit}</span>
                  </div>
                  {s.note ? (
                    <div style={{ marginTop: 8, fontSize: 12, color: AE.WARN, lineHeight: 1.45 }}>
                      note · {s.note}
                    </div>
                  ) : null}
                  <div style={_ae3_partsLineBase}>
                    parts · {(s.parts || []).join(" · ")}
                  </div>
                </div>
              );
            })}
            {filtered.length === 0 ? (
              <div style={Object.assign(aeCard(), { gridColumn: "1 / -1", textAlign: "center", color: AE.SLATE })}>
                No flight-heritage suppliers match the current filter.
              </div>
            ) : null}
          </div>
        </div>

        {/* right rail */}
        <div>
          <div style={aeCard()}>
            <div style={aeMono({ marginBottom: 8 })}>Qualify new supplier</div>
            <div style={{ fontSize: 12, color: AE.SLATE, marginBottom: 10, lineHeight: 1.5 }}>
              Run the AS9100 + ITAR vendor qualification protocol. Qualification artifacts (mech qual,
              TVAC, EMI, TID) attach to the supplier file before any flight pull.
            </div>
            <button
              onClick={function () { if (typeof navigate === "function") navigate("/forge/vendor-onboard"); }}
              style={_ae3_qualifyBtnFull}>
              Start onboarding wizard →
            </button>
          </div>

          <div style={Object.assign(aeCard({ marginTop: 12 }), {})}>
            <div style={aeMono({ marginBottom: 8 })}>Risk concentrations</div>
            <div style={{ fontSize: 12 }}>
              {[
                { k: "Hinges", v: "1 source", tone: AE.BAD, note: "Honeybee · ECO-AET-0042" },
                { k: "Star tracker", v: "1 source", tone: AE.WARN, note: "Sodern · single string" },
                { k: "OBC + EPS", v: "1 source", tone: AE.WARN, note: "AAC Clyde · ISS heritage" },
                { k: "Reaction wheels", v: "1 source", tone: AE.WARN, note: "BCT · series qual" },
                { k: "Harness", v: "1 source", tone: AE.OK,   note: "Glenair · 38999 family" },
                { k: "Structure", v: "1 source", tone: AE.OK,   note: "ISIS · TRL-9 bus" },
              ].map(function (r) {
                return (
                  <div key={r.k} style={{
                    display: "flex", justifyContent: "space-between", alignItems: "center",
                    padding: "5px 0", borderBottom: "1px solid " + AE.LINE_SOFT,
                  }}>
                    <div>
                      <div style={{ color: AE.MONO }}>{r.k}</div>
                      <div style={{ fontSize: 12, color: AE.SLATE_2, fontFamily: AE.FONT_MONO, marginTop: 2 }}>{r.note}</div>
                    </div>
                    <span style={{ fontFamily: AE.FONT_MONO, color: r.tone, fontSize: 12 }}>{r.v}</span>
                  </div>
                );
              })}
            </div>
          </div>

          <div style={Object.assign(aeCard({ marginTop: 12 }), { background: AE.INK_3 })}>
            <div style={aeMono({ marginBottom: 6 })}>Supplier control · 8.4.3</div>
            <div style={{ fontSize: 12, color: AE.SLATE, lineHeight: 1.5 }}>
              AS9100 8.4.3 supplier control file is maintained per sub-supplier:
              Honeybee, ISIS, AAC Clyde, Sodern, BCT, Glenair. Re-audit cadence
              annual · waiver requires Mission Director sign-off.
            </div>
          </div>

          <div style={Object.assign(aeCard({ marginTop: 12 }), { background: AE.INK_3 })}>
            <div style={aeMono({ marginBottom: 6 })}>Audits due (90d)</div>
            {suppliers.slice(0, 5).map(function (s, i) {
              const due = ["28d", "44d", "61d", "73d", "88d"][i] || "90d+";
              return (
                <div key={s.id} style={{
                  display: "flex", justifyContent: "space-between",
                  padding: "5px 0", fontSize: 12,
                  borderBottom: i < 4 ? "1px solid " + AE.LINE_SOFT : "0",
                }}>
                  <span style={{ color: AE.MONO }}>{s.name}</span>
                  <span style={{ fontFamily: AE.FONT_MONO, fontSize: 12, color: AE.SLATE_2 }}>{due}</span>
                </div>
              );
            })}
          </div>
        </div>
      </div>
    </div>
  );
}

// ──────────────────────────────────────────────── ScreenAetherionVendorOnboard
function ScreenAetherionVendorOnboard() {
  const slice = useAeResolve();
  const tmpl = slice.audit_template;

  const [activeTab, setActiveTab] = uSAE3(0);
  const [scores, setScores] = uSAE3(function () {
    const init = {};
    if (!tmpl) return init;
    tmpl.tabs.forEach(function (t) {
      t.criteria.forEach(function (c) { init[c.id] = -1; });
    });
    return init;
  });
  const [notes, setNotes] = uSAE3({});
  const [vendorName, setVendorName] = uSAE3("");
  const [usPersonsCount, setUsPersonsCount] = uSAE3(8);
  const [flash, setFlash] = uSAE3(null);
  const flashTimer = uRAE3(null);

  uEAE3(function () {
    return function () {
      if (flashTimer.current) { clearTimeout(flashTimer.current); flashTimer.current = null; }
    };
  }, []);

  uEAE3(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: AE.FONT_UI, color: AE.SLATE, background: AE.INK, minHeight: "100%" }}>
        AS9100 + ITAR audit template not loaded.
      </div>
    );
  }

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

  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 itarTab = tmpl.tabs[1];
  const itarScore = itarTab ? tabScore(itarTab) : null;
  const itarGate = itarScore === 100;
  const as9100Tab = tmpl.tabs[0];
  const as9100Score = as9100Tab ? tabScore(as9100Tab) : null;
  const as9100Gate = as9100Score != null && as9100Score >= 80;

  function fireFlash(msg) {
    setFlash(msg);
    if (flashTimer.current) clearTimeout(flashTimer.current);
    flashTimer.current = setTimeout(function () {
      flashTimer.current = null;
      setFlash(null);
    }, 1800);
  }

  function onSubmit() {
    // W14B/W15C — persist scorecard via forgeApi.mutate before flash+nav. The
    // server's JSON-patch-lite uses positional paths (canonical 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 retained as a defensive guardrail.
    const slug = (vendorName || "unnamed").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || "unnamed";
    const u = (typeof window !== "undefined") ? window.__forgeCurrentUser : null;
    const actor = (u && u.name) || "—";
    const scorecard = {
      vendor_name: vendorName || "Unnamed vendor",
      overall_pct: overall || 0,
      itar_gate_cleared: !!itarGate,
      as9100_gate_cleared: !!as9100Gate,
      us_persons_count: usPersonsCount,
      scores: scores, notes: notes,
      audited_by: actor,
      submitted_at: Date.now(),
    };
    const suppliersArr = (slice.tenant && slice.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: scorecard }
      : { op: "add",     path: "/-",                          value: { id: slug, name: vendorName || "Unnamed vendor", status: "conditional", audit_scorecard: scorecard } };
    const queuedOk = function (err) { return err && (err.status === 404 || err.status === 400); };
    if (typeof window !== "undefined" && window.forgeApi && typeof window.forgeApi.mutate === "function") {
      window.forgeApi.mutate("suppliers", patch).then(function () {
        fireFlash("Vendor file saved · " + (vendorName || "unnamed") + " · " + (overall || 0) + "% overall " +
                  (itarGate ? "(ITAR gate cleared)" : "(ITAR < 100%, conditional only)"));
      }).catch(function (err) {
        if (queuedOk(err)) {
          fireFlash("Vendor file queued · " + (vendorName || "unnamed") + " · " + (overall || 0) + "% overall " +
                    (itarGate ? "(ITAR gate cleared)" : "(ITAR < 100%, conditional only)"));
        } else {
          fireFlash("Save failed · " + (err && err.message || "unknown"));
        }
      });
    } else {
      fireFlash("Vendor file saved · " + (vendorName || "unnamed") + " · " + (overall || 0) + "% overall " +
                (itarGate ? "(ITAR gate cleared)" : "(ITAR < 100%, conditional only)"));
    }
    if (typeof navigate === "function") {
      setTimeout(function () { navigate("/forge/suppliers"); }, 1300);
    }
  }

  function scoreColor(pct) {
    if (pct == null) return AE.SLATE_2;
    if (pct >= 90) return AE.OK;
    if (pct >= 75) return AE.WARN;
    return AE.BAD;
  }

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

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

  return (
    <div style={root}>
      <AEItarBanner />

      <div style={{ display: "flex", alignItems: "baseline", justifyContent: "space-between", marginBottom: 14 }}>
        <div>
          <div style={aeMono({ marginBottom: 4, color: AE.ACCENT })}>forge:// vendor-onboard · {tmpl.name}</div>
          <div style={{ fontFamily: AE.FONT_SER, fontSize: 26, letterSpacing: "-0.01em", color: AE.MONO }}>
            Vendor onboarding · {tmpl.rev}
          </div>
          <div style={{ color: AE.SLATE, fontSize: 12, marginTop: 4 }}>
            Score 0–3 on each criterion. ITAR axis must be 100% to advance to approved status.
          </div>
        </div>
        <button
          onClick={function () { if (typeof navigate === "function") navigate("/forge/suppliers"); }}
          style={_ae3_backBtn}>
          ← Back to suppliers
        </button>
      </div>

      {/* vendor identity */}
      <div style={Object.assign(aeCard({ marginBottom: 16 }),
                                { display: "grid", gridTemplateColumns: "1.2fr 0.8fr 0.8fr 0.8fr 0.8fr", gap: 16 })}>
        <div>
          <div style={aeMono({ marginBottom: 4 })}>Vendor</div>
          <input id="ae-act3-f2" name="ae-act3-f2" aria-label="e.g. Maxar Technologies" value={vendorName} onChange={function (e) { setVendorName(e.target.value); }}
            placeholder="e.g. Maxar Technologies"
            style={{ ..._ae3_inputBase, fontFamily: AE.FONT_UI }} />
        </div>
        <div>
          <div style={aeMono({ marginBottom: 4 })}>US-persons</div>
          <input id="ae-act3-f3" name="ae-act3-f3" type="number" value={usPersonsCount}
            onChange={function (e) { setUsPersonsCount(parseInt(e.target.value, 10) || 0); }}
            min="0" max="9999"
            style={{ ..._ae3_inputBase, fontFamily: AE.FONT_MONO }} />
        </div>
        <div>
          <div style={aeMono({ marginBottom: 4 })}>Auditor</div>
          <div style={{ fontSize: 13, color: AE.MONO, fontFamily: AE.FONT_UI }}>K. Mehta · Q&MA</div>
        </div>
        <div>
          <div style={aeMono({ marginBottom: 4 })}>Date</div>
          <div style={{ fontSize: 13, fontFamily: AE.FONT_MONO, color: AE.MONO }}>2026-05-09Z</div>
        </div>
        <div>
          <div style={aeMono({ marginBottom: 4 })}>Protocol revision</div>
          <div style={{ fontSize: 13, fontFamily: AE.FONT_MONO, color: AE.MONO }}>{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: scoreColor(ts), fontWeight: 600 }}>
                {ts == null ? "—" : ts + "%"}
              </span>
              <span style={{ marginLeft: 6, color: AE.SLATE_2 }}>({t.criteria.length})</span>
            </button>
          );
        })}
      </div>

      {/* tab body */}
      <div style={{
        background: AE.INK_2, border: "1px solid " + AE.LINE, borderTop: 0,
        borderRadius: "0 0 4px 4px", padding: 18, marginBottom: 20,
      }}>
        <div style={{ marginBottom: 12, color: AE.SLATE, fontSize: 12 }}>
          {tmpl.tabs[activeTab].tab} · {tmpl.tabs[activeTab].criteria.length} criteria.
          Score 0 = absent, 1 = partial, 2 = adequate, 3 = best-in-class.
          {activeTab === 1 ? " · ITAR axis must be 100% before approved status." : ""}
          {activeTab === 3 ? " · Qualification artifacts attach to the supplier file as PDF + JSON manifest." : ""}
        </div>
        <div>
          {tmpl.tabs[activeTab].criteria.map(function (c, idx) {
            const cur = scores[c.id];
            return (
              <div key={c.id} style={{
                ..._ae3_criteriaRowBase,
                borderBottom: idx < tmpl.tabs[activeTab].criteria.length - 1
                  ? "1px solid " + AE.LINE_SOFT : "0",
              }}>
                <span style={{ fontFamily: AE.FONT_MONO, color: AE.SLATE_2, fontSize: 12 }}>{c.id}</span>
                <span style={{ fontSize: 13, color: AE.MONO }}>{c.text}</span>
                <div style={{ display: "flex", gap: 4 }}>
                  {[0, 1, 2, 3].map(function (v) {
                    const sel = cur === v;
                    const palette = [AE.BAD, AE.WARN, AE.ACCENT_DIM, AE.OK];
                    return (
                      <button key={v} onClick={function () { setScore(c.id, v); }}
                        style={{
                          ..._ae3_scoreBtnBase,
                          border: "1px solid " + (sel ? palette[v] : AE.LINE),
                          background: sel ? palette[v] : AE.INK_3,
                          color: sel ? AE.INK : AE.MONO,
                        }}>{v}</button>
                    );
                  })}
                </div>
                <input id="ae-act3-f4" name="ae-act3-f4" aria-label="evidence ref / note…" value={notes[c.id] || ""} onChange={function (e) { setNote(c.id, e.target.value); }}
                  placeholder="evidence ref / note…"
                  style={{
                    padding: "6px 8px", border: "1px solid " + AE.LINE,
                    background: AE.INK_3, fontSize: 12, fontFamily: AE.FONT_UI,
                    color: AE.MONO, borderRadius: 3,
                  }} />
                <div tabIndex={-1} aria-hidden="true" style={_ae3_dropFileBase}>drop file</div>
              </div>
            );
          })}
        </div>
      </div>

      {/* summary cards row */}
      <div style={{ display: "grid", gridTemplateColumns: "repeat(4, 1fr)", gap: 12, marginBottom: 20 }}>
        <div style={Object.assign(aeCard(), {})}>
          <div style={aeMono({ marginBottom: 6 })}>AS9100 cert · 8.1.1</div>
          <div style={{
            fontFamily: AE.FONT_MONO, fontSize: 22, fontWeight: 700,
            color: scoreColor(as9100Score),
          }}>{as9100Score == null ? "—" : as9100Score + "%"}</div>
          <div style={{ fontSize: 12, color: AE.SLATE, marginTop: 4 }}>
            {as9100Gate ? aePill("cert · valid", AE.OK) : aePill("cert · review", AE.WARN)}
          </div>
        </div>
        <div style={Object.assign(aeCard(), {})}>
          <div style={aeMono({ marginBottom: 6 })}>ITAR registration</div>
          <div style={{
            fontFamily: AE.FONT_MONO, fontSize: 22, fontWeight: 700,
            color: scoreColor(itarScore),
          }}>{itarScore == null ? "—" : itarScore + "%"}</div>
          <div style={{ fontSize: 12, color: AE.SLATE, marginTop: 4 }}>
            {itarGate ? aePill("itar gate · cleared", AE.OK) : aePill("itar gate · open", AE.BAD)}
          </div>
        </div>
        <div style={Object.assign(aeCard(), {})}>
          <div style={aeMono({ marginBottom: 6 })}>Heritage docs</div>
          <div style={{
            fontFamily: AE.FONT_MONO, fontSize: 22, fontWeight: 700,
            color: scoreColor(tabScore(tmpl.tabs[2])),
          }}>{tabScore(tmpl.tabs[2]) == null ? "—" : tabScore(tmpl.tabs[2]) + "%"}</div>
          <div style={{ fontSize: 12, color: AE.SLATE, marginTop: 4 }}>
            TRL evidence + flight history
          </div>
        </div>
        <div style={Object.assign(aeCard(), {})}>
          <div style={aeMono({ marginBottom: 6 })}>Qual artifacts</div>
          <div style={{
            fontFamily: AE.FONT_MONO, fontSize: 22, fontWeight: 700,
            color: scoreColor(tabScore(tmpl.tabs[3])),
          }}>{tabScore(tmpl.tabs[3]) == null ? "—" : tabScore(tmpl.tabs[3]) + "%"}</div>
          <div style={{ fontSize: 12, color: AE.SLATE, marginTop: 4 }}>
            mech / TVAC / EMI / TID / shock / EEE / clean
          </div>
        </div>
      </div>

      {/* sticky footer */}
      <div style={_ae3_stickyFooter}>
        <div style={{ display: "flex", gap: 22 }}>
          {tmpl.tabs.map(function (t) {
            const ts = tabScore(t);
            return (
              <div key={t.tab}>
                <div style={aeMono()}>{t.tab.split(" ")[0]}</div>
                <div style={{
                  fontFamily: AE.FONT_MONO, fontSize: 18, fontWeight: 600,
                  color: scoreColor(ts),
                }}>{ts == null ? "—" : ts + "%"}</div>
              </div>
            );
          })}
          <div style={{ borderLeft: "1px solid " + AE.LINE, paddingLeft: 22 }}>
            <div style={aeMono()}>Overall</div>
            <div style={{
              fontFamily: AE.FONT_MONO, fontSize: 22, fontWeight: 700,
              color: scoreColor(overall),
            }}>{overall == null ? "—" : overall + "%"}</div>
          </div>
          <div style={{ paddingLeft: 22, alignSelf: "center" }}>
            {itarScore == null ? aePill("itar · not scored", AE.SLATE_2) :
              (itarGate ? aePill("itar · cleared", AE.OK) : aePill("itar · " + itarScore + "%", AE.BAD))}
          </div>
        </div>
        <div style={{ display: "flex", gap: 10 }}>
          <button onClick={function () { if (typeof navigate === "function") navigate("/forge/suppliers"); }}
            style={_ae3_cancelBtn}>Cancel</button>
          <button onClick={onSubmit}
            disabled={overall == null}
            style={{
              ..._ae3_saveBtnBase,
              background: overall == null ? AE.SLATE_2 : AE.ACCENT,
              cursor: overall == null ? "not-allowed" : "pointer",
            }}>Save vendor file →</button>
        </div>
      </div>

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

// ──────────────────────────────────────────────── ScreenAetherionQualReview
function ScreenAetherionQualReview() {
  const slice = useAeResolve();
  const artifacts = slice.qual_artifacts;

  const [active, setActive] = uSAE3(artifacts && artifacts[0] ? artifacts[0].id : null);
  const [usPerson, setUsPerson] = uSAE3(true);
  const [filter, setFilter] = uSAE3("all");      // all | passed | re-test | scheduled
  const [flash, setFlash] = uSAE3(null);
  const flashTimer = uRAE3(null);

  uEAE3(function () {
    return function () {
      if (flashTimer.current) { clearTimeout(flashTimer.current); flashTimer.current = null; }
    };
  }, []);

  uEAE3(function () {
    if (typeof window === "undefined") return;
    function onTenantChange() {
      setActive(artifacts && artifacts[0] ? artifacts[0].id : null);
      setFilter("all"); setFlash(null);
    }
    window.addEventListener("forge:tenant-change", onTenantChange);
    return function () { window.removeEventListener("forge:tenant-change", onTenantChange); };
  }, [artifacts]);

  function fireFlash(msg) {
    setFlash(msg);
    if (flashTimer.current) clearTimeout(flashTimer.current);
    flashTimer.current = setTimeout(function () { flashTimer.current = null; setFlash(null); }, 1600);
  }

  const visible = artifacts.filter(function (a) {
    if (filter === "all") return true;
    return a.status === filter;
  });

  const activeArtifact = artifacts.find(function (a) { return a.id === active; }) || artifacts[0];

  // run history rollup
  const rollup = uMAE3(function () {
    let pass = 0, fail = 0, partial = 0, scheduled = 0;
    artifacts.forEach(function (a) {
      (a.history || []).forEach(function (h) {
        if (h.result === "pass") pass++;
        else if (h.result === "fail") fail++;
        else if (h.result === "partial") partial++;
        else if (h.result === "scheduled") scheduled++;
      });
    });
    return { pass: pass, fail: fail, partial: partial, scheduled: scheduled };
  }, [artifacts]);

  function resultTone(r) {
    if (r === "pass") return AE.OK;
    if (r === "fail") return AE.BAD;
    if (r === "partial") return AE.WARN;
    if (r === "scheduled") return AE.ACCENT;
    return AE.SLATE;
  }

  function resultGlyph(r) {
    if (r === "pass") return "PASS";
    if (r === "fail") return "FAIL";
    if (r === "partial") return "PART";
    if (r === "scheduled") return "SCHED";
    return "—";
  }

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

  return (
    <div style={root}>
      <AEItarBanner />

      <div style={{ display: "flex", alignItems: "baseline", justifyContent: "space-between", marginBottom: 14 }}>
        <div>
          <div style={aeMono({ marginBottom: 4, color: AE.ACCENT })}>forge:// audit · qualification deep-dive</div>
          <div style={{ fontFamily: AE.FONT_SER, fontSize: 26, letterSpacing: "-0.01em", color: AE.MONO }}>
            Qualification artifacts · KESTREL-3
          </div>
          <div style={{ color: AE.SLATE, fontSize: 12, marginTop: 4 }}>
            ECSS-E-ST-10-03 environmental + AS9100 8.3.4 verification matrix
          </div>
        </div>
        <div style={{ display: "flex", gap: 12, alignItems: "center" }}>
          <label style={{
            display: "flex", alignItems: "center", gap: 6,
            fontFamily: AE.FONT_MONO, fontSize: 12, color: AE.SLATE,
            cursor: "pointer",
          }}>
            <input id="ae-act3-f5" name="ae-act3-f5" type="checkbox" checked={usPerson} onChange={function (e) { setUsPerson(e.target.checked); }} />
            <span>US-person view</span>
          </label>
          <button onClick={function () {
            if (window.forgeApi && typeof window.forgeApi.exportAuditUrl === "function") {
              window.location.href = window.forgeApi.exportAuditUrl("pdf");
              fireFlash("Qual pack export started · audit PDF");
            } else {
              fireFlash("Export qual pack queued — v2");
            }
          }} style={_ae3_exportBtn}>Export qual pack</button>
        </div>
      </div>

      {/* rollup strip */}
      <div style={{ display: "grid", gridTemplateColumns: "repeat(4, 1fr)", gap: 12, marginBottom: 16 }}>
        <div style={Object.assign(aeCard(), { textAlign: "center" })}>
          <div style={aeMono()}>Test runs · pass</div>
          <div style={{ fontFamily: AE.FONT_MONO, fontSize: 22, fontWeight: 700, color: AE.OK }}>{rollup.pass}</div>
        </div>
        <div style={Object.assign(aeCard(), { textAlign: "center" })}>
          <div style={aeMono()}>Test runs · fail</div>
          <div style={{ fontFamily: AE.FONT_MONO, fontSize: 22, fontWeight: 700, color: AE.BAD }}>{rollup.fail}</div>
        </div>
        <div style={Object.assign(aeCard(), { textAlign: "center" })}>
          <div style={aeMono()}>Partial</div>
          <div style={{ fontFamily: AE.FONT_MONO, fontSize: 22, fontWeight: 700, color: AE.WARN }}>{rollup.partial}</div>
        </div>
        <div style={Object.assign(aeCard(), { textAlign: "center" })}>
          <div style={aeMono()}>Scheduled</div>
          <div style={{ fontFamily: AE.FONT_MONO, fontSize: 22, fontWeight: 700, color: AE.ACCENT }}>{rollup.scheduled}</div>
        </div>
      </div>

      {/* filter chips */}
      <div style={Object.assign(aeCard({ marginBottom: 16 }),
                                { display: "flex", gap: 12, alignItems: "center" })}>
        <span style={aeMono()}>Status</span>
        {[["all", "all"], ["passed", "passed"], ["re-test", "re-test"], ["scheduled", "scheduled"]].map(function (pair) {
          const k = pair[0], l = pair[1], a = filter === k;
          const tone = k === "passed" ? AE.OK : k === "re-test" ? AE.WARN : k === "scheduled" ? AE.ACCENT : AE.SLATE;
          return (
            <button key={k} onClick={function () { setFilter(k); }} style={{
              ..._ae3_chipBase,
              border: "1px solid " + (a ? tone : AE.LINE),
              background: a ? tone : AE.INK_3,
              color: a ? AE.INK : AE.MONO,
            }}>{l}</button>
          );
        })}
        <div style={{ flex: 1 }} />
        <span style={{ fontFamily: AE.FONT_MONO, fontSize: 12, color: AE.SLATE }}>
          {visible.length} of {artifacts.length} artifacts
        </span>
      </div>

      <div style={{ display: "grid", gridTemplateColumns: "320px 1fr", gap: 18 }}>
        {/* artifact list */}
        <div>
          {visible.map(function (a) {
            const sel = active === a.id;
            const restricted = a.us_persons_only && !usPerson;
            return (
              <div key={a.id}
                role="button"
                tabIndex={0}
                onClick={function () { setActive(a.id); }}
                onKeyDown={function (e) { if (e.key === "Enter" || e.key === " ") { e.preventDefault(); setActive(a.id); } }}
                style={Object.assign(aeCard({
                  marginBottom: 10, cursor: "pointer",
                  borderColor: sel ? AE.ACCENT : AE.LINE,
                  background: sel ? AE.INK_3 : AE.INK_2,
                }))}>
                <div style={{ display: "flex", justifyContent: "space-between", alignItems: "flex-start" }}>
                  <div style={{ flex: 1 }}>
                    <div style={aeMono({ marginBottom: 3, color: sel ? AE.ACCENT : AE.SLATE_2 })}>{a.id}</div>
                    <div style={{ fontWeight: 600, color: AE.MONO, fontSize: 13 }}>
                      {restricted ? "[ITAR · redacted]" : a.name}
                    </div>
                  </div>
                  {aePill(a.status, aeStatusTone(a.status))}
                </div>
                <div style={{ fontSize: 12, color: AE.SLATE, marginTop: 6, lineHeight: 1.4 }}>
                  {restricted ? "ITAR plane · US-persons-only artifact" : a.spec}
                </div>
                <div style={_ae3_artifactFooterBase}>
                  <span>{a.standard.split("·")[0].trim()}</span>
                  <span>{a.history ? a.history.length + " runs" : "0 runs"}</span>
                </div>
              </div>
            );
          })}
        </div>

        {/* detail */}
        {activeArtifact ? (function () {
          const restricted = activeArtifact.us_persons_only && !usPerson;
          const lastRun = (activeArtifact.history || [])[(activeArtifact.history || []).length - 1];
          return (
            <div>
              <div style={Object.assign(aeCard(), { marginBottom: 14 })}>
                <div style={{ display: "flex", alignItems: "baseline", justifyContent: "space-between", marginBottom: 12 }}>
                  <div>
                    <div style={aeMono({ marginBottom: 3, color: AE.ACCENT })}>{activeArtifact.id}</div>
                    <div style={{ fontFamily: AE.FONT_SER, fontSize: 22, color: AE.MONO }}>
                      {restricted ? "[ITAR · redacted]" : activeArtifact.name}
                    </div>
                  </div>
                  {aePill(activeArtifact.status, aeStatusTone(activeArtifact.status))}
                </div>

                {restricted ? (
                  <div style={_ae3_restrictedNote}>
                    Detail withheld · this artifact is on the aetherion-itar plane.
                    Toggle US-person view at the page header to display the dose envelope,
                    LET spectrum, and component-level SEU/SEL data.
                  </div>
                ) : (
                  <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 14 }}>
                    <div>
                      <div style={aeMono()}>Spec</div>
                      <div style={{ fontSize: 13, color: AE.MONO, marginTop: 4 }}>{activeArtifact.spec}</div>
                    </div>
                    <div>
                      <div style={aeMono()}>Standard</div>
                      <div style={{ fontSize: 13, fontFamily: AE.FONT_MONO, color: AE.MONO, marginTop: 4 }}>
                        {activeArtifact.standard}
                      </div>
                    </div>
                    <div>
                      <div style={aeMono()}>Chamber</div>
                      <div style={{ fontSize: 13, color: AE.MONO, marginTop: 4 }}>{activeArtifact.chamber}</div>
                    </div>
                    <div>
                      <div style={aeMono()}>Target gate</div>
                      <div style={{ fontSize: 13, fontFamily: AE.FONT_MONO, color: AE.MONO, marginTop: 4 }}>
                        {activeArtifact.target_gate}
                      </div>
                    </div>
                    <div>
                      <div style={aeMono()}>Last run</div>
                      <div style={{ fontSize: 13, fontFamily: AE.FONT_MONO, color: AE.MONO, marginTop: 4 }}>
                        {activeArtifact.last_run}Z
                      </div>
                    </div>
                    <div>
                      <div style={aeMono()}>Last result</div>
                      <div style={{ fontSize: 13, marginTop: 4, color: lastRun ? resultTone(lastRun.result) : AE.SLATE_2 }}>
                        {lastRun ? resultGlyph(lastRun.result) + " · " + (lastRun.note || "") : "—"}
                      </div>
                    </div>
                  </div>
                )}
              </div>

              {!restricted ? (
                <div style={Object.assign(aeCard(), {})}>
                  <div style={{ display: "flex", justifyContent: "space-between", marginBottom: 10 }}>
                    <span style={aeMono()}>Pass / fail history</span>
                    <span style={{ fontFamily: AE.FONT_MONO, fontSize: 12, color: AE.SLATE_2 }}>
                      {(activeArtifact.history || []).length} runs · most recent first
                    </span>
                  </div>
                  <div>
                    {(activeArtifact.history || []).slice().reverse().map(function (h, i) {
                      const tone = resultTone(h.result);
                      return (
                        <div key={h.run + i} style={{
                          display: "grid",
                          gridTemplateColumns: "180px 90px 80px 1fr",
                          gap: 12, padding: "10px 0", alignItems: "center",
                          borderBottom: i < (activeArtifact.history || []).length - 1
                            ? "1px solid " + AE.LINE_SOFT : "0",
                        }}>
                          <span style={{ fontFamily: AE.FONT_MONO, fontSize: 12, color: AE.MONO }}>{h.run}</span>
                          <span style={{ fontFamily: AE.FONT_MONO, fontSize: 12, color: AE.SLATE_2 }}>{h.date}Z</span>
                          <span style={{ ..._ae3_resultBadgeBase, background: tone }}>{resultGlyph(h.result)}</span>
                          <span style={{ fontSize: 12, color: AE.SLATE }}>{h.note}</span>
                        </div>
                      );
                    })}
                  </div>
                  <div style={_ae3_acceptanceCallout}>
                    Acceptance gate ACC requires this artifact at <b style={{ color: AE.MONO }}>passed</b>.
                    Re-test runs trigger a fresh CofC and a ledger entry of type
                    <span style={{ fontFamily: AE.FONT_MONO, color: AE.ACCENT }}> QUAL_PASSED</span>
                    or <span style={{ fontFamily: AE.FONT_MONO, color: AE.ACCENT }}>EMC_PASSED</span>.
                  </div>
                </div>
              ) : null}

              {/* expandable test plan section */}
              {!restricted ? (
                <div style={Object.assign(aeCard({ marginTop: 14 }), {})}>
                  <div style={aeMono({ marginBottom: 10 })}>Acceptance criteria</div>
                  <ul style={{ margin: 0, paddingLeft: 20, color: AE.MONO, fontSize: 12, lineHeight: 1.7 }}>
                    {activeArtifact.test === "tvac" ? [
                      "24 thermal-vacuum cycles −40 / +85 °C with 90 min ramps",
                      "Pumpdown to 1e-5 torr for ≥4 h before first cycle",
                      "Strain-gauge logging on every fastener critical to deploy",
                      "Post-run torque audit on M3 hinge fasteners (spec 0.55 ± 0.05 Nm)",
                      "Telemetry dump correlated to thermal trace · ≤5 ms drift",
                    ] : activeArtifact.test === "vibration" ? [
                      "Sine sweep 5–100 Hz 0.5 g 1 oct/min",
                      "Random GEVS 14.1 g rms · 20 Hz–2000 Hz · 1 min/axis",
                      "Resonance survey ± 0.5 dB Q-factor delta",
                      "Margin: GEVS + 3 dB qualification envelope",
                    ] : activeArtifact.test === "shock" ? [
                      "Pyroshock half-sine 2000 g · 0.5 ms / 0.5 ms",
                      "3 axes · 3 hits per axis",
                      "Continuity audit on all electrical interfaces",
                    ] : activeArtifact.test === "emi" ? [
                      "CE102 conducted emissions 10 kHz–10 MHz",
                      "CS101 conducted susceptibility 30 Hz–150 kHz",
                      "RE102 radiated emissions 10 kHz–18 GHz",
                      "RS103 radiated susceptibility 2 MHz–18 GHz @ 10 V/m",
                    ] : activeArtifact.test === "radiation_tid" ? [
                      "Co-60 gamma · ≥30 krad(Si) total ionising dose",
                      "Displacement damage per ECSS-E-ST-10-04 LEO 525 km · 5 y",
                      "SEU / SEL screen at ≥40 MeV·cm²/mg LET",
                      "ELDRS bias condition for bipolar parts",
                    ] : activeArtifact.test === "cleanliness" ? [
                      "ISO 14644-1 Class 7 entry verification",
                      "Particle count 0.5 µm ≤ 352 000 / m³",
                      "Particle count 5.0 µm ≤ 2 930 / m³",
                      "Monthly verification per ISO 14644-2",
                    ] : ["Acceptance criteria per standard"]
                    .map(function (line) {
                      return <li key={line}>{line}</li>;
                    })}
                  </ul>
                </div>
              ) : null}
            </div>
          );
        })() : null}
      </div>

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

// ──────────────────────────────────────────────── ScreenAetherionNPI
function ScreenAetherionNPI() {
  const slice = useAeResolve();
  const stages = slice.npi;

  const [active, setActive] = uSAE3(null);
  const [flash, setFlash] = uSAE3(null);
  const flashTimer = uRAE3(null);

  uEAE3(function () {
    return function () {
      if (flashTimer.current) { clearTimeout(flashTimer.current); flashTimer.current = null; }
    };
  }, []);

  function fireFlash(msg) {
    setFlash(msg);
    if (flashTimer.current) clearTimeout(flashTimer.current);
    flashTimer.current = setTimeout(function () { flashTimer.current = null; setFlash(null); }, 1600);
  }

  const passed   = stages.filter(function (s) { return s.status === "passed"; }).length;
  const inFlight = stages.filter(function (s) { return s.status === "in-flight" || s.status === "re-test"; }).length;
  const upcoming = stages.filter(function (s) { return s.status === "upcoming" || s.status === "pending"; }).length;

  const todayIso = "2026-05-09";
  const launchStage = stages[stages.length - 1];
  const daysToLaunch = (function () {
    if (!launchStage) return null;
    const d = launchStage.date;
    if (!/^\d{4}-\d{2}-\d{2}$/.test(d)) return null;
    const t = new Date(d + "Z").getTime();
    const today = new Date(todayIso + "Z").getTime();
    return Math.round((t - today) / (24 * 3600 * 1000));
  })();

  const progressPct = Math.round((passed / stages.length) * 100);

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

  const activeStage = stages.find(function (s) { return s.id === active; });

  return (
    <div style={root}>
      <AEItarBanner />

      <div style={{ display: "flex", alignItems: "baseline", justifyContent: "space-between", marginBottom: 14 }}>
        <div>
          <div style={aeMono({ marginBottom: 4, color: AE.ACCENT })}>plan:// npi · KESTREL-3 · 9-stage lifecycle</div>
          <div style={{ fontFamily: AE.FONT_SER, fontSize: 26, letterSpacing: "-0.01em", color: AE.MONO }}>
            New product introduction · KESTREL-3 12U
          </div>
          <div style={{ color: AE.SLATE, fontSize: 12, marginTop: 4 }}>
            SRR · PDR · CDR · FAB · ASSY · I&T · TVAC · ACC · LAUNCH: 9 gates from baseline to manifest lock
          </div>
        </div>
        <div style={{ display: "flex", gap: 10 }}>
          <div style={Object.assign(aeCard(), { textAlign: "center", minWidth: 110 })}>
            <div style={aeMono()}>Passed</div>
            <div style={{ fontFamily: AE.FONT_MONO, fontSize: 22, fontWeight: 700, color: AE.OK }}>
              {passed}<span style={{ color: AE.SLATE_2 }}>/{stages.length}</span>
            </div>
          </div>
          <div style={Object.assign(aeCard(), { textAlign: "center", minWidth: 110 })}>
            <div style={aeMono()}>In-flight</div>
            <div style={{ fontFamily: AE.FONT_MONO, fontSize: 22, fontWeight: 700, color: AE.WARN }}>{inFlight}</div>
          </div>
          <div style={Object.assign(aeCard(), { textAlign: "center", minWidth: 110 })}>
            <div style={aeMono()}>Days to launch</div>
            <div style={{ fontFamily: AE.FONT_MONO, fontSize: 22, fontWeight: 700, color: AE.ACCENT }}>
              {daysToLaunch == null ? "—" : daysToLaunch}<span style={{ color: AE.SLATE_2, fontSize: 13 }}>d</span>
            </div>
          </div>
        </div>
      </div>

      {/* progress rail */}
      <div style={Object.assign(aeCard({ marginBottom: 16 }), { padding: 18 })}>
        <div style={{ display: "flex", justifyContent: "space-between", marginBottom: 8 }}>
          <span style={aeMono()}>Lifecycle progress</span>
          <span style={{ fontFamily: AE.FONT_MONO, fontSize: 12, color: AE.MONO }}>
            {progressPct}% complete · today {todayIso}Z
          </span>
        </div>
        <div style={{
          height: 8, background: AE.INK_3, borderRadius: 4,
          overflow: "hidden", position: "relative",
          border: "1px solid " + AE.LINE,
        }}>
          <div style={{
            width: progressPct + "%", height: "100%",
            background: "linear-gradient(90deg, " + AE.ACCENT_DIM + " 0%, " + AE.ACCENT + " 100%)",
          }} />
        </div>
      </div>

      {/* horizontal 9-stage gantt-ish row */}
      <div style={Object.assign(aeCard(), { marginBottom: 16, padding: 0, overflow: "hidden" })}>
        <div style={{ padding: "10px 14px", borderBottom: "1px solid " + AE.LINE, background: AE.INK_3 }}>
          <span style={aeMono()}>Stage map · click for detail</span>
        </div>
        <div style={{
          display: "grid",
          gridTemplateColumns: "repeat(" + stages.length + ", 1fr)",
          gap: 0,
        }}>
          {stages.map(function (st, i) {
            const tone = aeStatusTone(st.status);
            const isActive = active === st.id;
            return (
              <div key={st.id}
                role="button"
                tabIndex={0}
                onClick={function () { setActive(isActive ? null : st.id); }}
                onKeyDown={function (e) { if (e.key === "Enter" || e.key === " ") { e.preventDefault(); setActive(isActive ? null : st.id); } }}
                style={{
                  cursor: "pointer", padding: "14px 10px",
                  borderRight: i < stages.length - 1 ? "1px solid " + AE.LINE_SOFT : "0",
                  background: isActive ? AE.INK_3 : (st.status === "in-flight" || st.status === "re-test" ? "rgba(224,162,74,0.06)" : "transparent"),
                  transition: "background .12s",
                  position: "relative",
                }}>
                <div style={{
                  position: "absolute", top: 0, left: 0, right: 0, height: 3,
                  background: tone,
                }} />
                <div style={aeMono({ color: AE.SLATE_2, marginBottom: 4 })}>g{i + 1}</div>
                <div style={{
                  fontFamily: AE.FONT_MONO, fontSize: 14, fontWeight: 700,
                  color: AE.MONO, marginBottom: 6,
                }}>{st.code}</div>
                <div style={{ fontSize: 12, color: AE.SLATE, lineHeight: 1.3, minHeight: 30 }}>
                  {st.name}
                </div>
                <div style={{
                  marginTop: 8, fontFamily: AE.FONT_MONO, fontSize: 12, color: tone,
                  textTransform: "uppercase", letterSpacing: "0.06em", fontWeight: 600,
                }}>{st.status}</div>
                <div style={{ fontFamily: AE.FONT_MONO, fontSize: 12, color: AE.SLATE_2, marginTop: 2 }}>
                  {st.date}{/^\d{4}-\d{2}-\d{2}$/.test(st.date) ? "Z" : ""}
                </div>
              </div>
            );
          })}
        </div>
      </div>

      <div style={{ display: "grid", gridTemplateColumns: activeStage ? "1fr 380px" : "1fr 280px", gap: 18 }}>
        {/* timeline list */}
        <div>
          <div style={Object.assign(aeCard(), { padding: 0, overflow: "hidden" })}>
            <div style={_ae3_npiStageHeaderRow}>
              <div style={aeMono()}>gate</div>
              <div style={aeMono()}>code</div>
              <div style={aeMono()}>name · note</div>
              <div style={aeMono()}>date</div>
              <div style={aeMono()}>status</div>
            </div>
            {stages.map(function (st, i) {
              const sel = active === st.id;
              return (
                <div key={st.id}
                  role="button"
                  tabIndex={0}
                  onClick={function () { setActive(sel ? null : st.id); }}
                  onKeyDown={function (e) { if (e.key === "Enter" || e.key === " ") { e.preventDefault(); setActive(sel ? null : st.id); } }}
                  style={{
                    ..._ae3_npiStageRowBase,
                    borderBottom: i < stages.length - 1 ? "1px solid " + AE.LINE_SOFT : "0",
                    background: sel ? AE.INK_3 : "transparent",
                  }}>
                  <div style={{ fontFamily: AE.FONT_MONO, fontSize: 12, color: AE.SLATE_2 }}>g{i + 1}</div>
                  <div style={{ fontFamily: AE.FONT_MONO, fontSize: 13, color: AE.MONO, fontWeight: 600 }}>{st.code}</div>
                  <div>
                    <div style={{ fontSize: 13, color: AE.MONO }}>{st.name}</div>
                    <div style={{ fontSize: 12, color: AE.SLATE, marginTop: 2, lineHeight: 1.4 }}>{st.note}</div>
                  </div>
                  <div style={{ fontFamily: AE.FONT_MONO, fontSize: 12, color: AE.SLATE }}>
                    {st.date}{/^\d{4}-\d{2}-\d{2}$/.test(st.date) ? "Z" : ""}
                  </div>
                  <div>{aePill(st.status, aeStatusTone(st.status))}</div>
                </div>
              );
            })}
          </div>

          <div style={Object.assign(aeCard({ marginTop: 16 }), {})}>
            <div style={aeMono({ marginBottom: 10 })}>Open actions across gates</div>
            {stages.reduce(function (acc, s) { if (s.actions && s.actions > 0) acc.push(s); return acc; }, []).map(function (s) {
              return (
                <div key={s.id} style={{
                  display: "flex", justifyContent: "space-between", alignItems: "center",
                  padding: "8px 0", borderBottom: "1px solid " + AE.LINE_SOFT,
                }}>
                  <div>
                    <div style={{ fontFamily: AE.FONT_MONO, fontSize: 12, color: AE.MONO }}>{s.code}</div>
                    <div style={{ fontSize: 12, color: AE.SLATE, marginTop: 2 }}>{s.note}</div>
                  </div>
                  <span style={_ae3_actionPill}>{s.actions} action{s.actions === 1 ? "" : "s"}</span>
                </div>
              );
            })}
            {stages.filter(function (s) { return s.actions && s.actions > 0; }).length === 0 ? (
              <div style={{ fontSize: 12, color: AE.SLATE, padding: "8px 0" }}>No open actions across gates.</div>
            ) : null}
          </div>
        </div>

        {/* right rail / detail */}
        <div>
          {activeStage ? (
            <div style={Object.assign(aeCard(), { borderColor: AE.ACCENT })}>
              <div style={{ display: "flex", justifyContent: "space-between", marginBottom: 10 }}>
                <span style={aeMono({ color: AE.ACCENT })}>{activeStage.code}</span>
                <button onClick={function () { setActive(null); }} style={{
                  background: "transparent", border: 0, cursor: "pointer",
                  color: AE.SLATE_2, fontFamily: AE.FONT_MONO, fontSize: 12,
                }}>close</button>
              </div>
              <div style={{ fontFamily: AE.FONT_SER, fontSize: 18, lineHeight: 1.3, marginBottom: 10, color: AE.MONO }}>
                {activeStage.name}
              </div>
              <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 10, marginBottom: 12 }}>
                <div>
                  <div style={aeMono()}>Date</div>
                  <div style={{ fontFamily: AE.FONT_MONO, color: AE.MONO, marginTop: 4 }}>
                    {activeStage.date}{/^\d{4}-\d{2}-\d{2}$/.test(activeStage.date) ? "Z" : ""}
                  </div>
                </div>
                <div>
                  <div style={aeMono()}>Status</div>
                  <div style={{ marginTop: 4 }}>{aePill(activeStage.status, aeStatusTone(activeStage.status))}</div>
                </div>
              </div>
              <div style={aeMono({ marginBottom: 4 })}>Note</div>
              <div style={{ fontSize: 12, color: AE.MONO, lineHeight: 1.5, marginBottom: 12 }}>
                {activeStage.note}
              </div>

              {activeStage.code === "TVAC" || activeStage.code === "I&T" ? (
                <div style={_ae3_ecoBannerCallout}>
                  <div style={aeMono({ color: AE.WARN, marginBottom: 4 })}>ECO-AET-0042 link</div>
                  Hinge fastener pre-load loss caught at TVAC-AET-014 cycle 14 of 24.
                  ECO replaces M3 A2-70 with A286 + 4× DIN 2093 Belleville stack.
                  Re-test TVAC-AET-014R scheduled for 2026-05-28Z.
                </div>
              ) : null}

              <button onClick={function () { fireFlash(activeStage.code + " review pack queued — v2"); }}
                style={_ae3_npiOpenReviewBtn}>
                Open {activeStage.code} review pack →
              </button>
            </div>
          ) : (
            <div>
              <div style={aeCard()}>
                <div style={aeMono({ marginBottom: 8 })}>Mass · power summary</div>
                <div style={{ fontSize: 12, lineHeight: 1.7 }}>
                  <div style={{ display: "flex", justifyContent: "space-between", marginBottom: 4 }}>
                    <span style={{ color: AE.SLATE }}>Mass cap</span>
                    <span style={{ fontFamily: AE.FONT_MONO, color: AE.MONO }}>14.000 kg</span>
                  </div>
                  <div style={{ display: "flex", justifyContent: "space-between", marginBottom: 4 }}>
                    <span style={{ color: AE.SLATE }}>Current</span>
                    <span style={{ fontFamily: AE.FONT_MONO, color: AE.MONO }}>12.46 kg</span>
                  </div>
                  <div style={{ display: "flex", justifyContent: "space-between", marginBottom: 4 }}>
                    <span style={{ color: AE.SLATE }}>Margin</span>
                    <span style={{ fontFamily: AE.FONT_MONO, color: AE.OK }}>11.0%</span>
                  </div>
                  <div style={{ display: "flex", justifyContent: "space-between", marginBottom: 4 }}>
                    <span style={{ color: AE.SLATE }}>Power BOL</span>
                    <span style={{ fontFamily: AE.FONT_MONO, color: AE.MONO }}>70.0 W</span>
                  </div>
                  <div style={{ display: "flex", justifyContent: "space-between" }}>
                    <span style={{ color: AE.SLATE }}>Power margin</span>
                    <span style={{ fontFamily: AE.FONT_MONO, color: AE.OK }}>8.0 W</span>
                  </div>
                </div>
              </div>

              <div style={Object.assign(aeCard({ marginTop: 12 }), {})}>
                <div style={aeMono({ marginBottom: 8 })}>Customer</div>
                <div style={{ fontSize: 13, color: AE.MONO, marginBottom: 4 }}>Aperture Earth Analytics</div>
                <div style={{ fontSize: 12, color: AE.SLATE, lineHeight: 1.4 }}>
                  Single-flight 12U bus · {((window.forgeI18n && window.forgeI18n.formatMoneyMinor && window.forgeI18n.formatMoneyMinor("420000000", "USD")) || "$4.2M") + " FFP"} · 1m-GSD imager · X-band 50 Mbps
                </div>
                <div style={{ marginTop: 8, fontFamily: AE.FONT_MONO, fontSize: 12, color: AE.SLATE_2 }}>
                  LOI 2025-01-12Z · CDR 2025-10-22Z · TVAC chatter 2026-04-22Z
                </div>
              </div>

              <div style={Object.assign(aeCard({ marginTop: 12 }), { background: AE.INK_3 })}>
                <div style={aeMono({ marginBottom: 6 })}>Launch manifest</div>
                <div style={{ fontSize: 12, color: AE.MONO, marginBottom: 4 }}>Falcon 9 · Transporter-15</div>
                <div style={{ fontSize: 12, color: AE.SLATE, lineHeight: 1.5 }}>
                  Sun-sync LEO 525 km · dawn-dusk · target 2026-09-10Z. Launch hold
                  is 7d behind ACC. Manifest signed pending Mission Director ACC sign.
                </div>
              </div>

              <div style={Object.assign(aeCard({ marginTop: 12 }), { background: AE.INK_3 })}>
                <div style={aeMono({ marginBottom: 6 })}>Risk register</div>
                <div style={{ fontSize: 12, color: AE.SLATE, lineHeight: 1.5 }}>
                  <div>· Hinge fastener · open · ECO-AET-0042</div>
                  <div>· Star tracker single-string · accepted · BCT swap-out plan</div>
                  <div>· TID coupon dose envelope · ITAR-restricted</div>
                </div>
              </div>
            </div>
          )}
        </div>
      </div>

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

// ──────────────────────────────────────────────── ScreenAetherionPFMEA
function ScreenAetherionPFMEA() {
  const slice = useAeResolve();
  const pfmea = slice.pfmea;

  const [sortKey, setSortKey] = uSAE3("RPN");
  const [sortDir, setSortDir] = uSAE3("desc");
  const [rpnFilter, setRpnFilter] = uSAE3("all");
  const [sevFilter, setSevFilter] = uSAE3(false);
  const [active, setActive] = uSAE3(null);
  const [editing, setEditing] = uSAE3({});  // id → { S, O, D }
  const [flash, setFlash] = uSAE3(null);
  const flashTimer = uRAE3(null);

  uEAE3(function () {
    return function () {
      if (flashTimer.current) { clearTimeout(flashTimer.current); flashTimer.current = null; }
    };
  }, []);

  uEAE3(function () {
    if (typeof window === "undefined") return;
    function onTenantChange() {
      setSortKey("RPN"); setSortDir("desc"); setRpnFilter("all");
      setSevFilter(false); setActive(null); setEditing({}); setFlash(null);
    }
    window.addEventListener("forge:tenant-change", onTenantChange);
    return function () { window.removeEventListener("forge:tenant-change", onTenantChange); };
  }, []);

  function fireFlash(msg) {
    setFlash(msg);
    if (flashTimer.current) clearTimeout(flashTimer.current);
    flashTimer.current = setTimeout(function () { flashTimer.current = null; setFlash(null); }, 1600);
  }

  function effective(m) {
    const e = editing[m.id];
    if (!e) return { S: m.S, O: m.O, D: m.D, RPN: m.RPN };
    const S = e.S != null ? e.S : m.S;
    const O = e.O != null ? e.O : m.O;
    const D = e.D != null ? e.D : m.D;
    return { S: S, O: O, D: D, RPN: S * O * D };
  }

  function onCellEdit(id, k, v) {
    const cur = editing[id] || {};
    const next = Object.assign({}, cur);
    next[k] = Math.max(1, Math.min(10, parseInt(v, 10) || 1));
    const all = Object.assign({}, editing);
    all[id] = next;
    setEditing(all);
  }

  function resetEdits() { setEditing({}); fireFlash("Edits reset"); }

  function commitEdits() {
    const n = Object.keys(editing).length;
    fireFlash("Committed " + n + " mode change" + (n === 1 ? "" : "s") + " — ECO-AET-0042 ledger entry queued");
  }

  const filtered = uMAE3(function () {
    let arr = pfmea.slice().map(function (m) {
      const eff = effective(m);
      return Object.assign({}, m, eff);
    });
    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 (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, sevFilter, sortKey, sortDir, editing]);

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

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

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

  const sortHead = function (k, label) {
    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,
        color: isActive ? AE.MONO : AE.SLATE,
      }}>
        {label}
        {isActive ? <span style={{ fontSize: 12, color: AE.ACCENT }}>{sortDir === "asc" ? "▲" : "▼"}</span> : null}
      </div>
    );
  };

  function rpnCellBg(rpn) {
    if (rpn >= 100) return "rgba(215,90,74,0.18)";
    if (rpn >= 50)  return "rgba(224,162,74,0.18)";
    return "rgba(63,181,127,0.18)";
  }

  const totalCrit = filtered.filter(function (m) { return m.RPN >= 100; }).length;
  const totalMid = filtered.filter(function (m) { return m.RPN >= 50 && m.RPN < 100; }).length;
  const sev7 = filtered.filter(function (m) { return m.S >= 7; }).length;
  const avgRpn = filtered.length
    ? Math.round(filtered.reduce(function (a, b) { return a + b.RPN; }, 0) / filtered.length) : 0;

  return (
    <div style={root}>
      <AEItarBanner />

      <div style={{ display: "flex", justifyContent: "space-between", alignItems: "baseline", marginBottom: 14 }}>
        <div>
          <div style={aeMono({ marginBottom: 4, color: AE.ACCENT })}>build:// pfmea · ECO-AET-0042 link</div>
          <div style={{ fontFamily: AE.FONT_SER, fontSize: 26, letterSpacing: "-0.01em", color: AE.MONO }}>
            Process FMEA · {pfmea.length} modes
          </div>
          <div style={{ color: AE.SLATE, fontSize: 12, marginTop: 4 }}>
            S × O × D → RPN. Modes ≥100 require live containment. ECO-AET-0042 hinge fastener at RPN 216.
          </div>
        </div>
        <div style={{ display: "flex", gap: 8 }}>
          <button onClick={resetEdits} disabled={Object.keys(editing).length === 0}
            style={{
              ..._ae3_exportBtn,
              color: Object.keys(editing).length === 0 ? AE.SLATE_2 : AE.MONO,
              cursor: Object.keys(editing).length === 0 ? "not-allowed" : "pointer",
            }}>Reset edits</button>
          <button onClick={function () {
            if (window.forgeApi && typeof window.forgeApi.exportAuditUrl === "function") {
              window.location.href = window.forgeApi.exportAuditUrl("csv");
              fireFlash("PFMEA export started · audit CSV");
            } else {
              fireFlash("Export PFMEA queued — v2");
            }
          }} style={_ae3_exportBtn}>Export FMEA</button>
          <button onClick={commitEdits} disabled={Object.keys(editing).length === 0}
            style={{
              ..._ae3_primaryBtnBase,
              background: Object.keys(editing).length === 0 ? AE.SLATE_2 : AE.ACCENT,
              cursor: Object.keys(editing).length === 0 ? "not-allowed" : "pointer",
            }}>Commit edits</button>
        </div>
      </div>

      {/* ECO-AET-0042 banner */}
      <div style={_ae3_pfmeaEcoBanner}>
        <div>
          <div style={aeMono({ color: AE.WARN, marginBottom: 3 })}>ECO-AET-0042 · critical</div>
          <div style={{ fontSize: 13, color: AE.MONO }}>
            Solar-array hinge fastener · M3 A2-70 → A286 + Belleville stack
          </div>
        </div>
        <div style={{ flex: 1, fontSize: 12, color: AE.SLATE, lineHeight: 1.4 }}>
          Trigger · TVAC-AET-014 cycle 14/24 · 50 µm pre-load loss · 0.42 Nm vs spec 0.55 ± 0.05 Nm.
          Mode <span style={{ fontFamily: AE.FONT_MONO, color: AE.MONO }}>PF-001</span> RPN
          <span style={{ fontFamily: AE.FONT_MONO, color: AE.BAD }}> 216</span> →
          target <span style={{ fontFamily: AE.FONT_MONO, color: AE.OK }}>36</span> after change.
        </div>
        <button onClick={function () { setActive(pfmea.find(function (m) { return m.id === "PF-001"; })); }}
          style={_ae3_pfmeaOpenEcoBtn}>Open PF-001 →</button>
      </div>

      {/* filter chips */}
      <div style={Object.assign(aeCard({ marginBottom: 16 }),
                                { display: "flex", gap: 14, flexWrap: "wrap", alignItems: "center" })}>
        <div style={{ display: "flex", gap: 6, alignItems: "center" }}>
          <span style={aeMono()}>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" ? AE.BAD : k === "mid" ? AE.WARN : k === "low" ? AE.OK : AE.SLATE;
            return (
              <button key={k} onClick={function () { setRpnFilter(k); }} style={{
                ..._ae3_chipBase,
                border: "1px solid " + (active ? tone : AE.LINE),
                background: active ? tone : AE.INK_3,
                color: active ? AE.INK : AE.MONO,
              }}>{l}</button>
            );
          })}
        </div>
        <label style={{ display: "flex", gap: 6, alignItems: "center", cursor: "pointer" }}>
          <input id="ae-act3-f6" name="ae-act3-f6" type="checkbox" checked={sevFilter} onChange={function (e) { setSevFilter(e.target.checked); }} />
          <span style={aeMono()}>severity ≥ 7</span>
        </label>
        <div style={{ flex: 1 }} />
        <span style={{ fontFamily: AE.FONT_MONO, fontSize: 12, color: AE.SLATE }}>
          {filtered.length} of {pfmea.length} modes
        </span>
      </div>

      <div style={{ display: "grid", gridTemplateColumns: active ? "1fr 380px" : "1fr", gap: 18 }}>
        {/* table */}
        <div style={Object.assign(aeCard(), { padding: 0, overflow: "hidden" })}>
          <div style={{ ..._ae3_pfmeaTableHeader, display: "grid", gridTemplateColumns: colTpl }}>
            {sortHead("item", "Item")}
            {sortHead("mode", "Mode")}
            {sortHead("effect", "Effect")}
            {sortHead("S", "S")}
            {sortHead("O", "O")}
            {sortHead("D", "D")}
            {sortHead("RPN", "RPN")}
            <div>Cause / control</div>
            <div>Owner · ECO</div>
          </div>
          {filtered.map(function (m, i) {
            const sel = active && active.id === m.id;
            const isHinge = m.id === "PF-001";
            return (
              <div key={m.id}
                role="button"
                tabIndex={0}
                onClick={function () { setActive(m); }}
                onKeyDown={function (e) { if (e.key === "Enter" || e.key === " ") { e.preventDefault(); setActive(m); } }}
                style={{
                  ..._ae3_pfmeaRowBase,
                  display: "grid", gridTemplateColumns: colTpl,
                  borderBottom: i < filtered.length - 1 ? "1px solid " + AE.LINE_SOFT : "0",
                  background: sel ? AE.INK_3 : (isHinge ? "rgba(224,162,74,0.05)" : "transparent"),
                  borderLeft: isHinge ? "2px solid " + AE.WARN : "2px solid transparent",
                }}>
                <div>
                  <div style={{ fontSize: 12, fontWeight: 600, color: AE.MONO }}>{m.item}</div>
                  <div style={{ fontFamily: AE.FONT_MONO, fontSize: 12, color: AE.SLATE_2, marginTop: 2 }}>{m.id}</div>
                </div>
                <div style={{ fontSize: 12, color: AE.MONO }}>{m.mode}</div>
                <div style={{ fontSize: 12, color: AE.SLATE }}>{m.effect}</div>
                {/* editable S */}
                <input id="ae-act3-f7" name="ae-act3-f7" type="number" min="1" max="10" value={m.S}
                  onClick={function (e) { e.stopPropagation(); }}
                  onChange={function (e) { e.stopPropagation(); onCellEdit(m.id, "S", e.target.value); }}
                  style={{
                    ..._ae3_pfmeaScoreInput,
                    background: editing[m.id] && editing[m.id].S != null ? AE.ACCENT_DIM : AE.INK_3,
                    border: "1px solid " + (m.S >= 7 ? AE.BAD : AE.LINE),
                  }} />
                {/* editable O */}
                <input id="ae-act3-f8" name="ae-act3-f8" type="number" min="1" max="10" value={m.O}
                  onClick={function (e) { e.stopPropagation(); }}
                  onChange={function (e) { e.stopPropagation(); onCellEdit(m.id, "O", e.target.value); }}
                  style={{
                    ..._ae3_pfmeaScoreInput,
                    background: editing[m.id] && editing[m.id].O != null ? AE.ACCENT_DIM : AE.INK_3,
                    border: "1px solid " + AE.LINE,
                  }} />
                {/* editable D */}
                <input id="ae-act3-f9" name="ae-act3-f9" type="number" min="1" max="10" value={m.D}
                  onClick={function (e) { e.stopPropagation(); }}
                  onChange={function (e) { e.stopPropagation(); onCellEdit(m.id, "D", e.target.value); }}
                  style={{
                    ..._ae3_pfmeaScoreInput,
                    background: editing[m.id] && editing[m.id].D != null ? AE.ACCENT_DIM : AE.INK_3,
                    border: "1px solid " + AE.LINE,
                  }} />
                <div style={{
                  ..._ae3_pfmeaRpnCell,
                  color: aeRpnTone(m.RPN),
                  background: rpnCellBg(m.RPN),
                }}>{m.RPN}</div>
                <div style={{ fontSize: 12, color: AE.SLATE, lineHeight: 1.4 }}>
                  <div style={{ color: AE.MONO, marginBottom: 2 }}>{m.cause}</div>
                  <div style={{ color: AE.SLATE_2 }}>{m.current_control}</div>
                </div>
                <div style={{ fontSize: 12, color: AE.SLATE }}>
                  <div style={{ color: AE.MONO }}>{m.owner}</div>
                  {m.eco_link !== "—" ? (
                    <span style={_ae3_ecoLinkChip}>{m.eco_link}</span>
                  ) : <span style={{ color: AE.SLATE_2, fontFamily: AE.FONT_MONO, fontSize: 12 }}>no eco</span>}
                </div>
              </div>
            );
          })}
          {filtered.length === 0 ? (
            <div style={{ padding: 24, textAlign: "center", color: AE.SLATE }}>
              No PFMEA entries match the current filter.
            </div>
          ) : null}
        </div>

        {/* side panel */}
        {active ? (function () {
          const eff = effective(active);
          const targetRPN = active.target_S * active.target_O * active.target_D;
          return (
            <div style={Object.assign(aeCard(), { borderColor: AE.ACCENT })}>
              <div style={{ display: "flex", justifyContent: "space-between", marginBottom: 10 }}>
                <span style={aeMono({ color: AE.ACCENT })}>Mode detail · {active.id}</span>
                <button onClick={function () { setActive(null); }} style={{
                  background: "transparent", border: 0, cursor: "pointer",
                  color: AE.SLATE_2, fontFamily: AE.FONT_MONO, fontSize: 12,
                }}>close</button>
              </div>

              <div style={{ fontFamily: AE.FONT_SER, fontSize: 18, lineHeight: 1.3, marginBottom: 4, color: AE.MONO }}>
                {active.item}
              </div>
              <div style={{ fontSize: 12, color: AE.SLATE, marginBottom: 14, lineHeight: 1.45 }}>
                {active.mode}
              </div>

              <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr 1fr", gap: 8, marginBottom: 14 }}>
                <div style={{ textAlign: "center", padding: "10px 4px", background: AE.INK_3, borderRadius: 3 }}>
                  <div style={aeMono()}>Severity</div>
                  <div style={{ fontFamily: AE.FONT_MONO, fontSize: 22, fontWeight: 700, color: aeSevTone(eff.S) }}>{eff.S}</div>
                  <div style={{ fontSize: 12, fontFamily: AE.FONT_MONO, color: AE.SLATE_2 }}>target {active.target_S}</div>
                </div>
                <div style={{ textAlign: "center", padding: "10px 4px", background: AE.INK_3, borderRadius: 3 }}>
                  <div style={aeMono()}>Occurrence</div>
                  <div style={{ fontFamily: AE.FONT_MONO, fontSize: 22, fontWeight: 700, color: aeSevTone(eff.O) }}>{eff.O}</div>
                  <div style={{ fontSize: 12, fontFamily: AE.FONT_MONO, color: AE.SLATE_2 }}>target {active.target_O}</div>
                </div>
                <div style={{ textAlign: "center", padding: "10px 4px", background: AE.INK_3, borderRadius: 3 }}>
                  <div style={aeMono()}>Detection</div>
                  <div style={{ fontFamily: AE.FONT_MONO, fontSize: 22, fontWeight: 700, color: aeSevTone(eff.D) }}>{eff.D}</div>
                  <div style={{ fontSize: 12, fontFamily: AE.FONT_MONO, color: AE.SLATE_2 }}>target {active.target_D}</div>
                </div>
              </div>

              <div style={_ae3_pfmeaRpnPanel}>
                <div style={aeMono({ marginBottom: 4 })}>Current RPN</div>
                <div style={{
                  fontFamily: AE.FONT_MONO, fontSize: 32, fontWeight: 700,
                  color: aeRpnTone(eff.RPN),
                }}>{eff.RPN}</div>
                <div style={{ fontSize: 12, color: AE.SLATE, marginTop: 6 }}>
                  target after action <span style={{ fontFamily: AE.FONT_MONO, color: AE.OK }}>{targetRPN}</span>
                </div>
                <div style={{
                  marginTop: 10, height: 6, background: AE.INK,
                  borderRadius: 3, position: "relative", overflow: "hidden",
                  border: "1px solid " + AE.LINE,
                }}>
                  <div style={{
                    width: Math.min(100, (eff.RPN / 1000) * 100) + "%",
                    height: "100%", background: aeRpnTone(eff.RPN),
                  }} />
                  <div style={{
                    position: "absolute",
                    left: Math.min(100, (targetRPN / 1000) * 100) + "%",
                    top: -2, bottom: -2,
                    width: 2, background: AE.OK,
                  }} />
                </div>
              </div>

              <div style={{ marginBottom: 12 }}>
                <div style={aeMono({ marginBottom: 4 })}>Cause</div>
                <div style={{ fontSize: 12, color: AE.MONO, lineHeight: 1.5 }}>{active.cause}</div>
              </div>

              <div style={{ marginBottom: 12 }}>
                <div style={aeMono({ marginBottom: 4 })}>Effect</div>
                <div style={{ fontSize: 12, color: AE.MONO, lineHeight: 1.5 }}>{active.effect}</div>
              </div>

              <div style={{ marginBottom: 12 }}>
                <div style={aeMono({ marginBottom: 4 })}>Current control</div>
                <div style={{ fontSize: 12, color: AE.MONO, lineHeight: 1.5 }}>{active.current_control}</div>
              </div>

              <div style={{ marginBottom: 12 }}>
                <div style={aeMono({ marginBottom: 4 })}>Recommended action</div>
                <div style={{ fontSize: 12, color: AE.MONO, lineHeight: 1.5 }}>{active.recommended_action}</div>
              </div>

              <div style={{
                display: "grid", gridTemplateColumns: "1fr 1fr", gap: 10, marginBottom: 12,
              }}>
                <div>
                  <div style={aeMono()}>Owner</div>
                  <div style={{ fontSize: 12, color: AE.MONO, marginTop: 4 }}>{active.owner}</div>
                </div>
                <div>
                  <div style={aeMono()}>Station</div>
                  <div style={{ fontSize: 12, fontFamily: AE.FONT_MONO, color: AE.MONO, marginTop: 4 }}>{active.station}</div>
                </div>
              </div>

              {active.eco_link !== "—" ? (
                <div style={_ae3_linkedEcoCard}>
                  <div style={aeMono({ color: AE.WARN, marginBottom: 4 })}>linked ECO</div>
                  <div style={{ fontSize: 13, fontFamily: AE.FONT_MONO, color: AE.MONO }}>{active.eco_link}</div>
                  <button onClick={function () {
                    fireFlash("Opening " + active.eco_link);
                    window.location.hash = "#/build/eco/" + encodeURIComponent(active.eco_link);
                  }}
                    style={_ae3_openEcoBtn}>Open ECO →</button>
                </div>
              ) : null}
            </div>
          );
        })() : null}
      </div>

      {/* footer summary */}
      <div style={Object.assign(aeCard({ marginTop: 18 }), {
        background: AE.INK_2, display: "grid",
        gridTemplateColumns: "repeat(4, 1fr)", gap: 18, textAlign: "center",
      })}>
        <div>
          <div style={aeMono()}>Modes ≥ 100 RPN</div>
          <div style={{ fontFamily: AE.FONT_MONO, fontSize: 22, fontWeight: 700, color: AE.BAD }}>{totalCrit}</div>
        </div>
        <div>
          <div style={aeMono()}>Modes 50–99</div>
          <div style={{ fontFamily: AE.FONT_MONO, fontSize: 22, fontWeight: 700, color: AE.WARN }}>{totalMid}</div>
        </div>
        <div>
          <div style={aeMono()}>Severity ≥ 7</div>
          <div style={{ fontFamily: AE.FONT_MONO, fontSize: 22, fontWeight: 700, color: AE.BAD }}>{sev7}</div>
        </div>
        <div>
          <div style={aeMono()}>Avg RPN</div>
          <div style={{ fontFamily: AE.FONT_MONO, fontSize: 22, fontWeight: 700, color: AE.MONO }}>{avgRpn}</div>
        </div>
      </div>

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

// ─────────────────────────────────────────────────── route registration
// Registers via registerSpaceRoute (SPACE_ROUTES) when present, falls
// back to registerPumpRoute (PUMP_ROUTES) so the screens are reachable
// even before space/registry-index.jsx lands.
(function aeRegisterRoutes() {
  const routes = [
    { path: "/forge/suppliers",      mode: "forge", title: "Aetherion · Suppliers",          renderer: function () { return React.createElement(ScreenAetherionSuppliers); } },
    { path: "/forge/vendor-onboard", mode: "forge", title: "Aetherion · Vendor onboarding",  renderer: function () { return React.createElement(ScreenAetherionVendorOnboard); } },
    { path: "/forge/audit",          mode: "forge", title: "Aetherion · Qualification review",renderer: function () { return React.createElement(ScreenAetherionQualReview); } },
    { path: "/forge/npi",            mode: "forge", title: "Aetherion · NPI plan",           renderer: function () { return React.createElement(ScreenAetherionNPI); } },
    { path: "/build/pfmea",          mode: "build", title: "Aetherion · PFMEA",              renderer: function () { return React.createElement(ScreenAetherionPFMEA); } },
  ];
  const reg = (typeof registerSpaceRoute === "function")
    ? registerSpaceRoute
    : (typeof registerPumpRoute === "function" ? registerPumpRoute : null);
  if (!reg) return;
  routes.forEach(function (r) { reg(r); });
})();

if (typeof window !== "undefined") {
  window.ScreenAetherionSuppliers     = ScreenAetherionSuppliers;
  window.ScreenAetherionVendorOnboard = ScreenAetherionVendorOnboard;
  window.ScreenAetherionQualReview    = ScreenAetherionQualReview;
  window.ScreenAetherionNPI           = ScreenAetherionNPI;
  window.ScreenAetherionPFMEA         = ScreenAetherionPFMEA;
  window.AE_SUPPLIERS_FALLBACK        = AE_SUPPLIERS_FALLBACK;
  window.AE_QUAL_ARTIFACTS_FALLBACK   = AE_QUAL_ARTIFACTS_FALLBACK;
  window.AE_NPI_STAGES_FALLBACK       = AE_NPI_STAGES_FALLBACK;
  window.AE_PFMEA_FALLBACK            = AE_PFMEA_FALLBACK;
  window.AE_AUDIT_TEMPLATE_FALLBACK   = AE_AUDIT_TEMPLATE_FALLBACK;
}
})();
