/* FORGE — pump-eco · ScreenECOCompose
   New ECO compose form, hero flow surface. Babel-standalone IIFE; no imports.
   Reads PUMP_TENANT.parts + people; mutates PUMP_TENANT.eco via window.forgeApi.eco.submit.

   Mounts at:  #/build/eco/new   (mode: build)

   Globals referenced (defined upstream in client/pump/act5-6-screens.jsx):
     - window.PUMP_TENANT
     - window.forgeApi.eco
     - window.useTenantState  (bump-on-tenant-change)
     - window.__forgeCurrentUser
     - window.SwitchUserPill, window.A56Btn, window.A56Pill, window.A56_PAPER, ...
     - registerPumpRoute (from pump/registry-index.jsx)
*/

(function eco_compose_iife() {
  if (typeof window === "undefined") return;

  const useS = React.useState;
  const useE = React.useEffect;
  const useM = React.useMemo;

  // ── Pre-fill template that matches the hero narrative (ECO-0051 NRV redesign).
  // We auto-increment the id from existing eco[], so the new draft will be
  // ECO-0052+ — the demo verbally bridges "this is ECO-0051" back to the audience.
  const HERO_TEMPLATE = {
    title: "NRV body redesign C.I. → S.G.-400 (HS variant)",
    reason: "5 field returns from Helios AgriFlow reporting NRV body cracking under pressure cycling on 86mm 2.0 variant. Material upgrade to S.G.-400 grade improves fatigue life ~4× per Spire Foundry test data.",
    parts_affected: [{ old: "20.07", new: "20.07b" }],
    proposed_change: "Replace C.I. body with S.G.-400 ductile-iron body on all M-27418 builds going forward.",
    cost_delta_inr: 190,
  };

  // Resolve the active tenant's data (multi-tenant safe). Used by nextEcoId
  // and ScreenECOCompose's parts lookup; both used to reach into PUMP_TENANT
  // directly which made the form Tritan-only.
  function activeTenantData() {
    if (typeof window === "undefined") return null;
    if (typeof window.useActiveTenant === "function") {
      // useActiveTenant is a React hook; not safe to call at top level.
      // Use getActiveTenant for non-hook callers like nextEcoId.
    }
    if (typeof window.getActiveTenant === "function") {
      try { return window.getActiveTenant(); } catch (_) { /* fall through */ }
    }
    return window.PUMP_TENANT || null;
  }

  function nextEcoId() {
    const td = activeTenantData();
    const ecos = (td && Array.isArray(td.eco))
      ? td.eco
      : (window.PUMP_TENANT && Array.isArray(window.PUMP_TENANT.eco) ? window.PUMP_TENANT.eco : []);
    const tid = (td && td.tenant && td.tenant.id) || "tritan";
    // Per-tenant id prefix: Tritan uses ECO-NNNN, Aetherion ECO-AET-NNNN,
    // Mittelstand ECO-MS-NNNN. Match the existing fixture pattern.
    const prefix = tid === "aetherion" ? "ECO-AET-"
                 : tid === "mittelstand" ? "ECO-MS-"
                 : "ECO-";
    const re = new RegExp("^" + prefix.replace(/[-]/g, "\\-") + "(\\d+)");
    let max = 0;
    ecos.forEach(function(e) {
      const m = re.exec(e.id || "");
      if (m) {
        const n = parseInt(m[1], 10);
        if (n > max) max = n;
      }
    });
    // Floor at 50 for Tritan to keep the demo numbering continuous
    // (ECO-0051 is the hero). Aetherion + Mittelstand floor at 0.
    if (tid === "tritan" && max < 50) max = 50;
    return prefix + ("0000" + (max + 1)).slice(-4);
  }

  function ScreenECOCompose() {
    // bump-on-tenant-change so the next-id stays accurate after a submit
    if (typeof window.useTenantState === "function") window.useTenantState();

    const P = window.A56_PAPER || {
      bg: "#fefefe", bg2: "#f5f5f5", bg3: "#e8e8e8",
      ink: "#111", ink2: "#444", ink3: "#666", ink4: "#999",
      line: "#ccc", lineSoft: "#e0e0e0",
      blue: "#1e6fd9", green: "#1f8a5b", red: "#c0392b", amber: "#b07c00",
      blueSoft: "#e6f0fb", greenSoft: "#e6f6ee", redSoft: "#fbe9e7", amberSoft: "#fdf3d8",
    };
    const FONT_UI = window.A56_FONT_UI || "var(--font-ui)";
    const FONT_MONO = window.A56_FONT_MONO || "var(--font-mono)";
    const FONT_SERIF = window.A56_FONT_SERIF || "var(--font-serif)";

    const A56Btn = window.A56Btn || (function(props) {
      return React.createElement("button", { type: "button", onClick: props.onClick, style: { padding: "6px 12px" } }, props.children);
    });
    const A56Pill = window.A56Pill || (function(props) {
      return React.createElement("span", null, props.children);
    });
    const SwitchUserPill = window.SwitchUserPill;

    const [title, setTitle] = useS("");
    const [reason, setReason] = useS("");
    const [proposedChange, setProposedChange] = useS("");
    const [costDelta, setCostDelta] = useS(0);
    const [selectedParts, setSelectedParts] = useS([]); // [{ old: partNum, new: "" }]
    const [partsQuery, setPartsQuery] = useS("");
    const [submitting, setSubmitting] = useS(false);
    const [flash, setFlash] = useS(null);

    // Multi-tenant: resolve via useActiveTenant; fall back to PUMP_TENANT for
    // legacy callers (tests / very early boot before active-tenant.jsx).
    const activeTenant = (typeof window.useActiveTenant === "function")
      ? window.useActiveTenant()
      : null;
    const tenant = activeTenant || window.PUMP_TENANT;
    const tenantId = (tenant && tenant.tenant && tenant.tenant.id) || "tritan";
    const allParts = (tenant && Array.isArray(tenant.parts)) ? tenant.parts : [];

    // Originator role must come from the active tenant's people, not a
    // hardcoded Tritan fallback. If the current user isn't part of this
    // tenant's roster, show "—" rather than a leaked Tritan role label.
    const people = (tenant && tenant.people) || [];
    const currentName = (window.__forgeCurrentUser && window.__forgeCurrentUser.name) || "";
    const matched = people.find(function(p) { return p.name === currentName; });
    const originatorRole = matched ? matched.role : "—";
    const cur = {
      id: (window.__forgeCurrentUser && window.__forgeCurrentUser.id) || (matched && matched.id) || "",
      name: currentName || (matched && matched.name) || "",
      role: originatorRole,
    };
    // Tenant-derived typical ECO originator. Pulls from the first ECO in the
    // tenant fixture (e.g. ECO-0051 for Tritan → Ishaan R. / Compliance Lead;
    // ECO-AET-0042 for Aetherion → M. Sato / Mech Lead; ECO-MS-0017 for
    // Mittelstand → R. Vogt / Engineering Lead). Avoids hardcoding Tritan-only
    // "Compliance Lead (Ishaan R.)" copy on Aetherion + Mittelstand screens.
    const firstEco = (tenant && Array.isArray(tenant.eco) && tenant.eco.length > 0) ? tenant.eco[0] : null;
    const typicalOriginatorName = (firstEco && firstEco.originator) || (people[0] && people[0].name) || "—";
    const typicalOriginatorRole = (function() {
      if (firstEco && firstEco.approval_chain && firstEco.approval_chain[0] && firstEco.approval_chain[0].role) {
        return firstEco.approval_chain[0].role;
      }
      const orig = people.find(function(p) { return p.name === typicalOriginatorName; });
      return orig ? orig.role : "—";
    })();
    const isTypicalOriginator = (originatorRole === typicalOriginatorRole);
    const isComplianceLead = isTypicalOriginator; // back-compat alias
    // Approval chain preview (auto-attached) — read from tenant's first ECO
    const typicalChain = (firstEco && Array.isArray(firstEco.approval_chain))
      ? firstEco.approval_chain.map(function(c) { return { role: c.role, name: c.name }; })
      : [];

    const ecoIdPreview = useM(nextEcoId, [submitting]); // recomputes on submit

    function applyHeroTemplate() {
      setTitle(HERO_TEMPLATE.title);
      setReason(HERO_TEMPLATE.reason);
      setProposedChange(HERO_TEMPLATE.proposed_change);
      setCostDelta(HERO_TEMPLATE.cost_delta_inr);
      setSelectedParts(HERO_TEMPLATE.parts_affected.slice());
      setFlash({ kind: "info", msg: "Hero template loaded — ECO-0051 NRV C.I. → S.G.-400" });
    }

    function clearForm() {
      setTitle(""); setReason(""); setProposedChange("");
      setCostDelta(0); setSelectedParts([]); setPartsQuery("");
    }

    function togglePart(partNum) {
      setSelectedParts(function(arr) {
        const ix = arr.findIndex(function(p) { return p.old === partNum; });
        if (ix >= 0) {
          const next = arr.slice(); next.splice(ix, 1); return next;
        }
        return arr.concat([{ old: partNum, new: "" }]);
      });
    }

    function setReplacement(partNum, replacement) {
      setSelectedParts(function(arr) {
        return arr.map(function(p) { return p.old === partNum ? Object.assign({}, p, { new: replacement }) : p; });
      });
    }

    function canSubmit() {
      return !!(title.trim() && reason.trim() && selectedParts.length > 0 && !submitting);
    }

    function onSubmit() {
      if (!canSubmit()) return;
      if (!window.forgeApi || !window.forgeApi.eco) {
        setFlash({ kind: "err", msg: "forgeApi.eco not available — bootstrap missing." });
        return;
      }
      setSubmitting(true);
      const id = nextEcoId();
      const today = new Date().toISOString().slice(0, 10);
      const partsAffected = selectedParts.map(function(p) {
        const meta = allParts.find(function(part) { return part.num === p.old; });
        return {
          old: meta ? (p.old + " " + meta.name) : p.old,
          new: p.new || (p.old + "b (new revision)"),
        };
      });

      // Build the 3-role approval chain from the active tenant's first ECO
      // (typicalChain). Tritan → Compliance Lead / Design Eng / Plant Director;
      // Aetherion → Mech Lead / QA Lead / Mission Director; Mittelstand →
      // Engineering Lead / Quality / Production. Falls back to the Tritan
      // shape only if the tenant has no ECOs to copy from. If the originator's
      // role matches one of the chain roles, count their submission as that
      // role's sign-off (matches ECO-0051 fixture shape).
      const fallbackChain = [
        { role: "Compliance Lead", name: "Ishaan R.",  at: null, status: "pending" },
        { role: "Design Eng",      name: "Devansh A.", at: null, status: "pending" },
        { role: "Plant Director",  name: "Meera S.",   at: null, status: "pending" },
      ];
      const baseChain = typicalChain.length > 0
        ? typicalChain.map(function(c) { return { role: c.role, name: c.name, at: null, status: "pending" }; })
        : fallbackChain;
      const approval_chain = baseChain.map(function(c) {
        if (c.role === cur.role) {
          return Object.assign({}, c, { name: cur.name, status: "approved", at: today });
        }
        return c;
      });

      // Pull currency from the resolved tenant config (set by
      // forgeApi.fetchConfig() at boot). Falls back to INR for the Tritan
      // demo. The DB column is `cost_delta_amount_minor` (minor units, e.g.
      // paise/cents); persistSection writes this exact field, so without it
      // the new ECO row would round-trip as +₹0/u after the SSE refresh.
      const cfgForCcy = (typeof window !== "undefined") ? window.__forgeConfig : null;
      const ccy = (cfgForCcy && cfgForCcy.currency) || "INR";
      const costMajor = Number(costDelta) || 0;
      const costMinor = String(Math.round(costMajor * 100));
      const eco = {
        id: id,
        title: title.trim(),
        originator: cur.name,
        status: "draft",
        date_raised: today,
        justification: reason.trim() + (proposedChange.trim() ? ("\n\nProposed change:\n" + proposedChange.trim()) : ""),
        parts_affected: partsAffected,
        cost_delta_inr: costMajor, // legacy field; kept for screens that read PUMP_TENANT directly
        cost_delta_amount_minor: costMinor,
        cost_delta_currency: ccy,
        approval_chain: approval_chain,
        transitions: [{ from: null, to: "draft", actor: cur.name, ts: new Date().toISOString() }],
      };

      window.forgeApi.eco.submit(eco)
        .then(function() {
          setSubmitting(false);
          setFlash({ kind: "ok", msg: id + " created as draft. Click 'Submit for review' on the detail page." });
          // Navigate to the new ECO's detail page so the user immediately
          // sees their freshly composed ECO highlighted in the list +
          // detail pane. /build/eco/:id is a parametric route; the static
          // /build/eco/new route still wins for compose because exact-
          // match-first ordering is enforced in router.jsx#App().
          const detailPath = "/build/eco/" + encodeURIComponent(id);
          setTimeout(function() {
            if (typeof navigate === "function") navigate(detailPath);
            else window.location.hash = detailPath;
          }, 600);
          clearForm();
        })
        .catch(function(err) {
          setSubmitting(false);
          setFlash({ kind: "err", msg: "Submit failed: " + (err && err.message || err) });
        });
    }

    // ── styles
    const sCol = { padding: 14, display: "grid", gridTemplateColumns: "1fr 360px", gap: 14, minHeight: 0, height: "100%" };
    const sCard = { background: P.bg2, border: "1px solid " + P.line, borderRadius: 8, padding: 16 };
    const sLabel = { fontFamily: FONT_MONO, fontSize: 12, letterSpacing: "0.10em", textTransform: "uppercase", color: P.ink3, marginBottom: 6 };
    const sInput = { width: "100%", padding: "8px 10px", border: "1px solid " + P.line, borderRadius: 4, fontFamily: FONT_UI, fontSize: 13, color: P.ink, background: P.bg, boxSizing: "border-box" };
    const sTextarea = Object.assign({}, sInput, { resize: "vertical", minHeight: 60, fontFamily: FONT_UI });
    const sToolbar = { display: "flex", justifyContent: "space-between", alignItems: "center", gap: 10, marginBottom: 12 };
    const sH = { fontFamily: FONT_SERIF, fontSize: 22, color: P.ink, marginBottom: 4 };
    const sSub = { fontFamily: FONT_UI, fontSize: 13, color: P.ink3, marginBottom: 14 };

    // Filter parts by query for the multi-select. Only top-N to keep render snappy.
    const filteredParts = allParts.filter(function(p) {
      if (!partsQuery) return true;
      const q = partsQuery.toLowerCase();
      return (p.num && p.num.toLowerCase().indexOf(q) >= 0) || (p.name && p.name.toLowerCase().indexOf(q) >= 0);
    }).slice(0, 30);

    return (
      <div style={sCol}>
        {/* Left: compose form */}
        <div style={sCard}>
          <div style={sToolbar}>
            <div>
              <div style={sH}>Compose new ECO</div>
              <div style={sSub}>
                Will be raised as <span style={{ fontFamily: FONT_MONO, color: P.ink }}>{ecoIdPreview}</span>
                {" "}· originator <span style={{ color: P.ink }}>{cur.name}</span> ({cur.role})
              </div>
            </div>
            <div style={{ display: "flex", gap: 8, alignItems: "center" }}>
              {SwitchUserPill && React.createElement(SwitchUserPill)}
              <A56Btn small onClick={applyHeroTemplate}>Load hero template (ECO-0051)</A56Btn>
              <A56Btn small onClick={clearForm}>Clear</A56Btn>
            </div>
          </div>

          {!isTypicalOriginator && cur.name && (
            <div style={{ padding: 10, marginBottom: 14, background: P.amberSoft, border: "1px solid " + P.amber, borderRadius: 4, fontFamily: FONT_UI, fontSize: 12, color: P.amber }}>
              Note: ECOs are typically raised by the {typicalOriginatorRole} ({typicalOriginatorName}). You are acting as <b>{cur.name}</b> ({cur.role}). The originator stamp will reflect this.
            </div>
          )}

          {(function() {
            // Currency-aware label: read the tenant's currency from the
            // resolved config (set by forgeApi.fetchConfig()). The tenant
            // symbol stays embedded in the legacy ₹ string for backward
            // compat if config hasn't resolved yet. Threshold remains in
            // major units of the tenant currency (500 INR for Tritan).
            const cfg = (typeof window !== "undefined") ? window.__forgeConfig : null;
            const ccy = (cfg && cfg.currency) || "INR";
            const symbolMap = { INR: "₹", USD: "$", EUR: "€" };
            const symbol = symbolMap[ccy] || (ccy + " ");
            const thresholdMajor = 500;
            const i18n = (typeof window !== "undefined") ? window.forgeI18n : null;
            const thresholdLabel = (i18n && typeof i18n.formatMoneyMinor === "function")
              ? (i18n.formatMoneyMinor(String(thresholdMajor * 100), ccy) || (symbol + thresholdMajor))
              : (symbol + thresholdMajor);
            return (
              <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 14 }}>
                <div>
                  <div style={sLabel}>Title</div>
                  <input id="eco-title" name="eco-title" aria-label="ECO title" style={sInput} value={title} onChange={function(e) { setTitle(e.target.value); }} placeholder="e.g. NRV body redesign C.I. → S.G.-400"/>
                </div>
                <div>
                  <div style={sLabel}>Cost delta ({symbol} / unit)</div>
                  <input id="eco-cost-delta" name="eco-cost-delta" aria-label="Cost delta per unit" style={sInput} type="number" value={costDelta} onChange={function(e) { setCostDelta(e.target.value); }} placeholder="0"/>
                  <div style={{ marginTop: 4, fontFamily: FONT_MONO, fontSize: 12, color: Number(costDelta) > thresholdMajor ? P.red : P.ink3 }}>
                    {Number(costDelta) > thresholdMajor ? ("Note: cost delta > " + thresholdLabel + " will require Plant Director sign-off at release.") : ""}
                  </div>
                </div>
              </div>
            );
          })()}

          <div style={{ marginTop: 14 }}>
            <div style={sLabel}>Reason / justification</div>
            <textarea id="eco-reason" name="eco-reason" aria-label="Reason and justification" rows={4} style={sTextarea} value={reason} onChange={function(e) { setReason(e.target.value); }} placeholder="Why is this change needed? Field-return counts, test data, customer impact."/>
          </div>

          <div style={{ marginTop: 14 }}>
            <div style={sLabel}>Proposed change</div>
            <textarea id="eco-proposed-change" name="eco-proposed-change" aria-label="Proposed change" rows={3} style={sTextarea} value={proposedChange} onChange={function(e) { setProposedChange(e.target.value); }} placeholder="The change itself — material, geometry, supplier, or test."/>
          </div>

          <div style={{ marginTop: 14 }}>
            <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center" }}>
              <div style={sLabel}>Parts affected ({selectedParts.length})</div>
              <input id="eco-parts-filter" name="eco-parts-filter" aria-label="Filter parts" style={Object.assign({}, sInput, { width: 220, padding: "6px 10px" })} value={partsQuery} onChange={function(e) { setPartsQuery(e.target.value); }} placeholder="filter by num or name"/>
            </div>

            {selectedParts.length > 0 && (
              <div style={{ marginTop: 8, border: "1px solid " + P.line, borderRadius: 4, overflow: "hidden" }}>
                <table className="dtable" style={{ width: "100%" }}>
                  <thead>
                    <tr>
                      <th>Old part</th>
                      <th>→</th>
                      <th>New part (free-text)</th>
                      <th style={{ width: 70 }}></th>
                    </tr>
                  </thead>
                  <tbody>
                    {selectedParts.map(function(p) {
                      const meta = allParts.find(function(part) { return part.num === p.old; });
                      return (
                        <tr key={p.old}>
                          <td style={{ fontFamily: FONT_MONO }}>{p.old}{meta ? " · " + meta.name : ""}</td>
                          <td className="dim">→</td>
                          <td>
                            <input id={"eco-repl-" + p.old} name={"eco-repl-" + p.old} aria-label={"Replacement part for " + p.old} style={Object.assign({}, sInput, { padding: "4px 6px" })} value={p.new} onChange={function(e) { setReplacement(p.old, e.target.value); }} placeholder={p.old + "b (new revision)"}/>
                          </td>
                          <td>
                            <A56Btn small onClick={function() { togglePart(p.old); }}>remove</A56Btn>
                          </td>
                        </tr>
                      );
                    })}
                  </tbody>
                </table>
              </div>
            )}

            <div style={{ marginTop: 10, maxHeight: 260, overflow: "auto", border: "1px solid " + P.lineSoft, borderRadius: 4 }}>
              {filteredParts.length === 0 && (
                <div style={{ padding: 12, fontFamily: FONT_UI, fontSize: 13, color: P.ink3 }}>No parts match the filter.</div>
              )}
              {filteredParts.map(function(part) {
                const checked = selectedParts.some(function(p) { return p.old === part.num; });
                return (
                  <label key={part.num} style={{
                    display: "grid", gridTemplateColumns: "20px 90px 1fr 120px", gap: 8, alignItems: "center",
                    padding: "6px 10px", borderBottom: "1px solid " + P.lineSoft, cursor: "pointer",
                    background: checked ? P.bg3 : "transparent",
                  }}>
                    <input id={"eco-part-" + part.num} name={"eco-part-" + part.num} type="checkbox" checked={checked} onChange={function() { togglePart(part.num); }}/>
                    <span style={{ fontFamily: FONT_MONO, fontSize: 12, color: P.ink2 }}>{part.num}</span>
                    <span style={{ fontFamily: FONT_UI, fontSize: 12, color: P.ink }}>{part.name}</span>
                    <span style={{ fontFamily: FONT_MONO, fontSize: 12, color: P.ink3 }}>{part.supplier}</span>
                  </label>
                );
              })}
            </div>
          </div>

          <div style={{ marginTop: 18, display: "flex", justifyContent: "flex-end", gap: 8 }}>
            <A56Btn onClick={function() { if (typeof navigate === "function") navigate("/build/eco"); else window.location.hash = "/build/eco"; }}>Cancel</A56Btn>
            <A56Btn variant="primary" onClick={onSubmit}>
              {submitting ? "Submitting…" : "Submit as draft"}
            </A56Btn>
          </div>

          {flash && (
            <div style={{
              marginTop: 14, padding: "10px 12px", borderRadius: 4,
              background: flash.kind === "ok" ? P.greenSoft : flash.kind === "err" ? P.redSoft : P.blueSoft,
              border: "1px solid " + (flash.kind === "ok" ? P.green : flash.kind === "err" ? P.red : P.blue),
              color: flash.kind === "ok" ? P.green : flash.kind === "err" ? P.red : P.blue,
              fontFamily: FONT_UI, fontSize: 13,
            }}>
              {flash.msg}
            </div>
          )}
        </div>

        {/* Right: state machine + hero hint */}
        <div style={sCard}>
          <div style={sLabel}>State machine</div>
          <div style={{ fontFamily: FONT_MONO, fontSize: 12, color: P.ink2, lineHeight: 1.65 }}>
            draft <span style={{ color: P.ink4 }}>→</span> in-review <span style={{ color: P.ink4 }}>→</span> approved | rejected <span style={{ color: P.ink4 }}>→</span> released <span style={{ color: P.ink4 }}>→</span> applied
          </div>

          <div style={Object.assign({}, sLabel, { marginTop: 18 })}>Approval chain (auto-attached)</div>
          <ol style={{ margin: 0, paddingLeft: 18, fontFamily: FONT_UI, fontSize: 13, color: P.ink2, lineHeight: 1.6 }}>
            {typicalChain.length > 0
              ? typicalChain.map(function(c, i) {
                  return <li key={i}>{c.role} · {c.name}</li>;
                })
              : <li style={{ color: P.ink4 }}>(approval chain will be auto-attached from the tenant's policy)</li>}
          </ol>

          <div style={Object.assign({}, sLabel, { marginTop: 18 })}>Hero demo · ECO-0051</div>
          <div style={{ fontFamily: FONT_UI, fontSize: 12, color: P.ink3, lineHeight: 1.5 }}>
            Click <b>Load hero template</b> to pre-fill with the NRV C.I. → S.G.-400 redesign. The new ECO id will auto-increment (e.g. ECO-0052) so the demo can re-run cleanly.
          </div>

          <div style={Object.assign({}, sLabel, { marginTop: 18 })}>Next step</div>
          <div style={{ fontFamily: FONT_UI, fontSize: 12, color: P.ink3, lineHeight: 1.5 }}>
            After submit, switch user to <b>Devansh A.</b> and click "Submit for review" on the detail page. Then Devansh, then Meera approve. Finally switch to <b>Priya I.</b> and head to the ERP release queue.
          </div>
        </div>
      </div>
    );
  }

  // ── route registration (all 3 tenants — was tritan-only)
  // Minimum viable cross-tenant fix: same form, same forgeApi.eco.submit. The
  // tenant-specific verb buttons (Aetherion gate-approve, Mittelstand PPAP
  // sign-off) are not yet exposed in this composer — those live in the ECO
  // detail page where the FSM core picks up the right verbs per tenant.
  const composeRoute = {
    path: "/build/eco/new",
    mode: "build",
    title: "New ECO",
    renderer: function() { return React.createElement(ScreenECOCompose); },
  };
  if (typeof registerPumpRoute === "function") {
    registerPumpRoute(composeRoute);
  }
  if (typeof registerAetherionRoute === "function") {
    registerAetherionRoute(composeRoute);
  }
  if (typeof registerMittelstandRoute === "function") {
    registerMittelstandRoute(composeRoute);
  }

  // ── global exposure
  window.ScreenECOCompose = ScreenECOCompose;
})();
