(function(){
/* FORGE — Mittelstand · Plan-mode Gantt. Wave A1 / Agent #15 (gantt-flavor).
   Renders ScreenMittelstandGantt at /plan/gantt. Spec §5 + §6 anchor the
   seven bands and the ECO ribbon. Critical path is the 180-d GMN spindle.
   Babel-standalone, single file, no ES imports/exports. Globals consumed:
   React, getActiveTenant, useActiveTenant, navigate, Panel/Pill/Btn (ui.jsx),
   registerMittelstandRoute (preferred) or registerPumpRoute (fallback). */

const { useState: uSMG, useMemo: uMMG } = React;

// Cool ink ramp per spec §10. STEEL is the steel-blue accent, BAD is
// critical-path red, WARN is tolerance amber for the ECO ribbon.
const MG = {
  BG: "oklch(0.97 0.003 250)", BG_2: "oklch(0.92 0.004 250)", BG_3: "oklch(0.95 0.003 250)",
  INK: "oklch(0.18 0.01 250)", INK_2: "oklch(0.32 0.01 250)",
  INK_3: "oklch(0.48 0.01 250)", INK_4: "oklch(0.62 0.005 250)",
  LINE: "oklch(0.82 0.005 250)", LINE_SOFT: "oklch(0.88 0.004 250)",
  STEEL: "oklch(0.50 0.02 250)", WARN: "oklch(0.55 0.13 60)",
  BAD: "oklch(0.55 0.18 25)", OK: "oklch(0.50 0.13 150)", COOL: "oklch(0.50 0.13 240)",
  FONT_UI: "var(--font-ui)", FONT_MONO: "var(--font-mono)", FONT_SER: "var(--font-serif)",
};

// 16-month program window: 2025-09 → 2026-12. All dates project to a
// month-fractional index so a single SVG x-mapping works for everything.
const MG_WINDOW_START = new Date(Date.UTC(2025, 8, 1));
const MG_WINDOW_END   = new Date(Date.UTC(2026, 11, 31));
const MG_TOTAL_MONTHS = 16;

const MG_MONTHS = [
  ["2025-09","Sep'25"],["2025-10","Oct"],["2025-11","Nov"],["2025-12","Dec"],
  ["2026-01","Jan'26"],["2026-02","Feb"],["2026-03","Mar"],["2026-04","Apr"],
  ["2026-05","May"],  ["2026-06","Jun"], ["2026-07","Jul"],["2026-08","Aug"],
  ["2026-09","Sep"],  ["2026-10","Oct"], ["2026-11","Nov"],["2026-12","Dec"],
];

// 2026-04-15: demo "today" — just past granite rework, approaching FA.
const MG_TODAY = new Date(Date.UTC(2026, 3, 15));

function mgDateToIdx(d) {
  if (typeof d === "string") d = new Date(d + "T00:00:00Z");
  if (!(d instanceof Date) || isNaN(d.getTime())) return 0;
  const ms = d.getTime() - MG_WINDOW_START.getTime();
  const totalMs = MG_WINDOW_END.getTime() - MG_WINDOW_START.getTime();
  return Math.max(0, Math.min(MG_TOTAL_MONTHS, (ms / totalMs) * MG_TOTAL_MONTHS));
}

// Seven §5 bands. `critical` tags the spindle-paced 180-d path. `ecoOverlay`
// draws the ECO-MS-0017 ribbon over the granite-rework band. `fai`/`ship`
// host the 2026-08-14 and 2026-12-15 milestone markers.
const MG_BANDS = [
  { id: "B1", code: "BAND-01", name: "Frame contract", detail: "MAHLE annual call-off · 24 mills · 2-batch FY split",
    start: "2025-09-01", end: "2025-11-15", lane: "commercial", risk: "low", riskLabel: "Signed · no hold",
    owner: "S. Klein · Account", receipts: ["FRAME_CONTRACT_SIGNED", "RFQ_RECEIVED", "QUOTE_SENT"],
    color: MG.STEEL, progress: 1.0 },
  { id: "B2", code: "BAND-02", name: "Eng Rev D freeze", detail: "Carryover diff Rev C → Rev D · ECO-MS-0017 raised against 10.01 / 10.02",
    start: "2025-10-15", end: "2025-12-20", lane: "engineering", risk: "med", riskLabel: "Quality CMM gauge R&R pending",
    owner: "R. Vogt · Eng Lead", receipts: ["ECO_RAISED", "DESIGN_MATCH", "CARRYOVER_DIFF"],
    color: MG.STEEL, progress: 1.0 },
  { id: "B3", code: "BAND-03", name: "Long-lead release", detail: "GMN spindle 180 d · Heidenhain TNC 640 45 d · Kessler head 90 d",
    start: "2026-01-05", end: "2026-06-30", lane: "procurement", risk: "high", riskLabel: "GMN single-source · 180-d critical path",
    owner: "D. Becker · Mfg Lead", receipts: ["LONG_LEAD_PO_RELEASED", "GATES_PUBLISHED"],
    color: MG.BAD, progress: 0.65, critical: true },
  { id: "B4", code: "BAND-04", name: "Granite rework", detail: "Re-grind op qualified · flatness ±5 µm → ±3 µm · two-pass lap",
    start: "2026-02-10", end: "2026-04-10", lane: "manufacturing", risk: "med", riskLabel: "+11 d on granite path · slack under spindle CP",
    owner: "D. Becker · Mfg Lead", receipts: ["ROUTING_REVISED", "ECO_APPROVED"],
    color: MG.WARN, progress: 0.92, ecoOverlay: true },
  { id: "B5", code: "BAND-05", name: "First article", detail: "Unit 1 of 24 · spindle alignment · run-out < 4 µm TIR @ 24k rpm",
    start: "2026-06-01", end: "2026-08-10", lane: "manufacturing", risk: "med", riskLabel: "Awaiting GMN spindle land",
    owner: "D. Becker · Mfg Lead", receipts: ["WO_RELEASED", "SUBASSY_COMPLETED", "DIM_INSPECTED"],
    color: MG.STEEL, progress: 0.18 },
  { id: "B6", code: "BAND-06", name: "FAI · PPAP L3", detail: "ISO 230-2 · ballbar · vibration ≤ 0.8 mm/s RMS · MAHLE witness",
    start: "2026-08-01", end: "2026-08-25", lane: "quality", risk: "med", riskLabel: "Vibration bench depends on Rev D granite",
    owner: "S. Klein · Quality Lead", receipts: ["FAI_PACKAGE_GENERATED", "FAI_PASSED", "CUSTOMER_WITNESSED"],
    color: MG.OK, progress: 0.0, fai: true },
  { id: "B7", code: "BAND-07", name: "Batch-1 ship", detail: "12 units acceptance signed · batch-2 release into 2027",
    start: "2026-09-01", end: "2026-12-20", lane: "commercial", risk: "low", riskLabel: "Logistics single ramp · low risk",
    owner: "S. Klein · Account", receipts: ["ACCEPTANCE_SIGNED"],
    color: MG.OK, progress: 0.0, ship: true },
];

const MG_LANES = [
  { id: "commercial",    label: "Commercial",    color: MG.STEEL },
  { id: "engineering",   label: "Engineering",   color: MG.COOL  },
  { id: "procurement",   label: "Procurement",   color: MG.BAD   },
  { id: "manufacturing", label: "Manufacturing", color: MG.WARN  },
  { id: "quality",       label: "Quality",       color: MG.OK    },
];

const MG_MILESTONES = [
  { id: "MS-FAI",  date: "2026-08-14", label: "FAI pass · TRV-MS-0244", tone: "ok" },
  { id: "MS-SHIP", date: "2026-12-15", label: "Batch-1 ship-accept",    tone: "accent" },
];

// ECO-MS-0017 envelope — ribbon spans 2025-11 raise → 2026-04 close.
const MG_ECO = {
  id: "ECO-MS-0017", title: "Granite flatness tightening · Rev C → Rev D",
  raised: "2025-11-08", approved: "2025-12-12", closed: "2026-04-10",
  costDelta: "+€820 / unit", leadDelta: "+11 d on granite path",
  spec: "10.01 / 10.02 flatness ±5 µm → ±3 µm · two-pass lap with re-grind",
};

// Locale-aware money/date — degrades gracefully when forgeI18n not yet loaded.
function _mg_money(minor, currency, fallback) {
  const i18n = (typeof window !== "undefined") ? window.forgeI18n : null;
  if (i18n && typeof i18n.formatMoneyMinor === "function") {
    const out = i18n.formatMoneyMinor(minor, currency || "EUR");
    if (out) return out;
  }
  return fallback;
}
function _mg_date(iso, fallback) {
  const i18n = (typeof window !== "undefined") ? window.forgeI18n : null;
  if (i18n && typeof i18n.formatDate === "function") {
    const out = i18n.formatDate(iso);
    if (out) return out;
  }
  return fallback || iso;
}

function mgRiskTone(r) { return r === "high" ? MG.BAD : r === "med" ? MG.WARN : MG.OK; }
function mgBandColor(b) { return b.critical ? MG.BAD : (b.color || MG.STEEL); }

// Extracted styles (react-doctor: no-inline-exhaustive-style).
const MG_GANTT_ROOT_STYLE = {
  padding: 14, display: "grid", gap: 14, height: "100%", minHeight: 0,
  gridTemplateColumns: "1fr 320px", gridTemplateRows: "auto 1fr",
  background: MG.BG,
};
function mgBandBtnStyle(active, isLast) {
  return {
    textAlign: "left",
    background: active ? "color-mix(in oklch," + MG.STEEL + " 8%, transparent)" : "transparent",
    borderRight: !isLast ? "1px solid " + MG.LINE_SOFT : "none",
    borderTop: "none", borderLeft: "none", borderBottom: "none",
    padding: "10px 12px", cursor: "pointer",
    fontFamily: MG.FONT_UI, color: MG.INK_2,
  };
}
function mgRiskRowStyle(sel) {
  return {
    display: "grid", gridTemplateColumns: "16px 1fr auto",
    gap: 8, alignItems: "center",
    padding: "6px 0",
    borderBottom: "1px solid " + MG.LINE_SOFT,
    cursor: "pointer",
    background: sel ? "color-mix(in oklch," + MG.STEEL + " 6%, transparent)" : "transparent",
  };
}
function mgRiskDot(r) {
  return <span style={{ display: "inline-block", width: 7, height: 7, borderRadius: 999,
    background: mgRiskTone(r), boxShadow: "0 0 0 2px " + MG.BG }} />;
}
function mgKV(k, v, mono) {
  return (
    <div style={{ display: "grid", gridTemplateColumns: "108px 1fr", gap: 10, padding: "4px 0", borderBottom: "1px solid " + MG.LINE_SOFT }}>
      <span style={{ fontFamily: MG.FONT_MONO, fontSize: 12, letterSpacing: "0.08em", textTransform: "uppercase", color: MG.INK_3 }}>{k}</span>
      <span style={{ fontFamily: mono ? MG.FONT_MONO : MG.FONT_UI, fontSize: 12, color: MG.INK_2, lineHeight: 1.4 }}>{v}</span>
    </div>
  );
}

function _MGHeaderStrip({ selected, setSelected, showCP, setShowCP, showECO, setShowECO }) {
  return (
    <Panel style={{ gridColumn: "1/-1" }}
      title={"MTL-220 Rev D · Program Gantt · 2025-09 → 2026-12"}
      right={
        <>
          <Btn size="sm" variant={showCP ? "primary" : "ghost"} onClick={function () { setShowCP(!showCP); }}>
            {showCP ? "Hide CP" : "Show CP"}
          </Btn>
          <Btn size="sm" variant={showECO ? "primary" : "ghost"} onClick={function () { setShowECO(!showECO); }}>
            {showECO ? "Hide ECO" : "Show ECO"}
          </Btn>
          <Btn size="sm" icon="ArrowD" onClick={() => window.forgeToast && window.forgeToast("Gantt export queued — wired in v2")}>Export</Btn>
        </>
      }>
      <div style={{ display: "grid", gridTemplateColumns: "repeat(7,1fr)", borderTop: "1px solid " + MG.LINE_SOFT }}>
        {MG_BANDS.map(function (b, i) {
          const active = b.id === selected;
          return (
            <button key={b.id}
              onClick={function () { setSelected(b.id); }}
              style={mgBandBtnStyle(active, i >= MG_BANDS.length - 1)}>
              <div style={{ display: "flex", alignItems: "center", gap: 6 }}>
                {mgRiskDot(b.risk)}
                <span style={{ fontFamily: MG.FONT_MONO, fontSize: 12, letterSpacing: "0.04em", color: MG.INK_3 }}>{b.code}</span>
              </div>
              <div style={{ fontSize: 13, color: MG.INK, marginTop: 4, lineHeight: 1.2 }}>{b.name}</div>
              <div style={{ fontFamily: MG.FONT_MONO, fontSize: 12, color: MG.INK_3, marginTop: 4 }}>
                {b.start.slice(2,7)} → {b.end.slice(2,7)}
              </div>
              {b.critical && (
                <div style={{ marginTop: 4, fontFamily: MG.FONT_MONO, fontSize: 12, letterSpacing: "0.08em", color: MG.BAD, textTransform: "uppercase" }}>
                  · Critical path
                </div>
              )}
              {b.ecoOverlay && (
                <div style={{ marginTop: 4, fontFamily: MG.FONT_MONO, fontSize: 12, letterSpacing: "0.08em", color: MG.WARN, textTransform: "uppercase" }}>
                  · {MG_ECO.id}
                </div>
              )}
            </button>
          );
        })}
      </div>
    </Panel>
  );
}

function _MGDetailPanel({ selectedBand, selected, setSelected }) {
  if (!selectedBand) {
    return (
      <Panel title="Select a band">
        <div style={{ padding: 24, textAlign: "center", color: MG.INK_3 }}>
          <div style={{ fontFamily: MG.FONT_MONO, fontSize: 12 }}>
            Click any band to inspect.
          </div>
        </div>
      </Panel>
    );
  }
  return (
    <>
      <Panel title={selectedBand.code + " · " + selectedBand.name}
        right={
          <Pill tone={selectedBand.risk === "high" ? "err" : selectedBand.risk === "med" ? "warn" : "ok"} dot={false}>
            RISK · {selectedBand.risk.toUpperCase()}
          </Pill>
        }>
        <div style={{ padding: 12 }}>
          <div style={{ fontFamily: MG.FONT_SER, fontSize: 16, color: MG.INK, lineHeight: 1.3 }}>
            {selectedBand.detail}
          </div>
          <div style={{ height: 10 }} />
          {mgKV("Window", selectedBand.start + "  →  " + selectedBand.end, true)}
          {mgKV("Lane", (MG_LANES.find(function (l) { return l.id === selectedBand.lane; }) || {}).label || selectedBand.lane)}
          {mgKV("Owner", selectedBand.owner)}
          {mgKV("Progress", Math.round(selectedBand.progress * 100) + "%", true)}
          {mgKV("Risk note", selectedBand.riskLabel)}
          {selectedBand.critical && mgKV("Path", "Critical · paces program", false)}
          {selectedBand.ecoOverlay && mgKV("ECO", MG_ECO.id + " · " + MG_ECO.spec, false)}
          {selectedBand.fai && mgKV("Milestone", "FAI 2026-08-14 · TRV-MS-0244", true)}
          {selectedBand.ship && mgKV("Milestone", "Batch-1 ship 2026-12-15", true)}
          <div style={{ height: 12 }} />
          <div style={{ fontFamily: MG.FONT_MONO, fontSize: 12, letterSpacing: "0.08em", textTransform: "uppercase", color: MG.INK_3, marginBottom: 6 }}>
            Ledger receipts emitted
          </div>
          <div style={{ display: "flex", flexWrap: "wrap", gap: 6 }}>
            {selectedBand.receipts.map(function (r) {
              return (
                <span key={r} style={{
                  fontFamily: MG.FONT_MONO, fontSize: 12,
                  padding: "3px 8px", borderRadius: 3,
                  border: "1px solid " + MG.LINE,
                  background: MG.BG_3, color: MG.INK_2,
                }}>{r}</span>
              );
            })}
          </div>
          <div style={{ height: 14 }} />
          <Btn size="sm" variant="primary"
            onClick={function () {
              if (typeof navigate === "function") {
                if (selectedBand.id === "B2" || selectedBand.ecoOverlay) navigate("/build/eco");
                else if (selectedBand.id === "B6") navigate("/traveler/test");
                else if (selectedBand.id === "B5") navigate("/traveler/subassy");
                else if (selectedBand.id === "B7") navigate("/forge/acceptance");
                else navigate("/forge/dashboard");
              }
            }}>
            Open detail →
          </Btn>
        </div>
      </Panel>

      {selectedBand.ecoOverlay && (
        <Panel title={MG_ECO.id + " · ribbon"}>
          <div style={{ padding: 12 }}>
            <div style={{ fontFamily: MG.FONT_SER, fontSize: 14, color: MG.INK, lineHeight: 1.3 }}>
              {MG_ECO.title}
            </div>
            <div style={{ height: 10 }} />
            {mgKV("Raised",   _mg_date(MG_ECO.raised, MG_ECO.raised),   true)}
            {mgKV("Approved", _mg_date(MG_ECO.approved, MG_ECO.approved), true)}
            {mgKV("Closed",   _mg_date(MG_ECO.closed, MG_ECO.closed),   true)}
            {mgKV("Cost Δ",   "+" + _mg_money("82000", "EUR", "€820") + " / unit", true)}
            {mgKV("Lead Δ",   MG_ECO.leadDelta,true)}
            {mgKV("Spec",     MG_ECO.spec)}
          </div>
        </Panel>
      )}

      <Panel title="Risk indicators">
        <div style={{ padding: 12 }}>
          {MG_BANDS.map(function (b) {
            const sel = b.id === selected;
            return (
              <div key={b.id}
                role="button"
                tabIndex={0}
                onClick={function () { setSelected(b.id); }}
                onKeyDown={function (e) { if (e.key === "Enter" || e.key === " ") { e.preventDefault(); setSelected(b.id); } }}
                style={mgRiskRowStyle(sel)}>
                {mgRiskDot(b.risk)}
                <div>
                  <div style={{ fontSize: 12, color: MG.INK_2 }}>{b.name}</div>
                  <div style={{ fontFamily: MG.FONT_MONO, fontSize: 12, color: MG.INK_3 }}>
                    {b.riskLabel}
                  </div>
                </div>
                <span style={{
                  fontFamily: MG.FONT_MONO, fontSize: 12,
                  color: mgRiskTone(b.risk), textTransform: "uppercase",
                  letterSpacing: "0.08em",
                }}>{b.risk}</span>
              </div>
            );
          })}
        </div>
      </Panel>
    </>
  );
}

function ScreenMittelstandGantt() {
  const tenant = useActiveTenant();
  const [selected, setSelected]     = uSMG("B3"); // critical-path band default
  const [laneFilter, setLaneFilter] = uSMG("all");
  const [showECO, setShowECO]       = uSMG(true);
  const [showCP, setShowCP]         = uSMG(true);

  const selectedBand = uMMG(function () {
    return MG_BANDS.find(function (b) { return b.id === selected; }) || null;
  }, [selected]);

  // SVG sized in absolute units; parent scrollbox handles overflow
  // (same approach as lifecycle-gantt.jsx ScreenGantt).
  const RAIL_W = 220, SVG_W = 1180, ROW_H = 38, HDR_H = 44, LANE_PAD = 8;
  const COL = SVG_W / MG_TOTAL_MONTHS;

  const bands = uMMG(function () {
    return MG_BANDS.map(function (b) {
      const sx = mgDateToIdx(b.start) * COL, ex = mgDateToIdx(b.end) * COL;
      return Object.assign({}, b, { x: sx, w: Math.max(ex - sx, 6) });
    });
  }, [COL]);

  const visibleBands = bands.filter(function (b) {
    return laneFilter === "all" || b.lane === laneFilter;
  });

  const laneRows = uMMG(function () {
    let y = HDR_H; const map = {};
    MG_LANES.forEach(function (lane) {
      const lb = visibleBands.filter(function (b) { return b.lane === lane.id; });
      if (lb.length === 0 && laneFilter !== "all") return;
      map[lane.id] = { y: y, bands: lb };
      y += LANE_PAD * 2 + Math.max(lb.length, 1) * ROW_H + 6;
    });
    return { map: map, totalH: y + 24 };
  }, [visibleBands, laneFilter]);

  const totalH = laneRows.totalH;
  const todayX = mgDateToIdx(MG_TODAY) * COL;
  // Critical-path corridor: 180-d spindle, B3 release → FAI 2026-08-14.
  const cpFrom = mgDateToIdx("2026-01-05") * COL, cpTo = mgDateToIdx("2026-08-14") * COL;
  const ecoFrom = mgDateToIdx(MG_ECO.raised) * COL, ecoTo = mgDateToIdx(MG_ECO.closed) * COL;

  return (
    <div style={MG_GANTT_ROOT_STYLE}>

      <_MGHeaderStrip selected={selected} setSelected={setSelected} showCP={showCP} setShowCP={setShowCP} showECO={showECO} setShowECO={setShowECO} />

      {/* ── CHART ─────────────────────────────────────────────────────── */}
      <Panel
        title={"Schedule · 16-month program window"}
        right={
          <>
            <Btn size="sm" variant={laneFilter === "all" ? "primary" : "ghost"} onClick={function () { setLaneFilter("all"); }}>All</Btn>
            {MG_LANES.map(function (l) {
              return (
                <Btn key={l.id} size="sm"
                  variant={laneFilter === l.id ? "primary" : "ghost"}
                  onClick={function () { setLaneFilter(l.id); }}>
                  {l.label}
                </Btn>
              );
            })}
          </>
        }>
        <div style={{ overflow: "auto", height: "100%" }}>
          <svg width={RAIL_W + SVG_W} height={totalH}
            style={{ display: "block", minWidth: RAIL_W + SVG_W, fontFamily: MG.FONT_UI }}>
            <rect x={RAIL_W} y={0} width={SVG_W} height={HDR_H} fill={MG.BG_2} />
            <rect x={0} y={0} width={RAIL_W} height={HDR_H} fill={MG.BG_3} />
            {MG_MONTHS.map(function (m, i) {
              const cx = RAIL_W + i * COL;
              const stripe = i % 2 === 0
                ? "transparent"
                : "color-mix(in oklch," + MG.BG_2 + " 50%, transparent)";
              return (
                <g key={m[0]}>
                  <rect x={cx} y={0} width={COL} height={totalH} fill={stripe} />
                  <text x={cx + COL / 2} y={18} textAnchor="middle"
                    fontSize={11} fontFamily={MG.FONT_MONO} fill={MG.INK_3}>
                    {m[1]}
                  </text>
                  <text x={cx + COL / 2} y={32} textAnchor="middle"
                    fontSize={10} fontFamily={MG.FONT_MONO} fill={MG.INK_3}>
                    {m[0].slice(0,4)}
                  </text>
                  <line x1={cx} y1={HDR_H} x2={cx} y2={totalH}
                    stroke={MG.LINE_SOFT} strokeWidth={0.5} />
                </g>
              );
            })}

            {[3, 6, 9, 12, 15].map(function (qi) {
              return (
                <line key={"q" + qi}
                  x1={RAIL_W + qi * COL} y1={HDR_H}
                  x2={RAIL_W + qi * COL} y2={totalH}
                  stroke={MG.LINE} strokeWidth={1} strokeDasharray="2,3" opacity={0.6} />
              );
            })}

            {showCP && (
              <g>
                <rect x={RAIL_W + cpFrom} y={HDR_H + 2}
                  width={cpTo - cpFrom} height={totalH - HDR_H - 4}
                  fill={"color-mix(in oklch," + MG.BAD + " 6%, transparent)"}
                  stroke={"color-mix(in oklch," + MG.BAD + " 35%, transparent)"}
                  strokeWidth={1} strokeDasharray="3,3" rx={4} />
                <text x={RAIL_W + cpFrom + 8} y={HDR_H + 18}
                  fontSize={10} fontFamily={MG.FONT_MONO}
                  fill={MG.BAD} letterSpacing="0.08em">
                  CRITICAL PATH · 180 d · GMN spindle 50.01
                </text>
              </g>
            )}

            {showECO && (
              <g>
                <rect x={RAIL_W + ecoFrom} y={totalH - 22}
                  width={ecoTo - ecoFrom} height={4}
                  fill={MG.WARN} opacity={0.55} rx={2} />
                <text x={RAIL_W + ecoFrom + 6} y={totalH - 8}
                  fontSize={10} fontFamily={MG.FONT_MONO}
                  fill={MG.WARN} letterSpacing="0.08em">
                  {MG_ECO.id} · raised {_mg_date(MG_ECO.raised, MG_ECO.raised)} · closed {_mg_date(MG_ECO.closed, MG_ECO.closed)}
                </text>
              </g>
            )}

            <line x1={RAIL_W + todayX} y1={0} x2={RAIL_W + todayX} y2={totalH}
              stroke={MG.STEEL} strokeWidth={1.5} strokeDasharray="4,3" />
            <text x={RAIL_W + todayX + 4} y={12}
              fontSize={10} fontFamily={MG.FONT_MONO} fill={MG.STEEL} fontWeight={600}>
              TODAY · {(window.forgeI18n && window.forgeI18n.formatDate(MG_TODAY.toISOString())) || MG_TODAY.toISOString().slice(0,10)}
            </text>

            {MG_LANES.map(function (lane) {
              const row = laneRows.map[lane.id];
              if (!row) return null;
              const ly = row.y;
              const laneTasks = row.bands;
              const laneH = LANE_PAD * 2 + Math.max(laneTasks.length, 1) * ROW_H;

              return (
                <g key={lane.id}>
                  <rect x={0} y={ly} width={RAIL_W + SVG_W} height={laneH}
                    fill={"color-mix(in oklch," + MG.BG_2 + " 25%, transparent)"} />
                  <rect x={0} y={ly} width={RAIL_W} height={laneH}
                    fill={MG.BG_3} stroke={MG.LINE_SOFT} strokeWidth={1} />
                  <line x1={0} y1={ly} x2={RAIL_W + SVG_W} y2={ly}
                    stroke={MG.LINE} strokeWidth={0.5} />
                  <text x={14} y={ly + 18} fontSize={11} fontFamily={MG.FONT_UI}
                    fontWeight={600} fill={lane.color} letterSpacing="0.04em">
                    {lane.label}
                  </text>

                  {laneTasks.map(function (b, idx) {
                    const ty = ly + LANE_PAD + idx * ROW_H;
                    const isSel = b.id === selected;
                    const bx = RAIL_W + b.x;
                    const bw = b.w;
                    const fill = "color-mix(in oklch," + mgBandColor(b) + " 22%, transparent)";
                    const stroke = mgBandColor(b);
                    const strokeW = isSel ? 2 : 1;

                    return (
                      <g key={b.id} style={{ cursor: "pointer" }}
                        onClick={function () { setSelected(b.id); }}>
                        <rect x={0} y={ty} width={RAIL_W + SVG_W} height={ROW_H}
                          fill={idx % 2 === 0 ? "transparent" : "color-mix(in oklch," + MG.BG_2 + " 25%, transparent)"} />
                        <text x={28} y={ty + ROW_H / 2 - 3}
                          fontSize={11} fontFamily={MG.FONT_UI} fill={MG.INK_2}>{b.name}</text>
                        <text x={28} y={ty + ROW_H / 2 + 11}
                          fontSize={10} fontFamily={MG.FONT_MONO} fill={MG.INK_3}>{b.code} · {b.owner}</text>
                        <circle cx={14} cy={ty + ROW_H / 2} r={4} fill={mgRiskTone(b.risk)} />
                        <rect x={bx} y={ty + 8} width={bw} height={ROW_H - 16}
                          fill={fill} stroke={stroke} strokeWidth={strokeW} rx={3} />
                        {b.progress > 0 && (
                          <rect x={bx} y={ty + 8}
                            width={Math.max(2, bw * Math.min(1, b.progress))} height={ROW_H - 16}
                            fill={"color-mix(in oklch," + stroke + " 45%, transparent)"} rx={3} />
                        )}
                        {showECO && b.ecoOverlay && (
                          <g>
                            <rect x={bx - 2} y={ty + 4} width={bw + 4} height={ROW_H - 8}
                              fill={"color-mix(in oklch," + MG.WARN + " 18%, transparent)"}
                              stroke={MG.WARN} strokeWidth={1.5} strokeDasharray="4,2" rx={4} />
                            <text x={bx + 6} y={ty + 16} fontSize={10}
                              fontFamily={MG.FONT_MONO} fill={MG.WARN} letterSpacing="0.08em">
                              {MG_ECO.id}
                            </text>
                          </g>
                        )}
                        {showCP && b.critical && (
                          <rect x={bx - 1} y={ty + 6} width={bw + 2} height={ROW_H - 12}
                            fill="none" stroke={MG.BAD} strokeWidth={1.5} rx={4} strokeDasharray="6,3" />
                        )}
                        <text x={bx + bw / 2} y={ty + ROW_H / 2 + 4} textAnchor="middle"
                          fontSize={10} fontFamily={MG.FONT_MONO} fill={MG.INK} pointerEvents="none">
                          {b.start.slice(5)} → {b.end.slice(5)}
                        </text>
                        {isSel && (
                          <rect x={bx - 3} y={ty + 5} width={bw + 6} height={ROW_H - 10}
                            fill="none" stroke={MG.STEEL} strokeWidth={1.5}
                            strokeDasharray="2,2" rx={5} opacity={0.7} />
                        )}
                      </g>
                    );
                  })}
                </g>
              );
            })}

            {MG_MILESTONES.map(function (m) {
              const mx = RAIL_W + mgDateToIdx(m.date) * COL;
              const tone = m.tone === "ok" ? MG.OK : MG.STEEL;
              return (
                <g key={m.id}>
                  <line x1={mx} y1={HDR_H} x2={mx} y2={totalH - 26}
                    stroke={tone} strokeWidth={1} strokeDasharray="2,2" />
                  <polygon
                    points={(mx - 7) + "," + (HDR_H + 4) + " " + (mx + 7) + "," + (HDR_H + 4) + " " + mx + "," + (HDR_H + 14)}
                    fill={tone} />
                  <text x={mx} y={HDR_H + 26} textAnchor="middle"
                    fontSize={10} fontFamily={MG.FONT_MONO}
                    fill={tone} letterSpacing="0.04em">
                    {m.id}
                  </text>
                  <text x={mx} y={HDR_H + 38} textAnchor="middle"
                    fontSize={10} fontFamily={MG.FONT_MONO} fill={MG.INK_3}>
                    {m.date}
                  </text>
                </g>
              );
            })}

            <g transform={"translate(" + (RAIL_W + 12) + "," + (totalH - 60) + ")"}>
              {[
                { c: MG.STEEL, label: "Planned" },
                { c: MG.OK,    label: "Complete" },
                { c: MG.WARN,  label: "ECO overlay" },
                { c: MG.BAD,   label: "Critical path · 180 d" },
              ].map(function (it, i) {
                return (
                  <g key={it.label} transform={"translate(" + (i * 170) + ",0)"}>
                    <rect x={0} y={0} width={14} height={10} rx={2}
                      fill={"color-mix(in oklch," + it.c + " 22%, transparent)"}
                      stroke={it.c} strokeWidth={1} />
                    <text x={20} y={10} fontSize={10} fontFamily={MG.FONT_MONO}
                      fill={MG.INK_3}>{it.label}</text>
                  </g>
                );
              })}
            </g>
          </svg>
        </div>
      </Panel>

      <div style={{ display: "flex", flexDirection: "column", gap: 14, minHeight: 0 }}>
        <_MGDetailPanel selectedBand={selectedBand} selected={selected} setSelected={setSelected} />
      </div>
    </div>
  );
}

// ─────────────────────────────────────────────── route registration (defensive)
// Agent #3 (registry-router) builds registerMittelstandRoute. Until then the
// route falls back into PUMP_ROUTES so the demo keeps working — router.jsx
// merges PUMP_ROUTES today regardless of active tenant.
(function registerMittelstandGanttRoute() {
  const route = {
    path: "/plan/gantt",
    mode: "plan",
    title: "Mittelstand · Plan Gantt",
    renderer: function () { return React.createElement(ScreenMittelstandGantt); },
    tenant: "mittelstand",
  };
  if (typeof registerMittelstandRoute === "function") {
    registerMittelstandRoute(route);
  } else if (typeof registerPumpRoute === "function") {
    // soft fallback so the screen is reachable while agent #3 is in flight
    registerPumpRoute(route);
  }
  if (typeof window !== "undefined") {
    window.ScreenMittelstandGantt = ScreenMittelstandGantt;
    window.MITTEL_GANTT_BANDS     = MG_BANDS;
    window.MITTEL_GANTT_MILESTONES = MG_MILESTONES;
    window.MITTEL_GANTT_ECO       = MG_ECO;
  }
})();
})();
