// CapexPage — window.CapexPage
//
// CAPEX Register: capital-expenditure projects sourced from the capex_projects
// table for the scoped company. Budget / spent / remaining KPIs, a per-category
// summary, a project register table with inline add + status pills + payback,
// a budget-vs-spent bar chart, a read-only approval-workflow reference, and a
// CSV importer. Honest empty state when no rows exist — never fabricates data.
//
// Props: { data, companyProfile, scopedCompanyId, globalPeriod, setPage }
//
// Table columns: company_id, project_id, project_name, category, fiscal_year,
// budget_amount, spent_ytd, committed, status, completion_pct,
// expected_completion_date, annual_cash_flow_benefit, notes.

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

  // ── status presentation (color + emoji per known status value) ──────────────
  const STATUS_STYLE = {
    "Planned": { color: "#6475a0", bg: "rgba(100,117,160,.12)", emoji: "📋" },
    "In Progress": { color: "#1C4ED8", bg: "rgba(28,78,216,.12)", emoji: "🔧" },
    "Delayed": { color: "#d97706", bg: "rgba(217,119,6,.12)", emoji: "⏳" },
    "Complete": { color: "#18a867", bg: "rgba(24,168,103,.12)", emoji: "✅" },
    "Cancelled": { color: "#d94f47", bg: "rgba(217,79,71,.12)", emoji: "✖" },
  };
  const statusStyleFor = (s) => STATUS_STYLE[s] || { color: "#6475a0", bg: "rgba(100,117,160,.12)", emoji: "•" };
  const STATUS_OPTIONS = ["Planned", "In Progress", "Delayed", "Complete", "Cancelled"];
  // "On track" = anything not Delayed/Cancelled.
  const isOnTrack = (s) => s !== "Delayed" && s !== "Cancelled";

  const DEFAULT_TIERS = [
    { band: "< $50K", a1: "Department Head", a2: "—", final: "Finance Manager", deadline: "5 business days" },
    { band: "$50K–$200K", a1: "Department Head", a2: "Finance Manager", final: "VP Finance", deadline: "10 business days" },
    { band: "$200K–$500K", a1: "Finance Manager", a2: "VP Finance", final: "CFO", deadline: "15 business days" },
    { band: "> $500K", a1: "VP Finance", a2: "CFO", final: "Board / CEO", deadline: "Next board cycle" },
  ];

  const nz = (v) => { const n = Number(v); return Number.isFinite(n) ? n : 0; };

  // Parse a CSV string into an array of objects keyed by header row.
  function parseCsv(text) {
    const rows = [];
    let i = 0, field = "", row = [], inQ = false;
    const pushField = () => { row.push(field); field = ""; };
    const pushRow = () => { rows.push(row); row = []; };
    while (i < text.length) {
      const c = text[i];
      if (inQ) {
        if (c === '"') { if (text[i + 1] === '"') { field += '"'; i += 2; continue; } inQ = false; i++; continue; }
        field += c; i++; continue;
      }
      if (c === '"') { inQ = true; i++; continue; }
      if (c === ",") { pushField(); i++; continue; }
      if (c === "\r") { i++; continue; }
      if (c === "\n") { pushField(); pushRow(); i++; continue; }
      field += c; i++;
    }
    if (field.length || row.length) { pushField(); pushRow(); }
    const nonEmpty = rows.filter((r) => r.some((v) => String(v).trim() !== ""));
    if (!nonEmpty.length) return { headers: [], records: [] };
    const headers = nonEmpty[0].map((hd) => String(hd).trim());
    const records = nonEmpty.slice(1).map((r) => {
      const o = {};
      headers.forEach((hd, j) => { o[hd] = r[j] != null ? String(r[j]).trim() : ""; });
      return o;
    });
    return { headers, records };
  }

  const CSV_COLUMNS = ["project_id", "project_name", "category", "budget_amount", "spent_ytd", "status", "completion_pct", "expected_completion_date", "annual_cash_flow_benefit"];

  // Sample CSV — exact column order the importer expects, with example rows.
  function downloadCapexTemplate() {
    const csv = [
      "project_id,project_name,category,budget_amount,spent_ytd,status,completion_pct,expected_completion_date,annual_cash_flow_benefit",
      "CAP-001,Production Line Upgrade,Equipment,250000,180000,In Progress,72,2025-09-30,45000",
      "CAP-002,ERP Implementation,IT/Software,120000,95000,Delayed,65,2025-12-31,0",
      "CAP-003,Warehouse Extension,Building,800000,12000,Planned,5,2026-06-30,60000",
    ].join("\n");
    const a = document.createElement("a");
    a.href = "data:text/csv;charset=utf-8," + encodeURIComponent(csv);
    a.download = "capex_template.csv";
    a.click();
  }

  // Progress-bar color per spec: red if over budget, amber if >80% spent but
  // <80% complete, else green (on track).
  function progressColor(budget, spent, pct) {
    const b = nz(budget), s = nz(spent), p = nz(pct);
    if (b > 0 && s > b) return "#d94f47";              // over budget
    if (b > 0 && s / b > 0.8 && p < 80) return "#d97706"; // spending ahead of completion
    return "#18a867";                                   // on track
  }

  function Page(props) {
    const K = window.PerduraPageKit;
    if (!K) return h("div", { className: "pc-page" }, "Loading…");
    const { scopedCompanyId, companyProfile } = props || {};
    const M = (v) => K.moneyStr(v, { compact: true });

    const [rows, setRows] = useState(null);     // null = loading
    const [reloadKey, setReloadKey] = useState(0);
    const [addOpen, setAddOpen] = useState(false);
    const [saving, setSaving] = useState(false);
    const [err, setErr] = useState("");

    // Inline add-project form state.
    const blankForm = {
      project_id: "", project_name: "", category: "", budget_amount: "", spent_ytd: "",
      committed: "", status: "Planned", completion_pct: "", expected_completion_date: "",
      annual_cash_flow_benefit: "", notes: "",
    };
    const [form, setForm] = useState(blankForm);

    // CSV import state.
    const [csvRecords, setCsvRecords] = useState(null);
    const [csvErr, setCsvErr] = useState("");
    const [csvSaving, setCsvSaving] = useState(false);

    useEffect(() => {
      let cancelled = false;
      const db = window.supabaseClient;
      if (!db || !scopedCompanyId) { setRows([]); return; }
      setRows(null);
      db.from("capex_projects").select("*").eq("company_id", scopedCompanyId).limit(5000)
        .then(({ data: d }) => { if (!cancelled) setRows(Array.isArray(d) ? d : []); },
              () => { if (!cancelled) setRows([]); });
      return () => { cancelled = true; };
    }, [scopedCompanyId, reloadKey]);

    const list = rows || [];

    // ── KPI aggregates ────────────────────────────────────────────────────────
    const agg = useMemo(() => {
      let budget = 0, spent = 0, onTrack = 0, delayed = 0;
      list.forEach((r) => {
        budget += nz(r.budget_amount);
        spent += nz(r.spent_ytd);
        if (isOnTrack(r.status)) onTrack++; else delayed++;
      });
      return { budget, spent, remaining: budget - spent, onTrack, delayed };
    }, [list]);
    const utilization = agg.budget ? agg.spent / agg.budget * 100 : null;

    // Publish CAPEX totals for cross-page consumers. Note: the KPI Scorecard
    // already reads capex_projects directly from the DB (so capex flows the
    // moment a project is saved); this global mirrors the page's totals.
    useEffect(() => {
      if (!list.length) { window._capexTotals = null; return; }
      window._capexTotals = { capex: agg.spent, capex_budget: agg.budget };
    }, [list, agg.spent, agg.budget]);

    // ── category summary (derived from rows, not hardcoded) ─────────────────────
    const categories = useMemo(() => {
      const map = new Map();
      list.forEach((r) => {
        const key = (r.category != null && String(r.category).trim() !== "") ? String(r.category).trim() : "Uncategorized";
        const e = map.get(key) || { name: key, budget: 0, spent: 0, count: 0 };
        e.budget += nz(r.budget_amount); e.spent += nz(r.spent_ytd); e.count++;
        map.set(key, e);
      });
      return Array.from(map.values()).sort((a, b) => b.budget - a.budget);
    }, [list]);

    // Border color: green <90% spent, amber 90-100%, red over budget.
    const catBorder = (e) => {
      const used = e.budget ? e.spent / e.budget * 100 : 0;
      return used > 100 ? "#d94f47" : used >= 90 ? "#d97706" : "#18a867";
    };

    const paybackOf = (r) => {
      const benefit = nz(r.annual_cash_flow_benefit);
      if (!benefit) return null;
      return nz(r.budget_amount) / benefit;
    };

    // ── add-project save ────────────────────────────────────────────────────────
    const setF = (k) => (e) => setForm((f) => Object.assign({}, f, { [k]: e.target.value }));
    const saveProject = () => {
      setErr("");
      const db = window.supabaseClient;
      if (!db || !scopedCompanyId) { setErr("No database connection."); return; }
      if (!String(form.project_name).trim()) { setErr("Project name is required."); return; }
      const record = {
        company_id: scopedCompanyId,
        project_id: String(form.project_id).trim() || null,
        project_name: String(form.project_name).trim(),
        category: String(form.category).trim() || null,
        budget_amount: form.budget_amount === "" ? null : nz(form.budget_amount),
        spent_ytd: form.spent_ytd === "" ? null : nz(form.spent_ytd),
        committed: form.committed === "" ? null : nz(form.committed),
        status: form.status || "Planned",
        completion_pct: form.completion_pct === "" ? null : nz(form.completion_pct),
        expected_completion_date: String(form.expected_completion_date).trim() || null,
        annual_cash_flow_benefit: form.annual_cash_flow_benefit === "" ? null : nz(form.annual_cash_flow_benefit),
        notes: String(form.notes).trim() || null,
      };
      setSaving(true);
      db.from("capex_projects").insert([record]).then(
        ({ error }) => {
          setSaving(false);
          if (error) { setErr(error.message || "Insert failed."); return; }
          setForm(blankForm); setAddOpen(false); setReloadKey((k) => k + 1);
        },
        (e) => { setSaving(false); setErr((e && e.message) || "Insert failed."); });
    };

    // ── CSV import ──────────────────────────────────────────────────────────────
    const onCsvFile = (e) => {
      setCsvErr(""); setCsvRecords(null);
      const file = e.target.files && e.target.files[0];
      if (!file) return;
      const reader = new FileReader();
      reader.onload = () => {
        try {
          const { headers, records } = parseCsv(String(reader.result || ""));
          if (!records.length) { setCsvErr("No rows found in file."); return; }
          const missing = CSV_COLUMNS.filter((c) => headers.indexOf(c) < 0);
          if (missing.length === CSV_COLUMNS.length) { setCsvErr("None of the expected columns were found. Expected: " + CSV_COLUMNS.join(", ")); return; }
          setCsvRecords(records);
        } catch (ex) { setCsvErr("Could not parse this file."); }
      };
      reader.onerror = () => setCsvErr("Could not read this file.");
      reader.readAsText(file);
    };
    const confirmCsv = () => {
      const db = window.supabaseClient;
      if (!db || !scopedCompanyId || !csvRecords) return;
      const records = csvRecords.map((r) => ({
        company_id: scopedCompanyId,
        project_id: (r.project_id || "").trim() || null,
        project_name: (r.project_name || "").trim() || "(unnamed)",
        category: (r.category || "").trim() || null,
        fiscal_year: r.fiscal_year === "" || r.fiscal_year == null ? null : Math.round(nz(r.fiscal_year)),
        budget_amount: r.budget_amount === "" || r.budget_amount == null ? null : nz(r.budget_amount),
        spent_ytd: r.spent_ytd === "" || r.spent_ytd == null ? null : nz(r.spent_ytd),
        committed: r.committed === "" || r.committed == null ? null : nz(r.committed),
        status: (r.status || "").trim() || "Planned",
        completion_pct: r.completion_pct === "" || r.completion_pct == null ? null : nz(r.completion_pct),
        expected_completion_date: (r.expected_completion_date || "").trim() || null,
        annual_cash_flow_benefit: r.annual_cash_flow_benefit === "" || r.annual_cash_flow_benefit == null ? null : nz(r.annual_cash_flow_benefit),
        notes: (r.notes || "").trim() || null,
      }));
      setCsvSaving(true); setCsvErr("");
      // Idempotent for rows that carry a project_id: clear this company's
      // existing rows with those ids first, then insert (the table has no
      // unique constraint on (company_id, project_id), so an upsert/onConflict
      // would error). Manual rows without a project_id are plain inserts.
      const ids = Array.from(new Set(records.map((x) => x.project_id).filter(Boolean)));
      const run = ids.length
        ? db.from("capex_projects").delete().eq("company_id", scopedCompanyId).in("project_id", ids)
            .then(({ error }) => { if (error) throw new Error(error.message); return db.from("capex_projects").insert(records); })
        : db.from("capex_projects").insert(records);
      run.then(({ error }) => {
        setCsvSaving(false);
        if (error) { setCsvErr(error.message || "Import failed."); return; }
        setCsvRecords(null); setReloadKey((k) => k + 1);
        window.logAuditEvent && window.logAuditEvent("data_upload", { category: "data", page: "capex", detail: "CAPEX projects uploaded: " + records.length + " projects" });
      }).catch((e) => { setCsvSaving(false); setCsvErr((e && e.message) || "Import failed."); });
    };

    // ── tier source ─────────────────────────────────────────────────────────────
    const tiers = (companyProfile && Array.isArray(companyProfile.approval_tiers) && companyProfile.approval_tiers.length)
      ? companyProfile.approval_tiers : DEFAULT_TIERS;

    const loading = rows === null;

    // ── shared input styling ────────────────────────────────────────────────────
    const inp = { padding: "6px 9px", fontSize: 12.5, border: "1px solid " + K.LINE, borderRadius: 7, outline: "none", background: "#fff", color: "#1a2233", width: "100%" };
    const btn = (primary) => ({ padding: "8px 16px", fontSize: 12.5, fontWeight: 700, borderRadius: 8, cursor: "pointer", border: "1px solid " + (primary ? "#1C4ED8" : K.LINE), background: primary ? "#1C4ED8" : "#fff", color: primary ? "#fff" : "#1C4ED8" });

    // ── KPI tiles ────────────────────────────────────────────────────────────────
    const kpis = [
      { label: "Total Budget", value: loading ? "…" : M(agg.budget), valueColor: "navy", sub: list.length + " project" + (list.length === 1 ? "" : "s") },
      { label: "Spent YTD", value: loading ? "…" : M(agg.spent), valueColor: "blue", sub: "capital deployed" },
      { label: "Remaining", value: loading ? "…" : M(agg.remaining), valueColor: agg.remaining < 0 ? "red" : "green", sub: agg.remaining < 0 ? "over budget" : "budget left" },
      { label: "Budget Utilization", value: utilization == null ? "—" : utilization.toFixed(0) + "%", valueColor: utilization == null ? "navy" : utilization > 100 ? "red" : utilization >= 90 ? "amber" : "teal", sub: "spent ÷ budget" },
      { label: "On Track / Delayed", value: loading ? "…" : (agg.onTrack + " / " + agg.delayed), valueColor: agg.delayed > 0 ? "amber" : "green", sub: "by project status" },
    ];

    // ── Section 1: category summary cards ────────────────────────────────────────
    function renderCategories() {
      if (loading) return h(K.Card, { title: "BY CATEGORY" }, h("div", { style: { padding: 16, color: "#6475a0", fontSize: 13 } }, "Loading…"));
      if (!categories.length) return null;
      return h(K.Card, { title: "BY CATEGORY", sub: categories.length + " categor" + (categories.length === 1 ? "y" : "ies"), padding: 0 },
        h("div", { style: { display: "grid", gridTemplateColumns: "repeat(auto-fill, minmax(200px, 1fr))", gap: 12, padding: 14 } },
          categories.map((e) => {
            const used = e.budget ? e.spent / e.budget * 100 : 0;
            return h("div", { key: e.name, style: { borderLeft: "4px solid " + catBorder(e), background: "#fafbfe", borderRadius: 8, padding: "12px 14px", border: "1px solid " + K.LINE } },
              h("div", { style: { fontWeight: 700, color: "#0d2040", fontSize: 13, marginBottom: 8 } }, e.name),
              h("div", { style: { display: "flex", justifyContent: "space-between", fontSize: 11.5, color: "#475569", marginBottom: 3 } }, h("span", null, "Budget"), h("b", { style: { fontFamily: K.MONO, color: "#0d2040" } }, M(e.budget))),
              h("div", { style: { display: "flex", justifyContent: "space-between", fontSize: 11.5, color: "#475569", marginBottom: 3 } }, h("span", null, "Spent"), h("b", { style: { fontFamily: K.MONO, color: "#0d2040" } }, M(e.spent))),
              h("div", { style: { display: "flex", justifyContent: "space-between", fontSize: 11.5, color: "#475569" } },
                h("span", null, "% Used"), h("b", { style: { fontFamily: K.MONO, color: catBorder(e) } }, e.budget ? used.toFixed(0) + "%" : "—")),
              h("div", { style: { fontSize: 10.5, color: "#94a3b8", marginTop: 6 } }, e.count + " project" + (e.count === 1 ? "" : "s")));
          })));
    }

    // ── Section 2: project register table ────────────────────────────────────────
    const th = (txt, align) => h("th", { style: { textAlign: align || "left", padding: "9px 10px", fontSize: 10.5, fontWeight: 700, letterSpacing: 0.4, textTransform: "uppercase", color: "#6475a0", borderBottom: "1px solid " + K.LINE, whiteSpace: "nowrap" } }, txt);
    const td = (children, style) => h("td", { style: Object.assign({ padding: "8px 10px", borderBottom: "1px solid #F1F5F9", color: "#475569", fontSize: 12.5 }, style || {}) }, children);

    function progressBar(pct, budget, spent) {
      const p = Math.max(0, Math.min(100, nz(pct)));
      const color = progressColor(budget, spent, pct);
      return h("div", { style: { display: "flex", alignItems: "center", gap: 8, minWidth: 110 } },
        h("div", { style: { flex: 1, height: 8, background: "#eef1f6", borderRadius: 5, overflow: "hidden" } },
          h("div", { style: { width: p + "%", height: "100%", background: color, transition: "width .5s ease" } })),
        h("span", { style: { fontSize: 11, fontWeight: 700, fontFamily: K.MONO, color: "#475569", width: 34, textAlign: "right" } }, p.toFixed(0) + "%"));
    }
    function statusPill(status) {
      const ss = statusStyleFor(status);
      return h("span", { style: { display: "inline-flex", alignItems: "center", gap: 4, padding: "3px 9px", borderRadius: 999, fontSize: 11, fontWeight: 700, color: ss.color, background: ss.bg, whiteSpace: "nowrap" } }, ss.emoji + " " + (status || "—"));
    }

    function renderRegister() {
      const addBtn = h("button", { onClick: () => { setErr(""); setAddOpen((v) => !v); }, style: btn(false) }, addOpen ? "× Cancel" : "+ Add Project");
      const formRow = addOpen ? h("tr", { style: { background: "#f5f8ff" } },
        h("td", { colSpan: 10, style: { padding: 14 } },
          h("div", { style: { display: "grid", gridTemplateColumns: "repeat(auto-fill, minmax(160px,1fr))", gap: 10 } },
            h("input", { style: inp, placeholder: "Project ID", value: form.project_id, onChange: setF("project_id") }),
            h("input", { style: inp, placeholder: "Project name *", value: form.project_name, onChange: setF("project_name") }),
            h("input", { style: inp, placeholder: "Category", value: form.category, onChange: setF("category") }),
            h("input", { style: inp, type: "number", placeholder: "Budget", value: form.budget_amount, onChange: setF("budget_amount") }),
            h("input", { style: inp, type: "number", placeholder: "Spent YTD", value: form.spent_ytd, onChange: setF("spent_ytd") }),
            h("input", { style: inp, type: "number", placeholder: "Committed", value: form.committed, onChange: setF("committed") }),
            h("select", { style: inp, value: form.status, onChange: setF("status") }, STATUS_OPTIONS.map((s) => h("option", { key: s, value: s }, s))),
            h("input", { style: inp, type: "number", placeholder: "% Complete", value: form.completion_pct, onChange: setF("completion_pct") }),
            h("input", { style: inp, type: "date", placeholder: "Expected completion", value: form.expected_completion_date, onChange: setF("expected_completion_date") }),
            h("input", { style: inp, type: "number", placeholder: "Annual cash benefit", value: form.annual_cash_flow_benefit, onChange: setF("annual_cash_flow_benefit") }),
            h("input", { style: Object.assign({}, inp, { gridColumn: "1 / -1" }), placeholder: "Notes", value: form.notes, onChange: setF("notes") })),
          err ? h("div", { style: { color: "#d94f47", fontSize: 12, marginTop: 8, fontWeight: 600 } }, err) : null,
          h("div", { style: { marginTop: 10, display: "flex", gap: 8 } },
            h("button", { onClick: saveProject, disabled: saving, style: Object.assign({}, btn(true), saving ? { opacity: 0.6, cursor: "default" } : null) }, saving ? "Saving…" : "Save project")))) : null;

      const sorted = list.slice().sort((a, b) => nz(b.budget_amount) - nz(a.budget_amount));
      return h(K.Card, { title: "PROJECT REGISTER", sub: list.length + " project" + (list.length === 1 ? "" : "s"), right: addBtn, padding: 0 },
        h("div", { style: { overflowX: "auto" } },
          h("table", { style: { width: "100%", borderCollapse: "collapse", minWidth: 1040 } },
            h("thead", null, h("tr", null,
              th("Project ID"), th("Project Name"), th("Category"),
              th("Budget", "right"), th("Spent", "right"), th("Remaining", "right"),
              th("% Complete"), th("Status"), th("Payback", "right"), th("Notes"))),
            h("tbody", null,
              formRow,
              sorted.length ? sorted.map((r, i) => {
                const rem = nz(r.budget_amount) - nz(r.spent_ytd);
                const pb = paybackOf(r);
                return h("tr", { key: r.id != null ? r.id : (r.project_id || "") + "-" + i },
                  td(r.project_id || "—", { fontFamily: K.MONO, color: "#6475a0", fontSize: 11.5 }),
                  td(r.project_name || "—", { fontWeight: 600, color: "#0d2040" }),
                  td(r.category || "—"),
                  td(M(r.budget_amount), { textAlign: "right", fontFamily: K.MONO }),
                  td(M(r.spent_ytd), { textAlign: "right", fontFamily: K.MONO }),
                  td(M(rem), { textAlign: "right", fontFamily: K.MONO, color: rem < 0 ? "#d94f47" : "#475569", fontWeight: 600 }),
                  td(progressBar(r.completion_pct, r.budget_amount, r.spent_ytd)),
                  td(statusPill(r.status)),
                  td(pb == null ? "—" : pb.toFixed(1) + " yrs", { textAlign: "right", fontFamily: K.MONO, color: pb == null ? "#94a3b8" : "#475569" }),
                  td(r.notes && String(r.notes).trim() ? r.notes : "—", { color: r.notes ? "#475569" : "#94a3b8", fontSize: 11.5, maxWidth: 220, whiteSpace: "normal" }));
              }) : (addOpen ? null : h("tr", null, h("td", { colSpan: 10, style: { padding: 18, color: "#6475a0", fontSize: 13, textAlign: "center" } }, "No projects yet — add one above or import a CSV below.")))))));
    }

    // ── Section 3: budget vs spent horizontal bars ───────────────────────────────
    function renderBudgetVsSpent() {
      if (!list.length) return null;
      const sorted = list.slice().sort((a, b) => nz(b.budget_amount) - nz(a.budget_amount)).slice(0, 20);
      const maxB = Math.max(1, ...sorted.map((r) => Math.max(nz(r.budget_amount), nz(r.spent_ytd))));
      return h(K.Card, { title: "BUDGET vs SPENT", sub: "By project · spent overlay colored by status", padding: 0 },
        h("div", { style: { padding: 14, display: "flex", flexDirection: "column", gap: 10 } },
          sorted.map((r, i) => {
            const b = nz(r.budget_amount), s = nz(r.spent_ytd);
            const ss = statusStyleFor(r.status);
            return h("div", { key: r.id != null ? r.id : i },
              h("div", { style: { display: "flex", justifyContent: "space-between", fontSize: 11.5, marginBottom: 4 } },
                h("span", { style: { fontWeight: 600, color: "#0d2040", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", maxWidth: "65%" } }, r.project_name || r.project_id || "—"),
                h("span", { style: { fontFamily: K.MONO, color: "#6475a0" } }, M(s) + " / " + M(b))),
              h("div", { style: { position: "relative", height: 18, background: "#eef1f6", borderRadius: 5, overflow: "hidden" } },
                h("div", { title: "Spent " + M(s), style: { position: "absolute", left: 0, top: 0, bottom: 0, width: (Math.min(b, s) / maxB * 100) + "%", background: ss.color, borderRadius: 5 } }),
                s > b ? h("div", { title: "Over budget", style: { position: "absolute", left: (b / maxB * 100) + "%", top: 0, bottom: 0, width: ((s - b) / maxB * 100) + "%", background: "#d94f47", opacity: 0.7 } }) : null,
                h("div", { style: { position: "absolute", left: (b / maxB * 100) + "%", top: -2, bottom: -2, width: 2, background: "#0d2040" } })));
          }),
          h("div", { style: { display: "flex", gap: 16, marginTop: 4, fontSize: 10.5, color: "#6475a0" } },
            h("span", null, "▮ bar = spent (by status)"), h("span", null, "│ marker = budget"))));
    }

    // ── Section 4: approval workflow reference ───────────────────────────────────
    function renderApprovals() {
      return h(K.Card, { title: "APPROVAL WORKFLOW", sub: "Reference tiers · read-only", padding: 0 },
        h("div", { style: { overflowX: "auto" } },
          h("table", { style: { width: "100%", borderCollapse: "collapse", minWidth: 560 } },
            h("thead", null, h("tr", null, th("Amount Band"), th("Approver 1"), th("Approver 2"), th("Final Approval"), th("Decision Deadline"))),
            h("tbody", null, tiers.map((t, i) => h("tr", { key: i },
              td(t.band, { fontWeight: 700, color: "#0d2040" }),
              td(t.a1), td(t.a2), td(t.final), td(t.deadline, { color: "#6475a0" })))))));
    }

    // ── Section 5: CSV upload ────────────────────────────────────────────────────
    function renderUpload() {
      return h(K.Card, { title: "IMPORT FROM CSV", sub: "Columns: " + CSV_COLUMNS.join(", ") },
        h("div", { style: { display: "flex", flexDirection: "column", gap: 12 } },
          h("div", { style: { display: "flex", flexWrap: "wrap", alignItems: "center", gap: 12 } },
            h("button", { onClick: downloadCapexTemplate, style: btn(false) }, "⭳ Download sample CSV"),
            h("input", { type: "file", accept: ".csv", onChange: onCsvFile, style: { fontSize: 12.5 } })),
          csvErr ? h("div", { style: { color: "#d94f47", fontSize: 12, fontWeight: 600 } }, csvErr) : null,
          csvRecords ? h("div", null,
            h("div", { style: { fontSize: 12.5, color: "#475569", marginBottom: 8 } }, h("b", null, csvRecords.length), " row" + (csvRecords.length === 1 ? "" : "s") + " ready to import — preview:"),
            h("div", { style: { overflowX: "auto", border: "1px solid " + K.LINE, borderRadius: 8 } },
              h("table", { style: { width: "100%", borderCollapse: "collapse", minWidth: 720 } },
                h("thead", null, h("tr", null, CSV_COLUMNS.map((c) => th(c)))),
                h("tbody", null, csvRecords.slice(0, 8).map((r, i) => h("tr", { key: i },
                  CSV_COLUMNS.map((c) => td(r[c] != null && r[c] !== "" ? r[c] : "—", { fontSize: 11.5 }))))))),
            csvRecords.length > 8 ? h("div", { style: { fontSize: 11, color: "#94a3b8", marginTop: 6 } }, "…and " + (csvRecords.length - 8) + " more") : null,
            h("div", { style: { marginTop: 12, display: "flex", gap: 8 } },
              h("button", { onClick: confirmCsv, disabled: csvSaving, style: Object.assign({}, btn(true), csvSaving ? { opacity: 0.6, cursor: "default" } : null) }, csvSaving ? "Importing…" : "Confirm import (" + csvRecords.length + ")"),
              h("button", { onClick: () => { setCsvRecords(null); setCsvErr(""); }, style: btn(false) }, "Discard"))) : null));
    }

    // ── empty state ──────────────────────────────────────────────────────────────
    const isEmpty = !loading && !list.length;

    return h(K.Shell, { hero: {
      eyebrow: "OPERATIONS", title: "CAPEX Register",
      subtitle: "Capital projects · budget vs spent · approval workflow",
    } },
      h("div", { className: "pa-kpi-strip pa-kpi-strip-5" }, kpis.map((k, i) => h(K.Kpi, Object.assign({ key: i, animDelay: i * 0.05, onClick: () => window.__perduraSetPage && window.__perduraSetPage("cash_flow_statement") }, k)))),

      isEmpty
        ? h(K.Card, { title: "CAPEX Register" },
            h("div", { style: { padding: 18, fontSize: 13, color: "#6475a0", lineHeight: 1.6 } },
              h("b", null, "No capital projects on file yet. "),
              "This page reads from the capex_projects table for the selected company. Use the “+ Add Project” form below to record one, or import a CSV. Nothing is shown until real projects are recorded."))
        : null,

      renderCategories(),
      renderRegister(),
      renderBudgetVsSpent(),
      renderApprovals(),
      renderUpload());
  }

  window.CapexPage = Page;
})();
