/* screens-weeklyreport.jsx — Weekly Report PDF export v2 (Brian 7/20 evening).
   v1 bugs fixed: (1) mondayOf used toISOString (UTC) → after ~5pm local the report
   asked for TOMORROW's week and every weekly section came back empty. Local date
   built from local parts now. (2) pipeline fetch unscoped + uncapped → firm-wide
   1,000-row garbage; now module-scoped. (3) browsers strip background colors in
   print → print-color-adjust: exact everywhere.
   v2 sections (all real data): Key Metrics · Leaderboard (getModuleIndividuals,
   Brian excluded, per-column leaders bolded) · YTD Deal Fees by Sub-Team (closed
   2026, dm2→sub-team via the individuals map, printed bars) · YTD Funnel
   (getOverviewTotals Jan1→today) · Cumulative fees ramp (inline SVG) ·
   New Signings & Deals · Research Plan Progress · Pipeline snapshot. */
(() => {
  const localYMD = (d) => d.getFullYear() + "-" + String(d.getMonth() + 1).padStart(2, "0") + "-" + String(d.getDate()).padStart(2, "0");
  const mondayOf = (d) => { const x = new Date(d.getFullYear(), d.getMonth(), d.getDate()); const dow = x.getDay() || 7; if (dow !== 1) x.setDate(x.getDate() - (dow - 1)); return localYMD(x); };
  const plusD = (s, n) => { const d = new Date(s + "T00:00:00"); d.setDate(d.getDate() + n); return localYMD(d); };
  const fmt = (s) => new Date(s + "T00:00:00").toLocaleDateString("en-US", { month: "short", day: "numeric" });
  const money = (n) => (n == null || isNaN(n)) ? "\u2014" : "$" + Number(n).toLocaleString();
  const moneyK = (n) => (n == null || isNaN(n)) ? "\u2014" : (n >= 1e6 ? "$" + (n / 1e6).toFixed(2) + "M" : "$" + Math.round(n / 1e3) + "K");
  const esc = (s) => String(s == null ? "" : s).replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
  const inWk = (dateStr, wk) => { const d = String(dateStr || "").slice(0, 10); return d >= wk && d < plusD(wk, 7); };

  // Weekly goals — Scott Module row of the Stat Tracker (Brian's Excel, 7/20 screenshot).
  // Edit here when goals re-baseline.
  const WEEKLY_GOALS = { leads: 21, ntps: 9, mailings: 200, calls: 375, confCalls: 11, visits: 4, offers: 1.5 };
  // BHAG deal-fee targets — 2026_Scott_BHAGProjections_1_8_26.xlsx (BHAG sheets).
  const BHAG_FEES = { "Scheftz Team": 10195000, "Burton Team": 3565000 };
  const BHAG_MODULE = 10195000 + 3565000;
  const WEEK1 = "2026-01-05"; // first Monday of the year — prorates YTD goals
  const paceColor = (v, target) => target == null ? null : (v >= target ? "#14603A" : v >= target * 0.7 ? "#8A5A12" : "#7C2438");

  const STAGE_BUCKETS = [
    ["Signed LOIs", r => Math.abs(r.status - 9.0) < 0.005],
    ["Current Offers", r => r.status >= 8.0 && r.status < 9.0],
    ["Pending Offer", r => r.status >= 7.0 && r.status <= 7.5],
    ["Visit", r => Math.abs(r.status - 6.0) < 0.005],
    ["Conf Call", r => Math.abs(r.status - 5.5) < 0.005],
    ["Data", r => Math.abs(r.status - 5.2) < 0.005],
    ["Leads", r => Math.abs(r.status - 5.0) < 0.005],
  ];
  const LB_COLS = [["ntps", "Lists"], ["mailings", "Mailings"], ["calls", "Calls"], ["leads", "Leads"], ["confCalls", "CC"], ["visits", "Visits"], ["offers", "Offers"]];

  function _build({ wk, moduleLabel, generatedBy, pipeline, goals, plans, newClients, offers, closed, individuals, ytd }) {
    const wkEnd = plusD(wk, 6);
    const year = wk.slice(0, 4);
    const offersWk = (offers || []).filter(o => inWk(o.offerDate, wk));
    const closedWk = (closed || []).filter(c => inWk(c.closeDate, wk));
    const closedYtd = (closed || []).filter(c => String(c.closeDate || "").slice(0, 4) === year);
    const ncWk = (newClients || []).filter(n => inWk(n.origDate, wk));
    const gWk = (goals || []).filter(g => String(g.weekStart || "").slice(0, 10) === wk);
    const doneIn = sec => gWk.filter(g => g.section === sec && g.done).length;
    const totIn = sec => gWk.filter(g => g.section === sec).length;
    const feesWk = closedWk.reduce((a, c) => a + (Number(c.fee) || 0), 0);

    const metrics = [
      ["New Offers", offersWk.length],
      ["Deals Closed", closedWk.length + (feesWk ? " \u00b7 " + moneyK(feesWk) : "")],
      ["New Clients", ncWk.length],
      ["Mailings Sent", doneIn("mailings") + (totIn("mailings") ? " / " + totIn("mailings") : "")],
      ["Lists Completed", doneIn("approval") + (totIn("approval") ? " / " + totIn("approval") : "")],
    ];

    // Leaderboard (Brian excluded); per-column leaders bolded
    const board = (individuals || []).filter(p => p.personId !== "bscott")
      .sort((a, b) => (b.calls + b.mailings) - (a.calls + a.mailings));
    const colMax = {}; LB_COLS.forEach(([k]) => { colMax[k] = Math.max(0, ...board.map(p => p[k] || 0)); });
    const subTeamOf = {}; (individuals || []).forEach(p => { subTeamOf[p.personId] = p.subTeamLabel || null; });

    // YTD fees by sub-team: resolve dm2 (fallback dm3) through ORG data, normalized
    // to the two teams Brian reports on. Everything else stays in the module total
    // but off the bars (Brian 7/20: no "Module / Other" bucket).
    const FIRM = (window.VAULT_FIRM || {});
    const teamOfPerson = (id) => {
      const viaWeek = subTeamOf[id];
      const p2 = (FIRM.PEOPLE_BY_ID || {})[id];
      const raw = String(viaWeek || (p2 && (p2.subteam || p2.team)) || "").toLowerCase();
      if (raw.includes("scheftz") || raw.includes("jscheftz")) return "Scheftz Team";
      if (raw.includes("burton") || raw.includes("gburton")) return "Burton Team";
      return null;
    };
    const feeBy = { "Scheftz Team": 0, "Burton Team": 0 };
    let feeTotal = 0;
    closedYtd.forEach(c => {
      const fee = Number(c.fee) || 0; feeTotal += fee;
      const st = teamOfPerson(c.dm2) || teamOfPerson(c.dm3);
      if (st) feeBy[st] += fee;
    });
    const feeRows = Object.entries(feeBy); // fixed order: Scheftz, Burton
    const feeMax = Math.max(1, ...feeRows.map(([, v]) => v));

    // Cumulative fees ramp (SVG, months Jan..current)
    const nowM = Number(wk.slice(5, 7));
    const cum = []; let run = 0;
    for (let m = 1; m <= nowM; m++) {
      run += closedYtd.filter(c => Number(String(c.closeDate || "").slice(5, 7)) === m)
        .reduce((a, c) => a + (Number(c.fee) || 0), 0);
      cum.push(run);
    }
    const W = 330, H = 132, padL = 42, padR = 8, padT = 8, padB = 18;
    const maxC = Math.max(1, ...cum);
    const X = i => padL + (cum.length === 1 ? 0 : i * (W - padL - padR) / (cum.length - 1));
    const Y = v => padT + (1 - v / maxC) * (H - padT - padB);
    const pts = cum.map((v, i) => X(i).toFixed(1) + "," + Y(v).toFixed(1)).join(" ");
    const MABBR = ["J","F","M","A","M","J","J","A","S","O","N","D"];
    const grid = [0, .25, .5, .75, 1].map(f => `<line x1="${padL}" x2="${W - padR}" y1="${Y(maxC * f).toFixed(1)}" y2="${Y(maxC * f).toFixed(1)}" stroke="#E2E8EE" stroke-width="1"/><text x="${padL - 5}" y="${(Y(maxC * f) + 3).toFixed(1)}" text-anchor="end" font-family="IBM Plex Mono,monospace" font-size="7.5" fill="#8896A5">${moneyK(maxC * f)}</text>`).join("");
    const ticks = cum.map((v, i) => `<text x="${X(i).toFixed(1)}" y="${H - 4}" text-anchor="middle" font-family="IBM Plex Mono,monospace" font-size="7.5" fill="#8896A5">${MABBR[i]}</text>`).join("");
    const ramp = cum.length ? `<svg width="${W}" height="${H}" viewBox="0 0 ${W} ${H}" xmlns="http://www.w3.org/2000/svg">
      ${grid}${ticks}
      <polyline points="${pts}" fill="none" stroke="#2E77C2" stroke-width="2.5"/>
      <circle cx="${X(cum.length - 1).toFixed(1)}" cy="${Y(cum[cum.length - 1]).toFixed(1)}" r="3.5" fill="#1F9D57"/>
      <text x="${(X(cum.length - 1) - 4).toFixed(1)}" y="${(Y(cum[cum.length - 1]) - 6).toFixed(1)}" text-anchor="end" font-family="IBM Plex Mono,monospace" font-size="8" font-weight="700" fill="#14603A">${moneyK(cum[cum.length - 1])}</text>
    </svg>` : "";

    const signRows = [
      ...offersWk.map(o => ({ co: o.target, buyer: o.buyer, stage: o.stage || "Offer", amt: o.amount || "\u2014", d: o.offerDate })),
      ...closedWk.map(c => ({ co: c.name, buyer: c.buyer, stage: "Closed", amt: moneyK(Number(c.fee)), d: c.closeDate })),
    ].sort((a, b) => String(b.d || "").localeCompare(String(a.d || "")));

    const buckets = STAGE_BUCKETS.map(([lbl, fn]) => [lbl, (pipeline || []).filter(fn).length]);
    const planRows = (plans || []).map(p => {
      const rows = gWk.filter(g => g.planId === p.id);
      const c = sec => ({ d: rows.filter(g => g.section === sec && g.done).length, t: rows.filter(g => g.section === sec).length });
      const r = c("research"), a = c("approval"), m = c("mailings");
      return { label: p.label || p.name || "Team", r, a, m };
    }).filter(p => p.r.t + p.a.t + p.m.t > 0);

    const F = ytd || {};
    const funnel = [["Lists", F.ntps], ["Leads", F.leads], ["Conf. Calls", F.confCalls], ["Visits", F.visits], ["Offers", F.offers], ["Signed LOIs", F.signedLOIs], ["Closed", F.closedDeals]]
      .map(([l, v]) => [l, Number(v) || 0]);
    const fMax = Math.max(1, ...funnel.map(([, v]) => v));

    // ---- Boardroom-only aggregates (from the same fetched data) ----
    const ind = (individuals || []).filter(p => p.personId !== "bscott");
    const sum = k => ind.reduce((a, p) => a + (Number(p[k]) || 0), 0);
    const wkCC = sum("confCalls"), wkLOI = ind.reduce((a, p) => a + (Number(p.loiExec) || 0), 0);
    const teams = {};
    ind.forEach(p => { const t = p.subTeamLabel || "Module"; (teams[t] = teams[t] || { calls: 0, confCalls: 0, leads: 0, offers: 0, fees: 0 });
      ["calls", "confCalls", "leads", "offers"].forEach(k => teams[t][k] += Number(p[k]) || 0); });
    closedWk.forEach(c => { const t = subTeamOf[c.dm2] || subTeamOf[c.dm3]; if (t && teams[t]) teams[t].fees += Number(c.fee) || 0; });
    const teamRows2 = Object.entries(teams).sort((a, b) => b[1].calls - a[1].calls);
    const tTot = { calls: sum("calls"), confCalls: wkCC, leads: sum("leads"), offers: sum("offers"), fees: feesWk };
    const acc = [];
    offersWk.filter(o => /LOI/i.test(o.stage || "")).forEach(o => acc.push(`<b>${esc(o.co || o.target)}</b> advanced to <b>${esc(o.stage)}</b>${o.amount ? " \u00b7 est. " + esc(o.amount) : ""}.`));
    closedWk.forEach(c => acc.push(`Closed <b>${esc(c.name)}</b> (${esc(c.buyer)}) \u00b7 ${moneyK(Number(c.fee))} fee.`));
    if (ncWk.length) acc.push(`Onboarded <b>${ncWk.length} new client${ncWk.length === 1 ? "" : "s"}</b>: ${ncWk.slice(0, 3).map(n => esc(n.project)).join(", ")}.`);
    if (doneIn("mailings")) acc.push(`<b>${doneIn("mailings")}</b> mailing set${doneIn("mailings") === 1 ? "" : "s"} sent (${doneIn("mailings")}/${totIn("mailings")} planned).`);
    if (doneIn("approval")) acc.push(`<b>${doneIn("approval")}</b> of ${totIn("approval")} approval lists completed.`);
    const topCaller = ind.slice().sort((a, b) => b.calls - a.calls)[0];
    if (topCaller && topCaller.calls) acc.push(`Top outreach: <b>${esc(topCaller.personName)}</b> \u00b7 ${topCaller.calls} calls.`);
    const F2 = ytd || {};
    // Weeks elapsed for prorating YTD goals (inclusive of the current week)
    const wksElapsed = Math.max(1, Math.round((new Date(wk + "T00:00:00") - new Date(WEEK1 + "T00:00:00")) / 6048e5) + 1);
    // First stage is the NTP / conflict-check count (the overview API aliases it "lists" —
    // NOT approval lists; that was the v3 mislabel Brian caught at 1,142).
    const fun = [["Conflict Chk", F2.ntps, null], ["Leads", F2.leads, WEEKLY_GOALS.leads], ["Conf Calls", F2.confCalls, WEEKLY_GOALS.confCalls], ["Visits", F2.visits, WEEKLY_GOALS.visits], ["Offers", F2.offers, WEEKLY_GOALS.offers], ["Signed LOIs", F2.signedLOIs, null], ["Closed", F2.closedDeals, null]].map(([l, v, g]) => [l, Number(v) || 0, g == null ? null : Math.round(g * wksElapsed)]);
    const pct = (a, b) => b ? Math.round(a / b * 1000) / 10 + "%" : "\u2014";
    const eff = [["Lead / List", pct(fun[1][1], fun[0][1])], ["CC / Lead", pct(fun[2][1], fun[1][1])], ["Off / CC", pct(fun[4][1], fun[2][1])]];

    const AR = "'Archivo',system-ui,sans-serif", PM = "'IBM Plex Mono',Consolas,monospace", LF = "'Libre Franklin',system-ui,sans-serif";
    const kick = (t, extra) => `<div style="display:flex;align-items:center;gap:8px;margin:13px 0 7px"><span style="width:4px;height:13px;background:#1F9D57;border-radius:1px"></span><span style="font:800 11px/1 ${AR};letter-spacing:.13em;color:#142B44">${t}</span>${extra ? `<span style="font:500 9.5px/1 ${PM};color:#8896a5;margin-left:6px">${extra}</span>` : ""}</div>`;
    const mbox = (v, l, sub) => `<div style="border:1px solid #e2e8ee;border-top:3px solid #2E77C2;padding:10px 12px"><div style="font:800 36px/1 ${AR};color:#142B44">${v}</div><div style="font:600 8.5px/1.3 ${AR};letter-spacing:.07em;color:#64768a;margin-top:6px">${l}</div>${sub ? `<div style="font:600 9px/1 ${PM};color:#1F9D57;margin-top:4px">${sub}</div>` : ""}</div>`;

    return `<!doctype html><html><head><meta charset="utf-8"><title>Vault Weekly Report</title>
<link href="https://fonts.googleapis.com/css2?family=Archivo:wght@500;700;800;900&family=IBM+Plex+Mono:wght@500;600;700&family=Libre+Franklin:wght@400;600;700&display=swap" rel="stylesheet">
<style>
  @page { size: Letter; margin: 0.4in; }
  * { box-sizing: border-box; margin: 0; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
  body { font-family: ${LF}; color: #12263a; font-size: 11px; }
  table { width: 100%; border-collapse: collapse; }
  th { text-align: right; font: 700 7.5px/1.2 ${AR}; letter-spacing: .07em; text-transform: uppercase; color: #64768a; padding: 3px 5px; border-bottom: 1.5px solid #0e3a5c; }
  th:first-child, td:first-child { text-align: left; }
  td { padding: 3.5px 5px; border-bottom: 1px solid #e8edf2; font: 500 10px/1.35 ${PM}; text-align: right; color: #12263a; }
  td:first-child { font-family: ${LF}; font-weight: 600; }
  td.top { color: #0d7a4f; font-weight: 700; background: #e9f7f0 !important; }
</style></head><body>
  <div style="background:linear-gradient(180deg,#2E77C2,#1C5C9E) !important;color:#fff;padding:13px 16px;display:flex;justify-content:space-between;align-items:center;border-radius:2px">
    <div style="display:flex;align-items:center;gap:11px">
      <svg width="28" height="28" viewBox="0 0 40 40" fill="none"><path d="M6 7 L20 34 L34 7" stroke="#fff" stroke-width="5" stroke-linejoin="round" stroke-linecap="round"/><path d="M16.5 13.5v-2.2a3.5 3.5 0 0 1 7 0v2.2" stroke="#fff" stroke-width="2" stroke-linecap="round"/><rect x="15" y="13.5" width="10" height="7.5" rx="1.6" fill="#fff"/><circle cx="20" cy="17" r="1.3" fill="#1C5C9E"/></svg>
      <div><span style="font:800 19px/1 ${AR}">Vault</span><span style="font:900 19px/1 ${AR};margin-left:8px">\u00b7 WEEKLY REPORT</span>
        <div style="font:500 10px/1 ${PM};letter-spacing:.08em;color:#DCEBFA;margin-top:5px">${esc(moduleLabel).toUpperCase()} \u00b7 WEEK OF ${fmt(wk).toUpperCase()} \u2013 ${fmt(wkEnd).toUpperCase()}, ${year}</div></div>
    </div>
    <div style="text-align:right;font:500 9.5px/1.6 ${PM};color:#DCEBFA">GENERATED \u00b7 ${new Date().toLocaleDateString("en-US", { month: "short", day: "2-digit", year: "numeric" }).toUpperCase()}<br>DIRECTOR \u00b7 ${esc(generatedBy).toUpperCase()}</div>
  </div>

  ${kick("THIS WEEK \u2014 KEY METRICS")}
  <div style="display:grid;grid-template-columns:repeat(4,1fr);gap:10px">
    ${mbox(wkCC, "CONFERENCE CALLS")}
    ${mbox(wkLOI, "SIGNED LOIs")}
    ${mbox(offersWk.length, "NEW OFFERS")}
    ${mbox(ncWk.length, "NEW CLIENTS")}
  </div>
  <div style="display:flex;gap:16px;font:500 9.5px/1 ${PM};color:#5E6E82;margin-top:7px;flex-wrap:wrap">
    ${[["BUYER INT.", sum("leads"), WEEKLY_GOALS.leads], ["LISTS", sum("ntps"), WEEKLY_GOALS.ntps], ["MAILINGS", sum("mailings"), WEEKLY_GOALS.mailings], ["CALLS", sum("calls"), WEEKLY_GOALS.calls]].map(([l, v, g]) => `<span>${l} <b style="color:${paceColor(v, g) || "#142B44"}">${v}</b><span style="color:#A8B4C2">/${g}</span></span>`).join("")}
    <span>WEEKLY FEES <b style="color:#1F9D57">${moneyK(feesWk)}</b></span>
  </div>

  <div style="display:grid;grid-template-columns:1.05fr 1fr;gap:16px">
    <div>
      ${kick("ACCOMPLISHED THIS WEEK")}
      ${acc.length ? acc.slice(0, 6).map(a => `<div style="font:400 10.5px/1.5 ${LF};padding:2.5px 0;border-bottom:1px solid #eef2f6">\u2022&nbsp; ${a}</div>`).join("") : `<div style="font:400 10.5px/1.5 ${LF};color:#8896a5">Week in progress \u2014 activity accrues through Sunday.</div>`}
      ${kick("NEW SIGNINGS &amp; DEALS")}
      ${signRows.length ? `<table><tr><th>Company</th><th style="text-align:left">Buyer</th><th>Stage</th><th>Fee/Amt</th></tr>${signRows.slice(0, 7).map(r => `<tr><td>${esc(r.co)}</td><td style="text-align:left;font-family:${LF};font-weight:400;color:#5f7183">${esc(r.buyer)}</td><td><span style="font:700 8px/1 ${AR};letter-spacing:.05em;padding:2px 7px;background:${r.stage === "Closed" ? "#14603A" : "#1C5C9E"} !important;color:#fff">${esc(String(r.stage).toUpperCase())}</span></td><td>${esc(r.amt)}</td></tr>`).join("")}</table>` : `<div style="font:400 10.5px/1.5 ${LF};color:#8896a5">None recorded this week yet.</div>`}
      ${kick("RESEARCH PLAN PROGRESS")}
      ${planRows.length ? `<table><tr><th>Team</th><th>Research</th><th>Lists</th><th>Mailings</th></tr>${planRows.map(p => `<tr><td>${esc(p.label)}</td><td>${p.r.d}/${p.r.t}</td><td>${p.a.d}/${p.a.t}</td><td>${p.m.d}/${p.m.t}</td></tr>`).join("")}</table>` : `<div style="font:400 10.5px/1.5 ${LF};color:#8896a5">No plan rows this week.</div>`}
    </div>
    <div>
      ${kick("TEAM ACTIVITY")}
      <table><tr><th>Team</th><th>Calls</th><th>CC</th><th>Leads</th><th>Off</th><th>Fees</th></tr>
        ${teamRows2.map(([t, v]) => `<tr><td>${esc(t)}</td><td>${v.calls}</td><td>${v.confCalls}</td><td>${v.leads}</td><td>${v.offers}</td><td>${v.fees ? moneyK(v.fees) : "\u2014"}</td></tr>`).join("")}
        <tr><td style="font-weight:800">TOTAL</td><td style="font-weight:700">${tTot.calls}</td><td style="font-weight:700">${tTot.confCalls}</td><td style="font-weight:700">${tTot.leads}</td><td style="font-weight:700">${tTot.offers}</td><td style="font-weight:700">${tTot.fees ? moneyK(tTot.fees) : "\u2014"}</td></tr></table>
      ${kick("LEADERBOARD", "individuals \u00b7 module lead excluded")}
      ${board.length ? `<table><tr><th>Person</th>${LB_COLS.map(([, l]) => `<th>${l}</th>`).join("")}</tr>${board.map(p => `<tr><td>${esc((p.personName || p.personId).split(" ")[0])}</td>${LB_COLS.map(([k]) => `<td${(p[k] || 0) > 0 && p[k] === colMax[k] ? ' class="top"' : ""}>${p[k] || 0}</td>`).join("")}</tr>`).join("")}</table>` : `<div style="font:400 10.5px/1.5 ${LF};color:#8896a5">No individual activity yet this week.</div>`}
    </div>
  </div>

  <div style="background:#142B44 !important;color:#fff;padding:7px 14px;margin-top:13px;font:800 11px/1 ${AR};letter-spacing:.15em">YEAR-TO-DATE \u00b7 ${year}</div>
  ${kick("ACTIVE PIPELINE \u2014 RIGHT NOW", (pipeline || []).length + " targets \u00b7 " + esc(moduleLabel))}
  <div style="display:grid;grid-template-columns:repeat(7,1fr);gap:8px">
    ${buckets.map(([l, v]) => `<div style="border:1px solid #e2e8ee;padding:8px 6px;text-align:center"><div style="font:800 19px/1 ${AR};color:#142B44">${v}</div><div style="font:700 7px/1.2 ${AR};letter-spacing:.05em;color:#64768a;margin-top:4px">${esc(l).toUpperCase()}</div></div>`).join("")}
  </div>
  ${kick("YTD CONVERSION FUNNEL")}
  <div style="display:grid;grid-template-columns:repeat(7,1fr);gap:8px">
    ${fun.map(([l, v, g], i) => { const bg = g != null ? paceColor(v, g) : (i === fun.length - 1 ? "#14603A" : "#1C5C9E"); return `<div style="background:${bg} !important;padding:9px 4px;text-align:center"><div style="font:800 20px/1 ${AR};color:#fff">${v.toLocaleString()}</div><div style="font:700 7px/1.2 ${AR};letter-spacing:.05em;color:rgba(255,255,255,.72);margin-top:5px">${esc(l).toUpperCase()}</div>${g != null ? `<div style="font:600 7px/1 ${PM};color:rgba(255,255,255,.6);margin-top:3px">GOAL ${g.toLocaleString()}</div>` : ""}</div>`; }).join("")}
  </div>
  <div style="display:flex;gap:12px;margin-top:5px;font:600 8px/1 ${PM};color:#8896a5"><span><span style="display:inline-block;width:8px;height:8px;background:#14603A !important;vertical-align:-1px"></span> ON PACE</span><span><span style="display:inline-block;width:8px;height:8px;background:#8A5A12 !important;vertical-align:-1px"></span> 70\u201399%</span><span><span style="display:inline-block;width:8px;height:8px;background:#7C2438 !important;vertical-align:-1px"></span> BEHIND</span><span style="margin-left:auto">GOALS PRORATED \u00d7 ${wksElapsed} WKS</span></div>
  <div style="display:grid;grid-template-columns:1fr 1fr;gap:16px;margin-top:4px">
    <div>
      ${kick("EFFICIENCY")}
      <div style="display:grid;grid-template-columns:repeat(3,1fr);gap:8px">
        ${eff.map(([l, v]) => `<div style="border:1px solid #e2e8ee;padding:8px 10px"><div style="font:800 18px/1 ${AR};color:#1F9D57">${v}</div><div style="font:700 7.5px/1.2 ${AR};letter-spacing:.06em;color:#64768a;margin-top:4px">${esc(l).toUpperCase()}</div></div>`).join("")}
      </div>
      ${kick("DEAL FEES vs BHAG \u00b7 " + year)}
      ${feeRows.map(([st, v]) => { const tgt = BHAG_FEES[st]; const p = tgt ? Math.min(100, Math.round(v / tgt * 100)) : 0; return `<div style="display:flex;align-items:center;gap:8px;margin:5px 0"><span style="width:78px;font:600 9px/1 ${AR};letter-spacing:.05em;color:#5E6E82;flex-shrink:0">${esc(st).toUpperCase()}</span><span style="flex:1;height:11px;background:#E8EDF2 !important;border-radius:2px;overflow:hidden"><span style="display:block;height:100%;width:${p}%;background:linear-gradient(90deg,#2E77C2,#1F9D57) !important"></span></span><span style="width:118px;text-align:right;font:700 9px/1.3 ${PM};color:#142B44">${moneyK(v)} / ${moneyK(tgt)} \u00b7 ${tgt ? Math.round(v / tgt * 100) : 0}%</span></div>`; }).join("")}
      <div style="background:#14603A !important;color:#fff;padding:6px 12px;margin-top:7px;display:flex;justify-content:space-between;font:700 10px/1 ${PM}"><span>MODULE TOTAL YTD \u00b7 vs BHAG ${moneyK(BHAG_MODULE)}</span><span>${moneyK(feeTotal)} \u00b7 ${Math.round(feeTotal / BHAG_MODULE * 100)}%</span></div>
    </div>
    <div>
      ${kick("CUMULATIVE FEES \u2014 " + year)}
      ${ramp}
    </div>
  </div>
  <div style="margin-top:11px;display:flex;justify-content:space-between;font:500 8px/1 ${PM};color:#8896a5"><span>GENERATED BY VAULT \u00b7 CONFIDENTIAL</span><span>${new Date().toLocaleString("en-US")}</span></div>
</body></html>`;
  }

  async function open() {
    const A = window.VaultAPI;
    const wk = mondayOf(new Date());
    const jan1 = wk.slice(0, 4) + "-01-01";
    const [pipeline, goals, plans, newClients, individuals, ytdRows] = await Promise.all([
      A.getPipelineRows(["bscott"], null, null, null).catch(() => []),
      A.listResearchGoals("bscott", wk).catch(() => []),
      A.listResearchPlans("bscott").catch(() => []),
      A.listNewClients().catch(() => []),
      A.getModuleIndividuals("bscott", wk, wk).catch(() => []),
      A.getOverviewTotals(["bscott"], null, null, jan1, wk, null).catch(() => null),
    ]);
    const ytd = Array.isArray(ytdRows) ? ytdRows[0] : ytdRows;
    const html = _build({
      wk, moduleLabel: "Scott Module", generatedBy: "Brian Scott",
      pipeline, goals, plans, newClients, individuals, ytd,
      offers: window.HARVEY_OFFERS || [], closed: window.HARVEY_CLOSED || [],
    });
    const w = window.open("", "_blank");
    if (!w) { window.VaultUI && window.VaultUI.toast("error", "Pop-up blocked \u2014 allow pop-ups for vault-harvey.com"); return; }
    w.document.write(html);
    w.document.close();
    setTimeout(() => { try { w.focus(); w.print(); } catch (e) {} }, 900); // fonts need a beat
  }

  window.WeeklyReport = { open, _build, _mondayOf: mondayOf };
})();