// InvestorPage (Stage 11) — window.InvestorPage
// Investor & Lender view: institutional metrics derived entirely from live data.
// LTM income from data.plHistory + data.txns; balance sheet from cumulative GL
// balances (same section mapping the Balance Sheet page uses); covenants stored
// in kpi_targets (period_type='covenant'), editable by super admins. Anything
// that can't be derived shows "—" with an honest "connect data" assessment.

(function () {
  const h = React.createElement;
  const { useState, useEffect } = React;

  function fmtShort(n) {
    if (n === null || n === undefined || isNaN(n)) return "—";
    const a = Math.abs(n), s = n < 0 ? "-" : "";
    if (a >= 1e6) return s + "$" + (a / 1e6).toFixed(1) + "M";
    if (a >= 1e3) return s + "$" + (a / 1e3).toFixed(0) + "K";
    return s + "$" + a.toFixed(0);
  }

  // Trailing-12-month rollup from the GL (abs-by-section; signs applied here).
  // Optional `range` {start,end} re-anchors the window (period selector); without
  // it, defaults to the trailing 12 months from the latest posting.
  function ltmRollup(txns, profile, range) {
    const tax = window.PerduraTaxonomy;
    let maxD = 0;
    for (const t of txns || []) { if (t.posted_date) { const d = +new Date(t.posted_date); if (d > maxD) maxD = d; } }
    if (!maxD) maxD = Date.now();
    const cut = range ? +range.start : maxD - 365 * 86400000;
    const hi = range ? +range.end : maxD;
    const sec = {};
    for (const t of txns || []) {
      const cat = t.canonical_category; if (!cat) continue;
      const d = t.posted_date ? +new Date(t.posted_date) : 0; if (!d || d <= cut || d > hi) continue;
      let s = null; try { s = tax && tax.sectionForCategory ? tax.sectionForCategory(cat, profile) : null; } catch (e) { s = null; }
      if (!s) continue;
      sec[s] = (sec[s] || 0) + Math.abs(Number(t.amount) || 0);
    }
    const g = (k) => sec[k] || 0;
    const revenue = g("revenue") - g("contra_revenue") + g("other_income");
    const cogs = g("cogs"), opex = g("opex"), da = g("da"), otherOp = g("other_op_exp");
    const interest = g("interest"), taxx = g("tax"), otherExp = g("other_expense");
    const oi = (revenue - cogs) - opex - da - otherOp;
    return { revenue, cogs, gp: revenue - cogs, opex, da, interest, tax: taxx, otherExp, oi, ebitda: oi + da, ni: oi - interest - taxx - otherExp };
  }

  // Balance-sheet snapshot: cumulative signed GL balance per category, mapped to
  // sections. Assets are debit-normal (signed), liab/equity credit-normal (−signed).
  function bsSnapshot(txns, profile, asOfMs) {
    const tax = window.PerduraTaxonomy;
    const sorted = (txns || []).filter((t) => t.posted_date && (!asOfMs || +new Date(t.posted_date) <= asOfMs)).slice();
    const signed = {};
    for (const t of sorted) { const cat = t.canonical_category; if (!cat) continue; signed[cat] = (signed[cat] || 0) + (Number(t.amount) || 0); }
    const assetSecs = { current_assets: 1, non_current_assets: 1 };
    const liabSecs = { current_liab: 1, long_term_liab: 1 };
    const debtRe = /debt|loan|note payable|line of credit|credit card|mortgage|borrow|bond/i;
    let assets = 0, liab = 0, equity = 0, cash = 0, debt = 0, currentDebt = 0, ltDebt = 0;
    for (const cat in signed) {
      let s = null; try { s = tax.sectionForCategory(cat, profile); } catch (e) { s = null; }
      const v = signed[cat];
      if (assetSecs[s]) { assets += v; if (/cash|bank/i.test(cat)) cash += v; }
      else if (liabSecs[s]) { const dv = -v; liab += dv; if (debtRe.test(cat)) { debt += dv; if (s === "current_liab") currentDebt += dv; else ltDebt += dv; } }
      else if (s === "equity") { equity += -v; }
    }
    return { assets, liab, equity, cash, debt, currentDebt, ltDebt };
  }

  // Detailed balance-sheet snapshot: cumulative signed GL balance per category as
  // of `asOfMs`, bucketed into the specific lines a mini balance sheet needs.
  // Assets are debit-normal (signed), liab/equity credit-normal (−signed). Lines
  // that have no sourcing in the GL come back as null so the UI can show "—".
  function bsDetail(txns, profile, asOfMs) {
    const tax = window.PerduraTaxonomy;
    const signed = {};
    for (const t of txns || []) {
      if (!t.posted_date) continue;
      if (asOfMs && +new Date(t.posted_date) > asOfMs) continue;
      const cat = t.canonical_category; if (!cat) continue;
      signed[cat] = (signed[cat] || 0) + (Number(t.amount) || 0);
    }
    const assetSecs = { current_assets: 1, non_current_assets: 1 };
    const liabSecs = { current_liab: 1, long_term_liab: 1 };
    const cashRe = /cash|bank|equivalent|money market/i;
    const arRe = /receivable|\bar\b|trade debtor/i;
    const invRe = /inventory|stock on hand|raw material|finished good|work in process|wip/i;
    const apRe = /payable|\bap\b|trade creditor/i;
    const debtRe = /debt|loan|note payable|line of credit|credit card|mortgage|borrow|bond/i;
    // hasX flags track whether ANY category mapped into a bucket, so we can
    // distinguish a genuine zero balance from "no such accounts in the GL".
    const r = {
      cash: 0, ar: 0, inv: 0, otherCA: 0, currentAssets: 0,
      fixedNet: 0, assets: 0,
      ap: 0, currentDebt: 0, ltDebt: 0, liab: 0, equity: 0,
      hasCash: false, hasAR: false, hasInv: false, hasOtherCA: false,
      hasFixed: false, hasAP: false, hasCurrentDebt: false, hasBS: false,
    };
    for (const cat in signed) {
      let s = null; try { s = tax.sectionForCategory(cat, profile); } catch (e) { s = null; }
      const v = signed[cat];
      if (assetSecs[s]) {
        r.assets += v; r.hasBS = true;
        if (s === "current_assets") {
          r.currentAssets += v;
          if (cashRe.test(cat)) { r.cash += v; r.hasCash = true; }
          else if (arRe.test(cat)) { r.ar += v; r.hasAR = true; }
          else if (invRe.test(cat)) { r.inv += v; r.hasInv = true; }
          else { r.otherCA += v; r.hasOtherCA = true; }
        } else {
          // non_current_assets → fixed assets (net), incl. contra accumulated dep.
          r.fixedNet += v; r.hasFixed = true;
        }
      } else if (liabSecs[s]) {
        const dv = -v; r.liab += dv; r.hasBS = true;
        if (apRe.test(cat)) { r.ap += dv; r.hasAP = true; }
        if (debtRe.test(cat)) { if (s === "current_liab") { r.currentDebt += dv; r.hasCurrentDebt = true; } else r.ltDebt += dv; }
      } else if (s === "equity") {
        r.equity += -v; r.hasBS = true;
      }
    }
    return r;
  }

  // EBITDA bridge waterfall (responsive SVG).
  function BridgeWaterfall(K, steps) {
    if (!steps.length) return null;
    const W = 960, H = 180, padT = 18, padB = 44, padX = 14, plotH = H - padT - padB;
    let cum = 0; const pts = [];
    steps.forEach((st) => {
      const start = st.type === "delta" ? cum : 0;
      const end = st.type === "delta" ? cum + st.value : st.value;
      pts.push({ label: st.label, start, end, value: st.value, type: st.type, color: st.color });
      cum = end;
    });
    const allV = pts.flatMap((p) => [p.start, p.end]).concat([0]);
    const maxV = Math.max(...allV), minV = Math.min(...allV), range = (maxV - minV) || 1;
    const y = (v) => padT + ((maxV - v) / range) * plotH;
    const n = pts.length, colW = (W - padX * 2) / n, bw = Math.min(108, colW * 0.6);
    return h("svg", { viewBox: `0 0 ${W} ${H}`, width: "100%", style: { display: "block", width: "100%", height: "auto", maxHeight: H + "px" }, preserveAspectRatio: "xMidYMid meet" },
      h("line", { x1: padX, x2: W - padX, y1: y(0), y2: y(0), stroke: K.LINE }),
      pts.map((p, i) => {
        const cx = padX + colW * i + colW / 2;
        const top = y(Math.max(p.start, p.end)), bot = y(Math.min(p.start, p.end)), hh = Math.max(2, bot - top);
        const neg = p.value < 0;
        return h("g", { key: i },
          (i > 0) ? h("line", { x1: padX + colW * (i - 1) + colW / 2 + bw / 2, x2: cx - bw / 2, y1: y(pts[i - 1].end), y2: y(pts[i - 1].end), stroke: "#CBD5E1", strokeDasharray: "3 3" }) : null,
          h("rect", { x: cx - bw / 2, y: top, width: bw, height: hh, rx: 3, fill: p.color, opacity: p.type === "delta" ? 0.9 : 1 }),
          h("text", { x: cx, y: top - 7, textAnchor: "middle", fontSize: "11", fontWeight: "800", fill: neg ? "#DC2626" : "#0F1520", fontFamily: "Inter, system-ui, sans-serif" }, (p.type === "delta" ? (neg ? "−" : "+") : "") + fmtShort(Math.abs(p.value))),
          h("text", { x: cx, y: H - padB + 20, textAnchor: "middle", fontSize: "10.5", fontWeight: "700", fill: "#475569" }, p.label),
          (p.type !== "delta") ? h("text", { x: cx, y: H - padB + 36, textAnchor: "middle", fontSize: "9", fontWeight: "600", fill: K.MUTE }, "total") : null);
      }));
  }

  // Horizontal debt-maturity bars.
  function DebtBars(K, rows) {
    const max = Math.max(1, ...rows.map((r) => r.total));
    return h("div", { style: { display: "flex", flexDirection: "column", gap: 10 } },
      rows.map((r, i) => h("div", { key: i },
        h("div", { style: { display: "flex", justifyContent: "space-between", fontSize: 12, marginBottom: 3 } },
          h("span", { style: { color: "#334155", fontWeight: 600 } }, r.label),
          h("span", { style: { fontWeight: 700, color: K.INK, fontVariantNumeric: "tabular-nums" } }, fmtShort(r.total))),
        h("div", { style: { height: 16, background: "#EEF1F6", borderRadius: 5, overflow: "hidden" } },
          h("div", { style: { width: Math.max(2, r.total / max * 100) + "%", height: "100%", background: r.color, borderRadius: 5, opacity: 0.9 } })))));
  }

  // ── MiniStatement — titled 3/4-column line table used for the three mini
  // financial statements. Row styling mirrors the P&L conventions:
  //   kind "metric" → bold label, navy/red value
  //   kind "ratio"  → colored value (green good / red bad) driven by row.good
  //   kind "total"  → gold-tinted background, heavier weight
  //   kind "contra" → red, shown in parentheses
  // Each row: { label, cols:[...], kind, good, deltaTone }.
  function MiniStatement(K, opts) {
    const headers = opts.headers || [];
    const rows = opts.rows || [];
    const cellPad = "6px 10px";
    const numStyle = { fontVariantNumeric: "tabular-nums", textAlign: "right", whiteSpace: "nowrap" };
    const valColor = (row, ci) => {
      // First data column tone by kind; delta column tone by deltaTone[ci].
      if (row.deltaTone && row.deltaTone[ci] === "up") return "#18a867";
      if (row.deltaTone && row.deltaTone[ci] === "down") return "#d94f47";
      if (row.kind === "contra") return "#d94f47";
      if (row.kind === "ratio") return row.good === true ? "#18a867" : row.good === false ? "#d94f47" : "#0d2040";
      return "#0d2040";
    };
    return h("table", { className: "pa-table", style: { width: "100%", borderCollapse: "collapse" } },
      h("thead", null, h("tr", null,
        h("th", { style: { textAlign: "left", padding: cellPad, fontSize: 10.5 } }, headers[0] || ""),
        headers.slice(1).map((hd, i) => h("th", { key: i, className: "num", style: { textAlign: "right", padding: cellPad, fontSize: 10.5 } }, hd)))),
      h("tbody", null, rows.map((row, ri) => {
        const isTotal = row.kind === "total";
        const trStyle = isTotal ? { background: "rgba(184,146,30,.10)" } : {};
        const labelWeight = (row.kind === "metric" || isTotal) ? 700 : (row.kind === "ratio" ? 600 : 500);
        const labelColor = isTotal ? "#0d2040" : (row.kind === "ratio" ? "#475569" : "#0d2040");
        // Real GL accounts (row.drill) open the transaction panel; computed
        // ratios navigate to the income statement. Everything else is static.
        const onRowClick = row.drill
          ? () => window.openAccountDetail && window.openAccountDetail(row.drill)
          : row.kind === "ratio"
            ? () => window.__perduraSetPage && window.__perduraSetPage("income_statement")
            : undefined;
        return h("tr", { key: ri, onClick: onRowClick, title: onRowClick ? (row.drill ? "View account detail" : "View income statement") : undefined, style: Object.assign({}, trStyle, onRowClick ? { cursor: "pointer" } : null) },
          h("td", { style: { padding: cellPad, fontWeight: labelWeight, color: labelColor, fontSize: row.kind === "ratio" ? 11.5 : 12.5 } }, row.label),
          row.cols.map((c, ci) => h("td", { key: ci, className: "num", style: Object.assign({ padding: cellPad, fontSize: 12, fontWeight: isTotal ? 700 : 500, color: valColor(row, ci) }, numStyle) }, c)));
      })));
  }

  function Page(props) {
    const K = window.PerduraPageKit;
    if (!K) return h("div", { className: "pc-page" }, "Loading…");
    const { data, companyProfile, scopedCompanyId } = props;
    const plH = (data && (data.plHistory || data.pl)) || {};
    const T = K.ttm(plH);
    const txns = (data && data.txns) || [];
    // G1 — period selector re-anchors the trailing window / as-of date.
    const anchor = K.anchorFromPlH(plH);
    const ps = K.usePeriodState("investor", "ltm");
    const range = K.resolvePeriod(ps.mode, anchor, ps.custom);
    const isLtm = ps.mode === "ltm";
    const pLabel = isLtm ? "LTM" : range.label;
    const lt = ltmRollup(txns, companyProfile, isLtm ? null : range);
    const bs = bsSnapshot(txns, companyProfile, isLtm ? null : +range.end);
    const cashEnd = (data && data.cash && Number.isFinite(data.cash.endCash)) ? data.cash.endCash : bs.cash;

    // Headline LTM figures — revenue/EBITDA from the canonical plHistory TTM when
    // available, below-EBITDA items (interest, net income) from the GL rollup.
    const revenue = !isLtm ? lt.revenue : ((T && T.cur.revenue) || lt.revenue);
    const ebitda = !isLtm ? lt.ebitda : ((T && Number.isFinite(T.cur.ebitda)) ? T.cur.ebitda : lt.ebitda);
    const gp = !isLtm ? lt.gp : ((T && Number.isFinite(T.cur.gp)) ? T.cur.gp : lt.gp);
    const ni = lt.ni;
    const interest = lt.interest;
    const ebitdaMargin = revenue ? ebitda / revenue * 100 : null;
    const netDebt = bs.debt - cashEnd;
    const debtEbitda = ebitda > 0 ? bs.debt / ebitda : null;
    const intCov = interest > 0 ? ebitda / interest : null;

    const hasBS = Math.abs(bs.assets) > 1 || Math.abs(bs.liab) > 1;

    // ── Financial Statements Summary — prior-period anchors ──────────────────
    // Latest month-end (LTM ⇒ latest posting; range ⇒ window end) and the same
    // point one year earlier, for the Prior-Year column.
    let latestMs = 0;
    for (const t of txns) { if (t.posted_date) { const d = +new Date(t.posted_date); if (d > latestMs) latestMs = d; } }
    if (!latestMs) latestMs = Date.now();
    const endMs = isLtm ? latestMs : +range.end;
    const priorEndMs = endMs - 365 * 86400000;
    // Prior-LTM P&L: re-anchor ltmRollup to the 12 months ending one year ago.
    const ltPrior = ltmRollup(txns, companyProfile, { start: new Date(endMs - 730 * 86400000), end: new Date(priorEndMs) });
    // Balance-sheet detail at both points (cumulative GL).
    const bsCur = bsDetail(txns, companyProfile, endMs);
    const bsPri = bsDetail(txns, companyProfile, priorEndMs);

    // ── Covenants (kpi_targets, period_type='covenant'; super-admin editable) ──
    const [canEdit, setCanEdit] = useState(false);
    const [covOv, setCovOv] = useState({});     // key -> target_value
    const [editing, setEditing] = useState(false);
    const [draft, setDraft] = useState({});
    const [saving, setSaving] = useState(false);
    useEffect(() => {
      const db = window.supabaseClient; if (!db) return; let alive = true;
      (async () => {
        try { const { data: { session } } = await db.auth.getSession(); if (alive) setCanEdit(!!(session && session.user && session.user.app_metadata && session.user.app_metadata.super_admin)); } catch (e) {}
        if (!scopedCompanyId) return;
        try { const { data: rows } = await db.from("kpi_targets").select("kpi_key, target_value, period_type").eq("company_id", scopedCompanyId).eq("period_type", "covenant"); if (!alive || !rows) return; const m = {}; rows.forEach((r) => { m[r.kpi_key] = Number(r.target_value); }); setCovOv(m); } catch (e) {}
      })();
      return () => { alive = false; };
    }, [scopedCompanyId]);

    const dscrDenom = interest + bs.currentDebt;
    const COV = [
      { key: "debt_ebitda", name: "Debt / EBITDA", actual: debtEbitda, def: 3.5, dir: "low", fmt: (v) => v == null ? "—" : v.toFixed(1) + "x" },
      { key: "dscr", name: "DSCR", actual: dscrDenom > 0 ? ebitda / dscrDenom : null, def: 1.25, dir: "high", fmt: (v) => v == null ? "—" : v.toFixed(2) + "x" },
      { key: "interest_cov", name: "Interest Coverage", actual: intCov, def: 1.5, dir: "high", fmt: (v) => v == null ? "—" : v.toFixed(1) + "x" },
      { key: "leverage", name: "Leverage Ratio", actual: bs.assets > 0 ? bs.liab / bs.assets * 100 : null, def: 60, dir: "low", fmt: (v) => v == null ? "—" : v.toFixed(0) + "%" },
      { key: "min_ebitda", name: "Min EBITDA", actual: ebitda, def: 1500000, dir: "high", fmt: (v) => fmtShort(v) },
      { key: "min_cash", name: "Min Cash", actual: cashEnd, def: 500000, dir: "high", fmt: (v) => fmtShort(v) },
    ];
    const covOf = (c) => (covOv[c.key] != null ? covOv[c.key] : c.def);
    const covEval = (c) => {
      const a = c.actual, cov = covOf(c);
      if (a == null || !Number.isFinite(a)) return { status: "na", dot: "⚪", head: "—" };
      const meets = c.dir === "low" ? a <= cov : a >= cov;
      const near = c.dir === "low" ? a <= cov * 1.15 : a >= cov * 0.85;
      const status = meets ? (near && !((c.dir === "low" ? a <= cov * 0.85 : a >= cov * 1.15)) ? "amber" : "green") : "red";
      const st = meets ? "green" : near ? "amber" : "red";
      const headVal = c.dir === "low" ? cov - a : a - cov;
      const head = c.fmt === COV[3].fmt ? Math.abs(headVal).toFixed(0) + "pp" : (c.key === "min_ebitda" || c.key === "min_cash") ? fmtShort(Math.abs(headVal)) : Math.abs(headVal).toFixed(c.key === "dscr" ? 2 : 1) + (c.key === "leverage" ? "pp" : "x");
      return { status: st, dot: st === "green" ? "🟢" : st === "amber" ? "🟡" : "🔴", head: (meets ? "Headroom " : "Breach ") + head };
    };
    async function saveCov() {
      const db = window.supabaseClient; if (!db || !scopedCompanyId) { setEditing(false); return; }
      setSaving(true);
      try {
        const { data: { session } } = await db.auth.getSession();
        const rows = Object.keys(draft).filter((k) => draft[k] !== "" && draft[k] != null).map((k) => ({ company_id: scopedCompanyId, kpi_key: k, target_value: Number(draft[k]), period_type: "covenant", effective_from: new Date().toISOString().slice(0, 10), created_by: session && session.user ? session.user.id : null }));
        if (rows.length) { await db.from("kpi_targets").upsert(rows, { onConflict: "company_id,kpi_key,period_type,effective_from" }); const m = Object.assign({}, covOv); rows.forEach((r) => { m[r.kpi_key] = r.target_value; }); setCovOv(m); }
      } catch (e) { alert("Save failed: " + (e.message || e)); }
      setSaving(false); setEditing(false); setDraft({});
    }

    // ── Section 1 — headline strip (Pattern A)
    const kpis = [
      { label: pLabel + " Revenue", value: fmtShort(revenue), valueColor: "gold", sub: isLtm ? "trailing twelve months" : range.label.toLowerCase() },
      { label: pLabel + " EBITDA", value: fmtShort(ebitda), sub: ebitdaMargin == null ? null : ebitdaMargin.toFixed(1) + "% margin", valueColor: ebitda < 0 ? "red" : "green" },
      { label: "EBITDA Margin", value: ebitdaMargin == null ? "—" : ebitdaMargin.toFixed(1) + "%", valueColor: "teal", sub: "EBITDA ÷ revenue" },
      { label: "Net Debt", value: hasBS ? fmtShort(netDebt) : "—", sub: hasBS ? "debt − cash" : "connect balance sheet", valueColor: (hasBS && netDebt > 0) ? "red" : "navy" },
      { label: "Debt / EBITDA", value: debtEbitda == null ? "—" : debtEbitda.toFixed(1) + "x", sub: debtEbitda == null ? null : debtEbitda < 2 ? "conservative" : debtEbitda <= 4 ? "moderate" : "elevated", valueColor: debtEbitda == null ? "navy" : debtEbitda < 2 ? "green" : debtEbitda <= 4 ? "amber" : "red" },
      { label: "Interest Coverage", value: intCov == null ? "—" : intCov.toFixed(1) + "x", sub: intCov == null ? "no interest expense" : "EBITDA ÷ interest", valueColor: intCov == null ? "navy" : intCov > 2 ? "green" : intCov < 1.5 ? "red" : "amber" },
    ];

    // ── Section 2 — EBITDA bridge
    let bridge = null;
    if (T && T.prior && T.prior.revenue) {
      const p = T.prior, c = T.cur;
      const priorGM = p.revenue ? p.gp / p.revenue : 0;
      const volume = (c.revenue - p.revenue) * priorGM;
      const rate = c.gp - c.revenue * priorGM;
      const opexChg = -((c.opex || 0) - (p.opex || 0));
      const other = (c.ebitda - p.ebitda) - (volume + rate + opexChg);
      const steps = [
        { label: "Prior EBITDA", type: "total", value: p.ebitda, color: "#94A3B8" },
        { label: "Revenue Growth", type: "delta", value: volume, color: volume >= 0 ? "#059669" : "#DC2626" },
        { label: "Gross Margin", type: "delta", value: rate, color: rate >= 0 ? "#059669" : "#DC2626" },
        { label: "OpEx Change", type: "delta", value: opexChg, color: opexChg >= 0 ? "#059669" : "#DC2626" },
      ];
      if (Math.abs(other) > Math.abs(c.ebitda) * 0.01) steps.push({ label: "Other", type: "delta", value: other, color: other >= 0 ? "#059669" : "#DC2626" });
      steps.push({ label: "Current EBITDA", type: "total", value: c.ebitda, color: "#1C4ED8" });
      bridge = steps;
    }
    // Map to Pattern-F BridgeChart items (start/positive/negative/end).
    const bridgeItems = bridge ? bridge.map((s, i) => ({ label: s.label, value: s.value, type: s.type === "total" ? (i === 0 ? "start" : "end") : (s.value >= 0 ? "positive" : "negative") })) : null;

    // ── Sections 2–3 — FINANCIAL STATEMENTS SUMMARY (three mini statements) ──
    const m = (v) => fmtShort(v);
    const paren = (v) => v == null ? "—" : "(" + fmtShort(Math.abs(v)) + ")";
    const pct = (v) => v == null || !Number.isFinite(v) ? "—" : v.toFixed(1) + "%";
    const dPct = (cur, pri) => (pri && Number.isFinite(pri) && pri !== 0) ? (cur - pri) / Math.abs(pri) * 100 : null;
    const fmtDpct = (v) => v == null ? "—" : (v >= 0 ? "+" : "") + v.toFixed(1) + "%";
    const fmtDamt = (cur, pri) => (cur == null || pri == null) ? "—" : (cur - pri >= 0 ? "+" : "−") + fmtShort(Math.abs(cur - pri));

    // LEFT — Mini P&L (LTM vs prior LTM). For LTM mode prefer canonical TTM.
    const plCur = {
      rev: revenue, cogs: lt.cogs, gp: gp, opex: lt.opex, ebitda: ebitda, ni: ni,
    };
    const plPri = {
      rev: (isLtm && T && T.prior) ? T.prior.revenue : ltPrior.revenue,
      cogs: ltPrior.cogs,
      gp: (isLtm && T && T.prior) ? T.prior.gp : ltPrior.gp,
      opex: (isLtm && T && T.prior) ? T.prior.opex : ltPrior.opex,
      ebitda: (isLtm && T && T.prior) ? T.prior.ebitda : ltPrior.ebitda,
      ni: ltPrior.ni,
    };
    const hasPlPrior = Math.abs(plPri.rev) > 1;
    const gmCur = plCur.rev ? plCur.gp / plCur.rev * 100 : null;
    const gmPri = plPri.rev ? plPri.gp / plPri.rev * 100 : null;
    const emCur = plCur.rev ? plCur.ebitda / plCur.rev * 100 : null;
    const emPri = plPri.rev ? plPri.ebitda / plPri.rev * 100 : null;
    const nmCur = plCur.rev ? plCur.ni / plCur.rev * 100 : null;
    const nmPri = plPri.rev ? plPri.ni / plPri.rev * 100 : null;
    const dp = (c, p) => hasPlPrior ? dPct(c, p) : null;
    // delta-tone: revenue growth up=green; cost increases down=red.
    const growthTone = (c, p) => { const d = dp(c, p); return d == null ? null : (d >= 0 ? "up" : "down"); };
    const costTone = (c, p) => { const d = dp(c, p); return d == null ? null : (d > 0 ? "down" : "up"); };
    const plRows = [
      { label: "Revenue", kind: "metric", cols: [m(plCur.rev), hasPlPrior ? m(plPri.rev) : "—", fmtDpct(dp(plCur.rev, plPri.rev))], deltaTone: [null, null, growthTone(plCur.rev, plPri.rev)] },
      { label: "Cost of Goods Sold", kind: "contra", cols: [paren(plCur.cogs), hasPlPrior ? paren(plPri.cogs) : "—", fmtDpct(dp(plCur.cogs, plPri.cogs))], deltaTone: [null, null, costTone(plCur.cogs, plPri.cogs)] },
      { label: "GROSS PROFIT", kind: "total", cols: [m(plCur.gp), hasPlPrior ? m(plPri.gp) : "—", fmtDpct(dp(plCur.gp, plPri.gp))], deltaTone: [null, null, growthTone(plCur.gp, plPri.gp)] },
      { label: "Gross Margin %", kind: "ratio", good: (gmCur != null && gmPri != null) ? gmCur >= gmPri : null, cols: [pct(gmCur), gmPri == null ? "—" : pct(gmPri), gmCur != null && gmPri != null ? (gmCur - gmPri >= 0 ? "+" : "") + (gmCur - gmPri).toFixed(1) + "pp" : "—"], deltaTone: [null, null, (gmCur != null && gmPri != null) ? (gmCur >= gmPri ? "up" : "down") : null] },
      { label: "Operating Expenses", kind: "contra", cols: [paren(plCur.opex), hasPlPrior ? paren(plPri.opex) : "—", fmtDpct(dp(plCur.opex, plPri.opex))], deltaTone: [null, null, costTone(plCur.opex, plPri.opex)] },
      { label: "EBITDA", kind: "total", cols: [m(plCur.ebitda), hasPlPrior ? m(plPri.ebitda) : "—", fmtDpct(dp(plCur.ebitda, plPri.ebitda))], deltaTone: [null, null, growthTone(plCur.ebitda, plPri.ebitda)] },
      { label: "EBITDA Margin %", kind: "ratio", good: (emCur != null && emPri != null) ? emCur >= emPri : null, cols: [pct(emCur), emPri == null ? "—" : pct(emPri), emCur != null && emPri != null ? (emCur - emPri >= 0 ? "+" : "") + (emCur - emPri).toFixed(1) + "pp" : "—"], deltaTone: [null, null, (emCur != null && emPri != null) ? (emCur >= emPri ? "up" : "down") : null] },
      { label: "Net Income", kind: "total", cols: [m(plCur.ni), hasPlPrior ? m(plPri.ni) : "—", fmtDpct(dp(plCur.ni, plPri.ni))], deltaTone: [null, null, growthTone(plCur.ni, plPri.ni)] },
      { label: "Net Margin %", kind: "ratio", good: (nmCur != null && nmPri != null) ? nmCur >= nmPri : null, cols: [pct(nmCur), nmPri == null ? "—" : pct(nmPri), nmCur != null && nmPri != null ? (nmCur - nmPri >= 0 ? "+" : "") + (nmCur - nmPri).toFixed(1) + "pp" : "—"], deltaTone: [null, null, (nmCur != null && nmPri != null) ? (nmCur >= nmPri ? "up" : "down") : null] },
    ];

    // MIDDLE — Mini Balance Sheet (latest vs one year prior). Use bsDetail flags
    // to show "—" for lines the GL genuinely can't source.
    const cashCur = (data && data.cash && Number.isFinite(data.cash.endCash)) ? data.cash.endCash : (bsCur.hasCash ? bsCur.cash : null);
    const bsLine = (label, kind, curV, priV, hasCur, hasPri, drillCat) => ({
      label, kind,
      drill: drillCat ? { name: label, category: drillCat, page: "investor" } : null,
      cols: [hasCur === false ? "—" : m(curV), hasPri === false ? "—" : m(priV),
        (hasCur === false || hasPri === false) ? "—" : fmtDamt(curV, priV)],
      deltaTone: [null, null, (hasCur === false || hasPri === false) ? null : (curV - priV >= 0 ? "up" : "down")],
    });
    const totCA_cur = bsCur.currentAssets, totCA_pri = bsPri.currentAssets;
    const eqLabel = (companyProfile && companyProfile.is_nonprofit) ? "TOTAL NET ASSETS" : "TOTAL EQUITY";
    const bsMiniRows = bsCur.hasBS ? [
      bsLine("Cash & Equivalents", "metric", cashCur, bsPri.hasCash ? bsPri.cash : null, cashCur != null, bsPri.hasCash, "Cash"),
      bsLine("Accounts Receivable", "metric", bsCur.ar, bsPri.ar, bsCur.hasAR, bsPri.hasAR, "Accounts Receivable"),
      bsLine("Inventory", "metric", bsCur.inv, bsPri.inv, bsCur.hasInv, bsPri.hasInv, "Inventory"),
      bsLine("Other Current Assets", "metric", bsCur.otherCA, bsPri.otherCA, bsCur.hasOtherCA, bsPri.hasOtherCA),
      Object.assign(bsLine("TOTAL CURRENT ASSETS", "total", totCA_cur, totCA_pri, true, true), {}),
      bsLine("Fixed Assets (Net)", "metric", bsCur.fixedNet, bsPri.fixedNet, bsCur.hasFixed, bsPri.hasFixed),
      bsLine("TOTAL ASSETS", "total", bsCur.assets, bsPri.assets, true, true),
      bsLine("Accounts Payable", "contra", bsCur.ap, bsPri.ap, bsCur.hasAP, bsPri.hasAP, "Accounts Payable"),
      bsLine("Current Debt", "contra", bsCur.currentDebt, bsPri.currentDebt, bsCur.hasCurrentDebt, bsPri.hasCurrentDebt),
      bsLine("TOTAL LIABILITIES", "total", bsCur.liab, bsPri.liab, true, true),
      bsLine(eqLabel, "total", bsCur.equity, bsPri.equity, true, true),
    ] : null;

    // RIGHT — Mini Cash Flow (LTM vs prior LTM). No mappings/accountMaster are on
    // `data`, so the full indirect-method engine can't run here. We derive:
    //   OCF ≈ NI + D&A (honest indirect-method shortcut, no WC movements)
    //   ICF ≈ −Δ Fixed Assets (Net) year-over-year (capex proxy)
    //   FCF ≈ −Δ Total Debt year-over-year (net borrowing/repayment proxy)
    // Beginning/Ending cash come from the GL cash balance one year apart; the
    // Net-Change line is the cash-balance delta (ties to the BS), and Financing
    // is shown as the residual so the statement reconciles.
    const ocfCur = (plCur.ni != null && Number.isFinite(lt.da)) ? plCur.ni + lt.da : null;
    const ocfPri = (hasPlPrior && Number.isFinite(ltPrior.da)) ? plPri.ni + ltPrior.da : null;
    const cfBeg = bsPri.hasCash ? bsPri.cash : null;
    const cfEnd = cashCur;
    const netChgCur = (cfBeg != null && cfEnd != null) ? cfEnd - cfBeg : null;
    // Investing proxy: cash used to grow net fixed assets (capex less D&A recovery).
    const icfCur = (bsCur.hasFixed && bsPri.hasFixed) ? -((bsCur.fixedNet - bsPri.fixedNet) + lt.da) : null;
    // Financing as residual once OCF + ICF are known and net change is anchored.
    const fcfFin = (netChgCur != null && ocfCur != null && icfCur != null) ? netChgCur - ocfCur - icfCur : null;
    const freeCash = (ocfCur != null && icfCur != null) ? ocfCur + icfCur : (ocfCur != null ? ocfCur : null);
    const cashConvFcf = (freeCash != null && plCur.ni && plCur.ni !== 0) ? freeCash / plCur.ni : null;
    // Prior-period analogues (where derivable) for the Δ% column.
    const cfRow = (label, kind, curV, priV) => ({
      label, kind,
      cols: [curV == null ? "—" : m(curV), priV == null ? "—" : m(priV),
        (curV == null || priV == null) ? "—" : fmtDpct(dPct(curV, priV))],
      deltaTone: [null, null, (curV == null || priV == null) ? null : (curV - priV >= 0 ? "up" : "down")],
    });
    const cfMiniRows = [
      cfRow("Operating Cash Flow", "metric", ocfCur, ocfPri),
      cfRow("Investing Cash Flow", "contra", icfCur, null),
      cfRow("Financing Cash Flow", "metric", fcfFin, null),
      cfRow("NET CHANGE IN CASH", "total", netChgCur, null),
      cfRow("Beginning Cash", "metric", cfBeg, null),
      cfRow("Ending Cash", "total", cfEnd, null),
      cfRow("Free Cash Flow", "metric", freeCash, null),
      { label: "Cash Conversion (FCF/NI)", kind: "ratio", good: cashConvFcf == null ? null : cashConvFcf >= 1,
        cols: [cashConvFcf == null ? "—" : cashConvFcf.toFixed(2) + "x", "—", "—"], deltaTone: [null, null, null] },
    ];

    // ── Section 5 — debt maturity (current portion vs long-term; honest split)
    const debtRows = bs.debt > 1 ? [
      { label: "Current portion (this FY)", total: bs.currentDebt, color: "#D97706" },
      { label: "Long-term (future years)", total: bs.ltDebt, color: "#1C4ED8" },
    ].filter((r) => r.total > 1) : [];

    // ── Section 6 — quality of earnings
    const arBuckets = (data && data.aging && data.aging.ar && data.aging.ar.buckets) || [];
    const arTotal = arBuckets.reduce((s, b) => s + (b.value || 0), 0);
    const arCurrent = arBuckets.length ? (arBuckets[0].value || 0) : 0;
    const arPctCurrent = arTotal ? arCurrent / arTotal * 100 : null;
    const cashConv = ni > 0 ? (ni + lt.da) / ni : null;
    // Revenue concentration — best-effort from subledger customers.
    let topCustPct = null;
    const custs = (data && (data.customers || (data.dimensions && data.dimensions.customers))) || [];
    if (custs.length) { const lv = custs.map((c) => Number(c.lifetime_value_cents || c.lifetime_value || 0)); const tot = lv.reduce((s, v) => s + v, 0); if (tot > 0) topCustPct = Math.max.apply(null, lv) / tot * 100; }
    // Gross-margin stability — stdev of last 4 quarterly GM%.
    let gmStab = null;
    const rA = (plH.revenue || []).map(Number), gA = (plH.gp || []).map(Number);
    if (rA.length >= 12) {
      const q = []; for (let k = 0; k < 4; k++) { let rr = 0, gg = 0; for (let m = 0; m < 3; m++) { const idx = rA.length - 1 - (k * 3) - m; if (idx >= 0) { rr += rA[idx]; gg += gA[idx]; } } if (rr) q.push(gg / rr * 100); }
      if (q.length >= 2) { const mu = q.reduce((s, v) => s + v, 0) / q.length; gmStab = Math.sqrt(q.reduce((s, v) => s + (v - mu) * (v - mu), 0) / q.length); }
    }
    const sig = (ok, warn) => ok ? "🟢" : warn ? "🟡" : "🔴";
    const qoe = [
      { m: "Cash conversion ((NI+D&A)/NI)", v: cashConv == null ? "—" : cashConv.toFixed(2) + "x", a: cashConv == null ? "Needs positive net income" : cashConv >= 1 ? "Earnings backed by cash" : "Earnings outpace cash", s: cashConv == null ? "⚪" : sig(cashConv >= 1, cashConv >= 0.8) },
      { m: "Revenue concentration (top customer)", v: topCustPct == null ? "—" : topCustPct.toFixed(0) + "%", a: topCustPct == null ? "Connect customer subledger" : topCustPct < 15 ? "Well diversified" : topCustPct < 30 ? "Moderate concentration" : "High single-customer risk", s: topCustPct == null ? "⚪" : sig(topCustPct < 15, topCustPct < 30) },
      { m: "AR quality (% current)", v: arPctCurrent == null ? "—" : arPctCurrent.toFixed(0) + "%", a: arPctCurrent == null ? "Connect AR subledger" : arPctCurrent >= 80 ? "Clean receivables" : arPctCurrent >= 60 ? "Some aging" : "Significant aged AR", s: arPctCurrent == null ? "⚪" : sig(arPctCurrent >= 80, arPctCurrent >= 60) },
      { m: "Gross-margin stability (4-qtr σ)", v: gmStab == null ? "—" : "±" + gmStab.toFixed(1) + "pp", a: gmStab == null ? "Needs 12 months history" : gmStab < 2 ? "Very stable margins" : gmStab < 5 ? "Some variability" : "Volatile margins", s: gmStab == null ? "⚪" : sig(gmStab < 2, gmStab < 5) },
      { m: "Recurring vs non-recurring revenue", v: "—", a: "Connect revenue classification to split recurring", s: "⚪" },
    ];

    // ── Section 7 — valuation reference (editable multiples)
    const [mult, setMult] = useState({ eb_low: 4.0, eb_base: 5.5, eb_high: 7.0, rev_low: 0.5, rev_base: 0.8, rev_high: 1.2 });
    const valRows = [
      { k: "eb_low", label: "EBITDA (Low)", basis: ebitda, mk: "eb_low" },
      { k: "eb_base", label: "EBITDA (Base)", basis: ebitda, mk: "eb_base" },
      { k: "eb_high", label: "EBITDA (High)", basis: ebitda, mk: "eb_high" },
      { k: "rev_low", label: "Revenue (Low)", basis: revenue, mk: "rev_low" },
      { k: "rev_base", label: "Revenue (Base)", basis: revenue, mk: "rev_base" },
      { k: "rev_high", label: "Revenue (High)", basis: revenue, mk: "rev_high" },
    ];

    // ── Section 8 — narrative
    const arche = (companyProfile && (companyProfile.industry || companyProfile.business_type)) || "business";
    const narrative = [
      { icon: "▣", text: "This is a <b>" + arche + "</b> generating <b>" + fmtShort(revenue) + "</b> of trailing-twelve-month revenue." },
      { icon: "◆", text: "LTM EBITDA is <b>" + fmtShort(ebitda) + "</b>" + (ebitdaMargin != null ? " (a <b>" + ebitdaMargin.toFixed(0) + "%</b> margin)" : "") + (ni != null ? ", with net income of " + fmtShort(ni) + "." : ".") },
      { icon: "▤", text: hasBS ? "The balance sheet carries <b>" + fmtShort(bs.debt) + "</b> of debt against <b>" + fmtShort(cashEnd) + "</b> of cash" + (debtEbitda != null ? " — <b>" + debtEbitda.toFixed(1) + "x</b> net leverage" : "") + "." : "Connect balance-sheet accounts to surface leverage and net-debt detail." },
      { icon: "▼", text: "Key risk: " + (debtEbitda != null && debtEbitda > 4 ? "leverage is elevated at " + debtEbitda.toFixed(1) + "x EBITDA." : topCustPct != null && topCustPct >= 30 ? "revenue concentration in the top customer (" + topCustPct.toFixed(0) + "%)." : intCov != null && intCov < 1.5 ? "thin interest coverage at " + intCov.toFixed(1) + "x." : "execution risk on sustaining the current growth and margin profile.") },
      { icon: "➜", text: "Forward outlook: " + (ebitda > 0 && (T && T.prior && T.cur.ebitda >= T.prior.ebitda) ? "EBITDA is expanding year-over-year — the trajectory supports continued reinvestment and debt service." : ebitda > 0 ? "the business is EBITDA-positive; protecting margin is the priority into next year." : "path-to-profitability is the central near-term objective.") },
    ];

    // ── render helpers
    const navyTh = (txt, align) => h("th", { style: { background: "#0F2044", color: "#fff", fontSize: 10.5, fontWeight: 600, textTransform: "uppercase", letterSpacing: 0.5, padding: "9px 12px", textAlign: align || "left" } }, txt);
    const covInput = (c) => h("input", { type: "number", value: draft[c.key] != null ? draft[c.key] : covOf(c), onChange: (e) => setDraft((p) => Object.assign({}, p, { [c.key]: e.target.value })), style: { width: 76, fontSize: 12, padding: "3px 5px", border: "1px solid " + K.LINE, borderRadius: 6, textAlign: "right" } });

    const td = (txt, extra) => h("td", Object.assign({ style: Object.assign({ padding: "7px 12px" }, (extra && extra.style) || {}) }, extra && extra.cls ? { className: extra.cls } : {}), txt);

    const bridgeTakeaway = bridge ? ("EBITDA moved from <b>" + fmtShort(bridge[0].value) + "</b> to <b>" + fmtShort(bridge[bridge.length - 1].value) + "</b> year-over-year" +
      (bridge[1] ? ", driven mainly by " + (Math.abs(bridge[1].value) >= Math.abs((bridge[2] || {}).value || 0) ? "revenue growth (" + (bridge[1].value >= 0 ? "+" : "−") + fmtShort(Math.abs(bridge[1].value)) + ")" : "gross-margin change (" + ((bridge[2] || {}).value >= 0 ? "+" : "−") + fmtShort(Math.abs((bridge[2] || {}).value || 0)) + ")") : "") + ".") : null;

    return h(K.Shell, { hero: { eyebrow: "INVESTOR & LENDER", title: "Financial Overview", subtitle: "Institutional-quality metrics for investors, lenders, and advisors · " + (isLtm ? "trailing twelve months" : range.label.toLowerCase()), controls: h(K.PeriodControls, Object.assign({}, ps, { showCompare: false })) } },

      // Row 1 — 6 KPI tiles
      h("div", { className: "pa-kpi-strip pa-kpi-strip-6" }, kpis.map((k, i) => h(K.Kpi, Object.assign({ key: i, animDelay: i * 0.04, onClick: () => window.__perduraSetPage && window.__perduraSetPage("income_statement") }, k)))),

      h("div", { style: { fontSize: 10, color: "#6475a0", padding: "2px 2px 10px", display: "flex", alignItems: "center", gap: 6 } },
        h("span", null, "💡"), "Click account rows to drill into transactions · Click metrics to navigate to detail pages"),

      // Row 2 — FINANCIAL STATEMENTS SUMMARY: three equal mini statements
      // (Mini P&L · Mini Balance Sheet · Mini Cash Flow), wrap on narrow screens.
      h("div", { style: { display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(300px, 1fr))", gap: 16, marginBottom: 16 } },
        h(K.Card, { title: "Income Statement (" + pLabel + ")", sub: "Actual vs prior year · margins colored" },
          MiniStatement(K, { headers: ["", "Actual", "Prior Y", "Δ%"], rows: plRows })),
        h(K.Card, { title: "Balance Sheet (" + (isLtm ? "latest month" : range.label) + ")", sub: "Cumulative GL position vs one year prior" },
          bsMiniRows ? MiniStatement(K, { headers: ["", "Current", "Prior Y", "Δ"], rows: bsMiniRows })
            : h("div", { style: { fontSize: 13, color: "#6475a0", padding: 8 } }, "Connect balance-sheet accounts to populate this summary.")),
        h(K.Card, { title: "Cash Flow (" + pLabel + ")", sub: "Indirect-method estimate · some lines derived" },
          h(React.Fragment, null,
            MiniStatement(K, { headers: ["", "Amount", "Prior Y", "Δ%"], rows: cfMiniRows }),
            h("div", { style: { fontSize: 10, color: "#6475a0", margin: "8px 10px 2px", fontStyle: "italic", lineHeight: 1.4 } },
              "Estimated from the GL (OCF ≈ NI + D&A; investing ≈ Δ net fixed assets + D&A; financing as residual). Connect the cash-flow engine for working-capital detail.")))),

      // Row 3 — 2-column: covenants · (QoE + valuation)
      h("div", { className: "pa-grid-2" },
        h(K.Card, {
          title: "Leverage & Covenants", sub: "Actual vs covenant · status reflects headroom", padding: 0,
          right: canEdit ? (editing
            ? h("div", { style: { display: "flex", gap: 6 } },
              h("button", { className: "pc-btn-mini", onClick: saveCov, disabled: saving }, saving ? "Saving…" : "Save"),
              h("button", { className: "pc-btn-mini ghost", onClick: () => { setEditing(false); setDraft({}); } }, "Cancel"))
            : h("button", { className: "pa-export-btn", onClick: () => setEditing(true) }, "Edit")) : null,
        },
          h("table", { className: "pa-table" },
            h("thead", null, h("tr", null, h("th", null, "Metric"), h("th", { className: "num" }, "Actual"), h("th", { className: "num" }, "Covenant"), h("th", null, "Status"))),
            h("tbody", null, COV.map((c, i) => { const e = covEval(c); return h("tr", { key: i },
              h("td", { style: { fontWeight: 600, padding: "8px 12px" } }, c.name),
              h("td", { className: "num", style: { padding: "8px 12px" } }, c.fmt(c.actual)),
              h("td", { className: "num muted", style: { padding: "8px 12px" } }, editing && canEdit ? covInput(c) : ((c.dir === "low" ? "< " : "> ") + c.fmt(covOf(c)))),
              h("td", { style: { padding: "8px 12px", fontWeight: 600, fontSize: 11, color: e.status === "green" ? "#18a867" : e.status === "amber" ? "#d97706" : e.status === "red" ? "#d94f47" : "#6475a0" } }, e.dot + " " + e.head)); })))),
        h("div", { style: { display: "flex", flexDirection: "column", gap: 12 } },
          h(K.Card, { title: "Quality of Earnings", sub: "Durability + cash backing", padding: 0 },
            h("table", { className: "pa-table" },
              h("thead", null, h("tr", null, h("th", null, "Metric"), h("th", { className: "num" }, "Value"), h("th", null, "Signal"))),
              h("tbody", null, qoe.map((r, i) => h("tr", { key: i },
                h("td", { style: { fontWeight: 500, padding: "7px 12px" } }, r.m),
                h("td", { className: "num", style: { padding: "7px 12px" } }, r.v),
                h("td", { style: { padding: "7px 12px", fontSize: 13 } }, r.s)))))),
          h(K.Card, { title: "Valuation Reference", sub: "Indicative EV · multiples editable", padding: 0 },
            h("table", { className: "pa-table" },
              h("thead", null, h("tr", null, h("th", null, "Methodology"), h("th", { className: "num" }, "Multiple"), h("th", { className: "num" }, "EV"))),
              h("tbody", null, valRows.map((r, i) => h("tr", { key: i },
                h("td", { style: { fontWeight: 500, padding: "7px 12px" } }, r.label),
                h("td", { className: "num", style: { padding: "7px 12px" } }, h("input", { type: "number", step: "0.1", value: mult[r.mk], onChange: (e) => setMult((p) => Object.assign({}, p, { [r.mk]: Number(e.target.value) })), style: { width: 54, fontSize: 12, padding: "2px 4px", border: "1px solid " + K.LINE, borderRadius: 6, textAlign: "right" } }), "x"),
                h("td", { className: "num", style: { padding: "7px 12px" } }, fmtShort((r.basis || 0) * mult[r.mk])))))),
            h("div", { style: { fontSize: 10.5, color: "#6475a0", margin: "8px 14px", fontStyle: "italic" } }, "For reference only — not a formal valuation.")))),

      // Row 4 — narrative
      h(K.Commentary, { title: "CFO Investor Narrative", items: narrative }));
  }

  window.InvestorPage = Page;
})();
