// ===== m7-recognition.jsx =====
// M7 · Recognition Programs, Milestones, Pass/Benefit Eligibility
// Replaces window.OrgRecognition with a deep multi-section module covering:
//   FR1.1 program configuration (milestones + rolling pass)
//   FR1.2 eligibility report (filters + scoped view)
//   FR1.3 volunteer-facing progress (visible to staff)
//   FR1.4 record award issuance (manual, immutable audit)
//   FR1.5 BULK award issuance (preview → exceptions → confirm → result)
//   FR1.6 prior-CY milestone fulfillment + Avery 5160 mailing label export

const {
  React,
  TopBar, Card, SectionHead, Btn, IconBtn, StatusChip, Avatar, Kpi, Progress,
  Field, Input, Textarea, Select, Checkbox, Toggle, Tabs, Empty,
  IconPlus, IconCheck, IconX, IconArrow, IconArrowL, IconDownload, IconUpload,
  IconAward, IconStar, IconClock, IconClipboard, IconMail, IconFilter, IconSearch,
  IconMore, IconEdit, IconShield, IconChevron, IconChevronD, IconExternal, IconReport,
  VOLUNTEERS,
} = window;
const { useState, useMemo } = React;

// ---------- shared tokens ----------
const m7r_overline = { fontSize: 11, letterSpacing: "0.12em", textTransform: "uppercase", color: "var(--fg-3)", fontWeight: 500 };
const m7r_meta = { fontSize: 11, color: "var(--fg-3)" };

// CPW recognition seed programs (configurable per tenant)
const RECOG_PROGRAMS = [
  {
    id: "rp-annual",
    name: "Annual milestone gifts",
    type: "annual",
    window: "Calendar year — Jan 1 to Dec 31, America/Denver",
    source: "Approved hours",
    audience: "All volunteer programs",
    tiers: [
      { id: "tier-10",  threshold: 10,  award: "CPW patch + thank-you note",          stock: "in stock", lead: "1 wk" },
      { id: "tier-100", threshold: 100, award: "$50 CPW shop credit + pin",           stock: "in stock", lead: "2 wk" },
      { id: "tier-500", threshold: 500, award: "Engraved nameplate + lifetime pass",  stock: "low (4)",  lead: "6 wk" },
    ],
    labels: { milestone: "Milestone gift", recipients: "Recipients", issuance: "Issuance" },
    audit: { reset: "annual", recalc: "after approved-hour correction" },
  },
  {
    id: "rp-parkpass",
    name: "State park pass benefit",
    type: "rolling",
    window: "Rolling 12 months — recalculates daily, America/Denver",
    source: "Approved hours",
    audience: "All volunteer programs (excluding staff hours)",
    tiers: [
      { id: "tier-48", threshold: 48, award: "Free state park pass (1 yr)", stock: "in stock", lead: "—", resets: "after issuance" },
    ],
    labels: { milestone: "Pass eligibility", recipients: "Recipients", issuance: "Pass issued" },
    audit: { reset: "after issuance", recalc: "nightly + after hour correction" },
  },
];

// Synthetic eligibility records — joins volunteer × tier
function buildEligibility() {
  const rows = [];
  VOLUNTEERS.forEach(v => {
    if (v.lifetimeHours == null) return;
    // annual gift eligibility (this calendar year)
    if (v.ytdHours >= 500) rows.push({ ...elig(v, "tier-500", "Annual gift · 500 hr"), ytd: v.ytdHours });
    else if (v.ytdHours >= 100) rows.push({ ...elig(v, "tier-100", "Annual gift · 100 hr"), ytd: v.ytdHours });
    else if (v.ytdHours >= 10)  rows.push({ ...elig(v, "tier-10",  "Annual gift · 10 hr"),  ytd: v.ytdHours });
    // rolling park pass
    if (v.last12moHours >= 48) rows.push({ ...elig(v, "tier-48", "Park pass · 48 hr rolling"), ytd: v.last12moHours, isPass: true });
  });
  return rows;
}
function elig(v, tierId, milestone) {
  return {
    key: v.id + "_" + tierId,
    volunteer: v,
    tierId,
    milestone,
    qualifyingHours: tierId === "tier-48" ? v.last12moHours : v.ytdHours,
    dateRange: tierId === "tier-48" ? "May 23, 2025 – May 23, 2026" : "Jan 1 – May 23, 2026",
    site: v.site, program: v.program, role: v.role, region: "Northeast",
    preference: pref(v.id, tierId),
    issued: false,
  };
}
function pref(vid, tierId) {
  // mock the volunteer's stated preference at last sign-up
  if (vid === "v-arenas") return "Send to: 814 Lemay Ave, Fort Collins CO 80524";
  if (vid === "v-okonkwo") return tierId === "tier-48" ? "Email digital pass" : "Send to: 47 Pine Ridge Rd, Boulder CO 80302";
  if (vid === "v-mendez") return "Pickup at Lake Pueblo SP visitor center";
  if (vid === "v-walsh") return "Opted out — donate to general fund";
  if (vid === "v-chen") return "Send to: 1409 16th St #4, Denver CO 80202";
  if (vid === "v-kowalski") return "Send to: 89 Aspen Ct, Estes Park CO 80517";
  if (vid === "v-tovar") return "Send to: 312 Garfield Ave, Loveland CO 80537";
  if (vid === "v-nguyen") return "Send to: 8801 Federal Blvd, Westminster CO 80031";
  return "Send to mailing address on file";
}

// ====================== ROOT ======================
const OrgRecognition = ({ go }) => {
  const [tab, setTab] = useState("overview");
  const [bulkOpen, setBulkOpen] = useState(false);
  const [bulkContext, setBulkContext] = useState(null); // {program, tierId, rows}

  // role from app tweaks — drives scoped view; fallback is universal
  const role = (document.body.dataset.role || "Universal admin");

  const eligibility = useMemo(buildEligibility, []);

  return (
    <>
      <TopBar
        title="Recognition"
        subtitle="3 programs · 14 milestones triggered this cycle · 4 ready to issue · 38 mailing labels owed"
        primary={<Btn icon={IconAward} onClick={() => { setTab("eligibility"); }}>Issue recognition</Btn>}
        secondary={<Btn kind="secondary" icon={IconDownload} onClick={() => { setTab("priorcy"); }}>Prior-CY fulfillment</Btn>}
      />
      <div style={{ flex: 1, overflow: "auto", padding: "20px 32px 56px" }}>
        <Tabs active={tab} onChange={setTab} tabs={[
          { id: "overview",    label: "Overview" },
          { id: "eligibility", label: "Eligibility report", count: eligibility.length },
          { id: "issuance",    label: "Issuance & audit", count: 412 },
          { id: "programs",    label: "Programs" },
          { id: "priorcy",     label: "Prior-CY fulfillment" },
        ]} />

        {tab === "overview"    && <Overview eligibility={eligibility} go={go} setTab={setTab} />}
        {tab === "eligibility" && <Eligibility rows={eligibility} go={go} role={role}
                                    onBulk={(ctx) => { setBulkContext(ctx); setBulkOpen(true); }} />}
        {tab === "issuance"    && <IssuanceLog />}
        {tab === "programs"    && <Programs />}
        {tab === "priorcy"     && <PriorCY rows={eligibility} />}
      </div>

      {bulkOpen && <BulkIssuanceFlow ctx={bulkContext} onClose={() => setBulkOpen(false)} />}
    </>
  );
};

// ====================== OVERVIEW ======================
const Overview = ({ eligibility, go, setTab }) => {
  const annualReady = eligibility.filter(r => r.tierId !== "tier-48");
  const passReady = eligibility.filter(r => r.tierId === "tier-48");
  const annual500 = annualReady.filter(r => r.tierId === "tier-500");
  const annual100 = annualReady.filter(r => r.tierId === "tier-100");
  const annual10  = annualReady.filter(r => r.tierId === "tier-10");

  return (
    <>
      <div style={{ display: "grid", gridTemplateColumns: "repeat(4, 1fr)", gap: 14, marginBottom: 24 }}>
        <Kpi label="Eligible this cycle" value={String(eligibility.length)} delta="across 2 programs" tone="neutral" icon={IconAward} />
        <Kpi label="Annual gifts ready" value={String(annualReady.length)} delta="needs fulfillment" tone="up" icon={IconClipboard} />
        <Kpi label="Park passes ready" value={String(passReady.length)} delta="rolling 12-mo · 48 hr" tone="up" icon={IconStar} />
        <Kpi label="Service value YTD" value="$1.24M" delta="at $33.49/hr" tone="up" icon={IconClock} />
      </div>

      <SectionHead title="Programs at a glance" action={<button onClick={() => setTab("programs")} style={linkBtn}>Configure <IconArrow size={13} /></button>} />
      <div style={{ display: "grid", gridTemplateColumns: "repeat(2, 1fr)", gap: 14, marginBottom: 24 }}>
        {RECOG_PROGRAMS.map(p => (
          <Card key={p.id}>
            <div style={{ display: "flex", justifyContent: "space-between", alignItems: "baseline", marginBottom: 8 }}>
              <div>
                <div style={{ ...m7r_overline, marginBottom: 6 }}>{p.type === "annual" ? "Annual milestone" : "Rolling benefit"}</div>
                <div style={{ fontSize: 17, fontWeight: 500, color: "var(--ink)" }}>{p.name}</div>
              </div>
              <StatusChip status="active" size="sm" label="Active" />
            </div>
            <div style={{ fontSize: 12, color: "var(--fg-2)", marginBottom: 14, lineHeight: 1.5 }}>{p.window}</div>
            <div style={{ display: "flex", flexDirection: "column", gap: 8 }}>
              {p.tiers.map(t => {
                const count = eligibility.filter(e => e.tierId === t.id).length;
                return (
                  <div key={t.id} style={{ display: "grid", gridTemplateColumns: "70px 1fr auto auto", gap: 10, alignItems: "center", padding: "10px 12px", background: "var(--paper)", borderRadius: 10, border: "1px solid var(--border-soft)" }}>
                    <div style={{ fontFamily: "var(--font-display)", fontSize: 22, color: "var(--ink)", fontVariantNumeric: "tabular-nums", lineHeight: 1 }}>{t.threshold}<span style={{ fontSize: 11, color: "var(--fg-3)", fontFamily: "var(--font-sans)" }}> hr</span></div>
                    <div>
                      <div style={{ fontSize: 13, color: "var(--ink)" }}>{t.award}</div>
                      <div style={{ ...m7r_meta, marginTop: 2 }}>{t.stock} · {t.lead} lead time{t.resets ? " · resets " + t.resets : ""}</div>
                    </div>
                    <span style={{ fontSize: 11, padding: "3px 9px", borderRadius: 999, background: count > 0 ? "var(--coral-100)" : "var(--paper-deep)", color: count > 0 ? "var(--coral-700)" : "var(--fg-3)", fontWeight: 500, fontVariantNumeric: "tabular-nums" }}>{count} ready</span>
                  </div>
                );
              })}
            </div>
          </Card>
        ))}
      </div>

      <SectionHead title="Recent activity" action={<button onClick={() => setTab("issuance")} style={linkBtn}>Issuance log <IconArrow size={13} /></button>} />
      <Card padded={false} style={{ marginBottom: 24 }}>
        {RECENT_ACTIVITY.slice(0, 4).map((a, i) => (
          <ActivityRow key={i} a={a} last={i === 3} />
        ))}
      </Card>

      <div style={{ display: "grid", gridTemplateColumns: "repeat(3, 1fr)", gap: 14 }}>
        <ShortcutCard title="Run prior-CY eligibility report"
          desc="Calendar-year aggregation with mailing fields, award preference, and Avery 5160 labels."
          cta="Open" onClick={() => setTab("priorcy")} icon={IconReport} />
        <ShortcutCard title="Bulk-issue 100-hr gifts"
          desc="6 volunteers ready · 1 opt-out · 1 already issued"
          cta="Start" onClick={() => setTab("eligibility")} icon={IconAward} />
        <ShortcutCard title="Volunteer-facing progress"
          desc="Service history shows live progress to each milestone — preview the volunteer view."
          cta="Preview" onClick={() => go("v-home")} icon={IconStar} />
      </div>
    </>
  );
};

const ShortcutCard = ({ title, desc, cta, onClick, icon: Icon }) => (
  <Card style={{ cursor: "pointer" }} onClick={onClick}>
    <div style={{ display: "flex", gap: 10, marginBottom: 10 }}>
      <div style={{ width: 32, height: 32, borderRadius: 8, background: "var(--coral-100)", color: "var(--coral-700)", display: "flex", alignItems: "center", justifyContent: "center" }}>
        <Icon size={16} />
      </div>
      <div style={{ flex: 1 }}>
        <div style={{ fontSize: 13, fontWeight: 500, color: "var(--ink)" }}>{title}</div>
      </div>
    </div>
    <div style={{ fontSize: 12, color: "var(--fg-2)", lineHeight: 1.5, marginBottom: 14 }}>{desc}</div>
    <Btn size="sm" kind="secondary" iconRight={IconArrow}>{cta}</Btn>
  </Card>
);

const linkBtn = { background: "transparent", border: "none", color: "var(--coral-700)", fontSize: 12, fontWeight: 500, cursor: "pointer", display: "inline-flex", alignItems: "center", gap: 4, padding: 0 };

// ====================== ELIGIBILITY REPORT ======================
const Eligibility = ({ rows, go, role, onBulk }) => {
  const isScoped = role && role.toLowerCase().includes("basic");
  const [program, setProgram] = useState("all");
  const [tier, setTier] = useState("all");
  const [pref, setPref] = useState("all");
  const [site, setSite] = useState("all");
  const [search, setSearch] = useState("");
  const [picked, setPicked] = useState(new Set());

  const filtered = rows.filter(r => {
    if (program !== "all") {
      if (program === "annual" && r.tierId === "tier-48") return false;
      if (program === "parkpass" && r.tierId !== "tier-48") return false;
    }
    if (tier !== "all" && r.tierId !== tier) return false;
    if (pref === "optout" && !/opt(ed)? out/i.test(r.preference)) return false;
    if (pref === "wantsmail" && !/Send to:/i.test(r.preference)) return false;
    if (site !== "all" && r.site !== site) return false;
    if (search && !r.volunteer.name.toLowerCase().includes(search.toLowerCase())) return false;
    if (isScoped && r.site && r.site.indexOf("Northeast") === -1 && r.site !== "Boyd Lake SP" && r.site !== "Cherry Creek SP") return false;
    return true;
  });

  const sites = Array.from(new Set(rows.map(r => r.site))).filter(Boolean);

  const togglePick = (key) => {
    const s = new Set(picked);
    if (s.has(key)) s.delete(key); else s.add(key);
    setPicked(s);
  };
  const allSelected = filtered.length > 0 && filtered.every(r => picked.has(r.key));
  const toggleAll = () => {
    if (allSelected) setPicked(new Set());
    else setPicked(new Set(filtered.map(r => r.key)));
  };

  const selectedRows = filtered.filter(r => picked.has(r.key));
  const canBulk = selectedRows.length > 0;

  return (
    <>
      {isScoped && (
        <ScopedBanner role={role}
          msg="You're seeing only volunteers within Northeast region. Hide rule: scope check on participation site + program." />
      )}

      {/* Filter bar */}
      <Card style={{ padding: 14, marginBottom: 14 }}>
        <div style={{ display: "grid", gridTemplateColumns: "minmax(180px, 1.4fr) 160px 160px 220px 160px auto", gap: 10, alignItems: "end" }}>
          <Field label="Search volunteer">
            <Input placeholder="Name…" value={search} onChange={(e) => setSearch(e.target.value)} />
          </Field>
          <Field label="Program">
            <Select value={program} onChange={(e) => setProgram(e.target.value)}
              options={[
                { value: "all", label: "All programs" },
                { value: "annual", label: "Annual gifts" },
                { value: "parkpass", label: "Park pass (rolling)" },
              ]} />
          </Field>
          <Field label="Milestone">
            <Select value={tier} onChange={(e) => setTier(e.target.value)}
              options={[
                { value: "all", label: "All milestones" },
                { value: "tier-10",  label: "10 hr (annual)" },
                { value: "tier-100", label: "100 hr (annual)" },
                { value: "tier-500", label: "500 hr (annual)" },
                { value: "tier-48",  label: "48 hr (park pass)" },
              ]} />
          </Field>
          <Field label="Site">
            <Select value={site} onChange={(e) => setSite(e.target.value)}
              options={[{ value: "all", label: "All sites" }, ...sites.map(s => ({ value: s, label: s }))]} />
          </Field>
          <Field label="Award preference">
            <Select value={pref} onChange={(e) => setPref(e.target.value)}
              options={[
                { value: "all", label: "Any preference" },
                { value: "wantsmail", label: "Wants mailed" },
                { value: "optout", label: "Opted out" },
              ]} />
          </Field>
          <div style={{ display: "flex", gap: 8, justifyContent: "flex-end" }}>
            <Btn kind="ghost" size="sm" onClick={() => { setProgram("all"); setTier("all"); setPref("all"); setSite("all"); setSearch(""); }}>Reset</Btn>
            <Btn kind="secondary" size="sm" icon={IconDownload}>Export</Btn>
          </div>
        </div>
        <div style={{ display: "flex", gap: 8, flexWrap: "wrap", marginTop: 12, paddingTop: 12, borderTop: "1px solid var(--border-soft)" }}>
          <FilterChip label={`${filtered.length} of ${rows.length} matching`} tone="info" />
          {filtered.length !== rows.length && <FilterChip label="Hours through May 23, 2026" />}
          {isScoped && <FilterChip label="Scoped to Northeast region" tone="warn" />}
          <FilterChip label="Excludes hours awaiting audit signoff" />
          <FilterChip label="Excludes staff hours" />
        </div>
      </Card>

      {/* Bulk action bar */}
      {canBulk && (
        <div style={{
          display: "flex", justifyContent: "space-between", alignItems: "center",
          padding: "12px 16px", marginBottom: 14, borderRadius: 12,
          background: "var(--ink)", color: "var(--paper)",
        }}>
          <div>
            <div style={{ fontSize: 13, fontWeight: 500 }}>{selectedRows.length} selected for issuance</div>
            <div style={{ fontSize: 11, opacity: 0.7 }}>
              Will go through preview + exception check before any award is recorded.
            </div>
          </div>
          <div style={{ display: "flex", gap: 8 }}>
            <Btn kind="ghost" size="sm" onClick={() => setPicked(new Set())}>Clear</Btn>
            <Btn kind="secondary" size="sm" icon={IconMail}>Send notes only</Btn>
            <Btn size="sm" icon={IconAward} onClick={() => onBulk({ rows: selectedRows })}>Bulk issue ({selectedRows.length})</Btn>
          </div>
        </div>
      )}

      {/* Table */}
      <Card padded={false} style={{ overflowX: "auto" }}>
        <div style={{
          display: "grid",
          gridTemplateColumns: "28px minmax(200px, 2fr) 130px 110px 110px 140px minmax(200px, 1.4fr) 100px 36px",
          gap: 12, padding: "12px 18px", fontSize: 11, letterSpacing: "0.1em",
          textTransform: "uppercase", color: "var(--fg-3)", borderBottom: "1px solid var(--border)",
          alignItems: "center", minWidth: 1100,
        }}>
          <Checkbox checked={allSelected} onChange={toggleAll} aria-label="Select all" />
          <span>Volunteer</span>
          <span>Milestone</span>
          <span style={{ textAlign: "right" }}>Qualifying hrs</span>
          <span>Site</span>
          <span>Program</span>
          <span>Preference</span>
          <span>Status</span>
          <span />
        </div>
        {filtered.length === 0 && (
          <div style={{ padding: 24 }}>
            <Empty title="No volunteers match these filters" body="Try widening the milestone or date range." icon={IconAward} />
          </div>
        )}
        {filtered.map((r, i) => (
          <ElRow key={r.key} r={r} picked={picked.has(r.key)} onPick={() => togglePick(r.key)} last={i === filtered.length - 1} go={go} />
        ))}
      </Card>
    </>
  );
};

const ElRow = ({ r, picked, onPick, last, go }) => {
  const v = r.volunteer;
  const optedOut = /opt(ed)? out/i.test(r.preference);
  const tierLabel = r.tierId === "tier-48" ? "Park pass · 48 hr" :
                    r.tierId === "tier-10" ? "Annual · 10 hr" :
                    r.tierId === "tier-100" ? "Annual · 100 hr" : "Annual · 500 hr";
  return (
    <div style={{
      display: "grid",
      gridTemplateColumns: "28px minmax(200px, 2fr) 130px 110px 110px 140px minmax(200px, 1.4fr) 100px 36px",
      gap: 12, padding: "14px 18px", alignItems: "center",
      borderBottom: last ? "none" : "1px solid var(--border-soft)",
      background: picked ? "var(--coral-50)" : "transparent",
      minWidth: 1100,
    }}>
      <Checkbox checked={picked} onChange={onPick} />
      <div onClick={() => go("volunteer/" + v.id)} style={{ display: "flex", gap: 12, alignItems: "center", cursor: "pointer", minWidth: 0 }}>
        <Avatar {...v} />
        <div style={{ minWidth: 0 }}>
          <div style={{ fontSize: 13, fontWeight: 500, color: "var(--ink)", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{v.name}</div>
          <div style={{ ...m7r_meta }}>{v.role} · joined {v.joined}</div>
        </div>
      </div>
      <div>
        <div style={{ fontSize: 12, color: "var(--ink)" }}>{tierLabel}</div>
        <div style={{ ...m7r_meta }}>{r.dateRange}</div>
      </div>
      <div style={{ textAlign: "right", fontVariantNumeric: "tabular-nums" }}>
        <div style={{ fontFamily: "var(--font-display)", fontSize: 20, color: "var(--ink)", lineHeight: 1 }}>{r.qualifyingHours}</div>
        <div style={{ ...m7r_meta, marginTop: 2 }}>hours</div>
      </div>
      <div style={{ fontSize: 12, color: "var(--fg-2)" }}>{v.site}</div>
      <div style={{ fontSize: 12, color: "var(--fg-2)" }}>{v.program}</div>
      <div style={{ fontSize: 12, color: optedOut ? "var(--crimson-600)" : "var(--fg-1)", lineHeight: 1.4 }}>{r.preference}</div>
      <StatusChip status={optedOut ? "expired" : "confirmed"} size="sm" label={optedOut ? "Opted out" : "Ready"} />
      <IconBtn icon={IconMore} size={28} aria-label="More" />
    </div>
  );
};

const FilterChip = ({ label, tone }) => {
  const bg = tone === "info" ? "var(--iris-100)" : tone === "warn" ? "var(--amber-100)" : "var(--paper-deep)";
  const fg = tone === "info" ? "var(--iris-600)" : tone === "warn" ? "var(--amber-600)" : "var(--fg-1)";
  return <span style={{ fontSize: 11, padding: "4px 10px", borderRadius: 999, background: bg, color: fg, fontWeight: 500, whiteSpace: "nowrap" }}>{label}</span>;
};

const ScopedBanner = ({ role, msg }) => (
  <div style={{ display: "flex", gap: 12, padding: "12px 16px", marginBottom: 14, borderRadius: 10, background: "var(--iris-100)", color: "var(--iris-600)", border: "1px solid rgba(67,86,161,0.2)" }}>
    <IconShield size={18} />
    <div style={{ fontSize: 12, color: "var(--ink-soft)" }}>
      <span style={{ fontWeight: 500 }}>{role} · scoped view.</span> <span style={{ color: "var(--fg-2)" }}>{msg}</span>
    </div>
  </div>
);

// ====================== BULK ISSUANCE FLOW ======================
const BulkIssuanceFlow = ({ ctx, onClose }) => {
  const [step, setStep] = useState(1);
  const [rows, setRows] = useState(() => (ctx?.rows || []).map(r => ({ ...r, include: !/opt(ed)? out/i.test(r.preference) })));
  const [issueDate, setIssueDate] = useState(new Date().toISOString().slice(0, 10));
  const [admin, setAdmin] = useState("Priya Sandoval");
  const [notes, setNotes] = useState("Spring batch — printed labels picked up at Denver office Fri.");
  const [committed, setCommitted] = useState(false);

  const exceptions = useMemo(() => buildExceptions(rows), [rows]);
  const willIssue = rows.filter(r => r.include);

  return (
    <div style={overlay} role="dialog" aria-modal="true">
      <div style={drawer}>
        <div style={drawerHead}>
          <div>
            <div style={{ ...m7r_overline }}>Bulk award issuance · {willIssue.length} record{willIssue.length === 1 ? "" : "s"}</div>
            <div style={{ fontSize: 19, fontWeight: 500, color: "var(--ink)", marginTop: 4 }}>
              {step === 1 ? "Step 1 · Review selection"
              : step === 2 ? "Step 2 · Exceptions & overrides"
              : step === 3 ? "Step 3 · Confirm issuance"
              : "Result"}
            </div>
          </div>
          <IconBtn icon={IconX} size={32} onClick={onClose} aria-label="Close" />
        </div>

        {/* Step indicator */}
        <div style={{ display: "flex", gap: 4, padding: "12px 24px 0", alignItems: "center" }}>
          {[1, 2, 3, 4].map(i => (
            <div key={i} style={{ flex: 1, height: 3, borderRadius: 2,
              background: i <= step ? "var(--coral-600)" : "var(--paper-deep)" }} />
          ))}
        </div>

        <div style={{ flex: 1, overflow: "auto", padding: 24 }}>
          {step === 1 && <BulkStep1 rows={rows} setRows={setRows} />}
          {step === 2 && <BulkStep2 rows={rows} setRows={setRows} exceptions={exceptions} />}
          {step === 3 && <BulkStep3 rows={willIssue} issueDate={issueDate} setIssueDate={setIssueDate} admin={admin} setAdmin={setAdmin} notes={notes} setNotes={setNotes} />}
          {step === 4 && <BulkStep4 rows={willIssue} issueDate={issueDate} admin={admin} onClose={onClose} />}
        </div>

        <div style={drawerFoot}>
          {step > 1 && step < 4 && <Btn kind="ghost" onClick={() => setStep(step - 1)} icon={IconArrowL}>Back</Btn>}
          <div style={{ marginLeft: "auto", display: "flex", gap: 8 }}>
            {step < 3 && <Btn onClick={() => setStep(step + 1)} iconRight={IconArrow}>Continue ({willIssue.length})</Btn>}
            {step === 3 && (
              <Btn icon={IconCheck} onClick={() => { setCommitted(true); setStep(4); }}>
                Confirm & record issuance
              </Btn>
            )}
            {step === 4 && (
              <>
                <Btn kind="secondary" icon={IconDownload}>Export result CSV</Btn>
                <Btn icon={IconCheck} onClick={onClose}>Done</Btn>
              </>
            )}
          </div>
        </div>
      </div>
    </div>
  );
};

const overlay = { position: "fixed", inset: 0, background: "rgba(31,27,22,0.45)", backdropFilter: "blur(4px)", zIndex: 80, display: "flex", justifyContent: "flex-end" };
const drawer = { width: "min(960px, 100%)", height: "100%", background: "var(--paper)", display: "flex", flexDirection: "column", boxShadow: "var(--shadow-lg)" };
const drawerHead = { padding: "20px 24px 16px", display: "flex", justifyContent: "space-between", alignItems: "start", gap: 14, borderBottom: "1px solid var(--border-soft)" };
const drawerFoot = { padding: "14px 24px", borderTop: "1px solid var(--border-soft)", display: "flex", alignItems: "center", gap: 8, background: "var(--paper-soft)" };

const BulkStep1 = ({ rows, setRows }) => (
  <>
    <div style={{ ...m7r_overline, marginBottom: 8 }}>What will be issued</div>
    <p style={{ fontSize: 13, color: "var(--fg-2)", marginBottom: 18, maxWidth: 620 }}>
      Recording issuance creates an immutable audit entry per volunteer. Park-pass eligibility resets after issuance.
      Annual gifts do not reset until next calendar year.
    </p>
    <Card padded={false}>
      <div style={bulkHead}>
        <span>Volunteer</span><span>Milestone</span><span>Award</span><span>Preference</span><span style={{ textAlign: "right" }}>Hrs</span>
      </div>
      {rows.map((r, i) => (
        <div key={r.key} style={{ ...bulkRow, borderBottom: i === rows.length - 1 ? "none" : "1px solid var(--border-soft)" }}>
          <div style={{ display: "flex", gap: 10, alignItems: "center" }}>
            <Avatar {...r.volunteer} />
            <div>
              <div style={{ fontSize: 13, fontWeight: 500 }}>{r.volunteer.name}</div>
              <div style={{ ...m7r_meta }}>{r.volunteer.site}</div>
            </div>
          </div>
          <div style={{ fontSize: 12 }}>{tierName(r.tierId)}</div>
          <div style={{ fontSize: 12, color: "var(--fg-1)" }}>{awardOf(r.tierId)}</div>
          <div style={{ fontSize: 12, color: /opt/i.test(r.preference) ? "var(--crimson-600)" : "var(--fg-2)" }}>{r.preference}</div>
          <div style={{ textAlign: "right", fontVariantNumeric: "tabular-nums", fontSize: 13 }}>{r.qualifyingHours}</div>
        </div>
      ))}
    </Card>
  </>
);

const BulkStep2 = ({ rows, setRows, exceptions }) => (
  <>
    <div style={{ ...m7r_overline, marginBottom: 8 }}>{exceptions.length} exception{exceptions.length === 1 ? "" : "s"} detected</div>
    <p style={{ fontSize: 13, color: "var(--fg-2)", marginBottom: 18, maxWidth: 620 }}>
      Resolve each exception before continuing. Skipped records are logged in the audit trail with a reason code.
    </p>
    {exceptions.length === 0 && (
      <Card><Empty title="No exceptions" body="All selected records are eligible to proceed." icon={IconCheck} /></Card>
    )}
    <div style={{ display: "flex", flexDirection: "column", gap: 10 }}>
      {exceptions.map(ex => {
        const row = rows.find(r => r.key === ex.key);
        if (!row) return null;
        return (
          <Card key={ex.key}>
            <div style={{ display: "flex", justifyContent: "space-between", alignItems: "start", gap: 16 }}>
              <div style={{ display: "flex", gap: 12, flex: 1, minWidth: 0 }}>
                <div style={{ width: 8, height: 8, borderRadius: 999, background: ex.severity === "skip" ? "var(--crimson-500)" : "var(--amber-500)", marginTop: 8, flexShrink: 0 }} />
                <div style={{ flex: 1 }}>
                  <div style={{ display: "flex", gap: 8, alignItems: "baseline" }}>
                    <span style={{ fontSize: 14, fontWeight: 500 }}>{row.volunteer.name}</span>
                    <span style={{ fontSize: 11, color: "var(--fg-3)" }}>· {tierName(row.tierId)}</span>
                  </div>
                  <div style={{ fontSize: 11, textTransform: "uppercase", letterSpacing: "0.1em", color: ex.severity === "skip" ? "var(--crimson-600)" : "var(--amber-600)", fontWeight: 500, marginTop: 6 }}>{ex.code}</div>
                  <div style={{ fontSize: 13, color: "var(--fg-1)", marginTop: 6, lineHeight: 1.5 }}>{ex.message}</div>
                </div>
              </div>
              <div style={{ display: "flex", flexDirection: "column", gap: 6, alignItems: "flex-end" }}>
                <Btn size="sm" kind={row.include ? "secondary" : "primary"} onClick={() => setRows(rows.map(r => r.key === row.key ? { ...r, include: !r.include } : r))}>
                  {row.include ? "Skip this record" : "Override & include"}
                </Btn>
                <span style={{ ...m7r_meta }}>{row.include ? "Will be issued" : "Will be skipped"}</span>
              </div>
            </div>
          </Card>
        );
      })}
    </div>
  </>
);

const BulkStep3 = ({ rows, issueDate, setIssueDate, admin, setAdmin, notes, setNotes }) => (
  <>
    <div style={{ ...m7r_overline, marginBottom: 8 }}>Confirm & record</div>
    <p style={{ fontSize: 13, color: "var(--fg-2)", marginBottom: 18, maxWidth: 620 }}>
      Recording cannot be undone. Each row creates an immutable audit entry tied to the actor below. Park-pass eligibility resets for the relevant volunteers on save.
    </p>
    <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 14, marginBottom: 18 }}>
      <Field label="Issue date" required>
        <Input type="date" value={issueDate} onChange={(e) => setIssueDate(e.target.value)} />
      </Field>
      <Field label="Issuing administrator" required>
        <Select value={admin} onChange={(e) => setAdmin(e.target.value)} options={["Priya Sandoval", "Marcus Chen", "Devon Park", "Aliyah Chen"]} />
      </Field>
    </div>
    <Field label="Notes (saved with audit entry)">
      <Textarea rows={3} value={notes} onChange={(e) => setNotes(e.target.value)} />
    </Field>

    <div style={{ marginTop: 18, padding: 16, background: "var(--paper-soft)", borderRadius: 12, border: "1px solid var(--border-soft)" }}>
      <div style={{ ...m7r_overline, marginBottom: 10 }}>What happens on save</div>
      <ul style={{ margin: 0, paddingLeft: 18, fontSize: 13, color: "var(--fg-1)", lineHeight: 1.7 }}>
        <li>{rows.length} issuance record{rows.length === 1 ? "" : "s"} created (immutable)</li>
        <li>Audit log captures actor, timestamp, source filter, affected records, skip reasons</li>
        <li>Park pass tier resets eligibility window for affected volunteers</li>
        <li>Volunteer service-history shows the award on next page load</li>
        <li>Result CSV available for download from this drawer and from the issuance log</li>
      </ul>
    </div>
  </>
);

const BulkStep4 = ({ rows, issueDate, admin, onClose }) => (
  <>
    <div style={{ display: "flex", flexDirection: "column", alignItems: "center", padding: "20px 0 30px" }}>
      <div style={{ width: 56, height: 56, borderRadius: 999, background: "var(--sage-100)", color: "var(--sage-700)", display: "flex", alignItems: "center", justifyContent: "center", marginBottom: 14 }}>
        <IconCheck size={28} />
      </div>
      <div style={{ fontFamily: "var(--font-display)", fontSize: 30, color: "var(--ink)" }}>{rows.length} awards recorded</div>
      <div style={{ fontSize: 13, color: "var(--fg-2)", marginTop: 6 }}>Logged to audit trail · ref <code style={{ background: "var(--paper-deep)", padding: "2px 7px", borderRadius: 4, fontFamily: "var(--font-mono)", fontSize: 12 }}>bulk-issue-{issueDate}-{Math.random().toString(36).slice(2, 7)}</code></div>
    </div>
    <Card padded={false}>
      <div style={bulkHead}><span>Volunteer</span><span>Milestone</span><span>Award</span><span>Result</span><span style={{ textAlign: "right" }}>Audit ref</span></div>
      {rows.map((r, i) => (
        <div key={r.key} style={{ ...bulkRow, borderBottom: i === rows.length - 1 ? "none" : "1px solid var(--border-soft)" }}>
          <div style={{ display: "flex", gap: 10, alignItems: "center" }}><Avatar {...r.volunteer} /><span style={{ fontSize: 13, fontWeight: 500 }}>{r.volunteer.name}</span></div>
          <div style={{ fontSize: 12 }}>{tierName(r.tierId)}</div>
          <div style={{ fontSize: 12, color: "var(--fg-1)" }}>{awardOf(r.tierId)}</div>
          <StatusChip status="confirmed" size="sm" label="Recorded" />
          <code style={{ fontFamily: "var(--font-mono)", fontSize: 11, color: "var(--fg-3)", textAlign: "right" }}>ai-{r.volunteer.id.slice(-3)}-{Math.random().toString(36).slice(2, 6)}</code>
        </div>
      ))}
    </Card>
  </>
);

const bulkHead = { display: "grid", gridTemplateColumns: "minmax(180px, 1.4fr) 130px minmax(160px, 1.4fr) minmax(140px, 1fr) 80px", gap: 12, padding: "12px 18px", fontSize: 11, letterSpacing: "0.1em", textTransform: "uppercase", color: "var(--fg-3)", borderBottom: "1px solid var(--border)" };
const bulkRow  = { display: "grid", gridTemplateColumns: "minmax(180px, 1.4fr) 130px minmax(160px, 1.4fr) minmax(140px, 1fr) 80px", gap: 12, padding: "12px 18px", alignItems: "center" };

function buildExceptions(rows) {
  const ex = [];
  rows.forEach(r => {
    if (/opt(ed)? out/i.test(r.preference)) ex.push({ key: r.key, code: "VOLUNTEER OPTED OUT", severity: "skip", message: "Volunteer asked to donate the gift to the general fund. Override only if you've confirmed by phone." });
    if (r.volunteer.id === "v-tovar" && r.tierId === "tier-10") ex.push({ key: r.key, code: "ALREADY ISSUED THIS CYCLE", severity: "skip", message: "10-hr annual gift recorded for this volunteer on Apr 12, 2026 by Marcus Chen. Issuing again creates a duplicate audit entry." });
    if (r.volunteer.id === "v-okonkwo" && r.tierId === "tier-500") ex.push({ key: r.key, code: "MAILING ADDRESS UNVERIFIED", severity: "warn", message: "Address last verified Mar 2024 (over 12 months). Verify or use 'Hold for pickup'." });
  });
  return ex;
}
function tierName(t) { return t === "tier-48" ? "Park pass · 48 hr" : t === "tier-10" ? "Annual · 10 hr" : t === "tier-100" ? "Annual · 100 hr" : "Annual · 500 hr"; }
function awardOf(t) { return t === "tier-48" ? "Free state park pass" : t === "tier-10" ? "Patch + thank-you" : t === "tier-100" ? "$50 shop credit + pin" : "Engraved nameplate + lifetime pass"; }

// ====================== ISSUANCE LOG ======================
const RECENT_ACTIVITY = [
  { who: "Priya Sandoval", action: "Bulk-issued", count: 12, what: "10-hr annual gift", when: "Today · 9:14 am", note: "Spring batch · source: Eligibility report", ref: "bulk-issue-2026-05-23-3kf8" },
  { who: "Marcus Chen", action: "Recorded", what: "100-hr annual gift", when: "Yesterday · 4:42 pm", note: "Maya Okonkwo · audit ref ai-mko-c98", ref: "ai-mko-c98" },
  { who: "System", action: "Recalculated", what: "Park pass eligibility", when: "Today · 6:02 am", note: "Nightly recalc · 4 new eligible · 1 reset after issuance", ref: "sys-recalc-2026-05-23" },
  { who: "Priya Sandoval", action: "Recorded", what: "Park pass (48 hr)", when: "Tue · 2:18 pm", note: "Esteban Mendez · resets rolling window to today", ref: "ai-emz-1f4" },
  { who: "Marcus Chen", action: "Corrected hours", what: "Apr 19 trail crew", when: "May 21 · 11:30 am", note: "Ben Liu · 32→28 hr · triggered milestone recalculation · no tier change", ref: "hr-corr-bli-2d1" },
  { who: "Priya Sandoval", action: "Marked opted out", what: "10-hr annual gift", when: "May 19 · 10:02 am", note: "Tara Walsh · donate to general fund · honored on next issuance", ref: "pref-tw-x21" },
];

const IssuanceLog = () => {
  const [scope, setScope] = useState("all");
  return (
    <>
      <div style={{ display: "flex", gap: 8, marginBottom: 14 }}>
        <SegBtn active={scope === "all"} onClick={() => setScope("all")}>All actions</SegBtn>
        <SegBtn active={scope === "issuance"} onClick={() => setScope("issuance")}>Issuance only</SegBtn>
        <SegBtn active={scope === "corrections"} onClick={() => setScope("corrections")}>Corrections</SegBtn>
        <SegBtn active={scope === "system"} onClick={() => setScope("system")}>System</SegBtn>
        <div style={{ marginLeft: "auto", display: "flex", gap: 8 }}>
          <Btn kind="ghost" size="sm" icon={IconFilter}>More filters</Btn>
          <Btn kind="secondary" size="sm" icon={IconDownload}>Export audit log</Btn>
        </div>
      </div>
      <Card padded={false}>
        {RECENT_ACTIVITY.filter(a => {
          if (scope === "all") return true;
          if (scope === "issuance") return /issued|Recorded/.test(a.action);
          if (scope === "corrections") return /Corrected|Marked/.test(a.action);
          if (scope === "system") return a.who === "System";
        }).map((a, i, arr) => <ActivityRow key={i} a={a} last={i === arr.length - 1} />)}
      </Card>
      <div style={{ marginTop: 14, padding: "12px 16px", background: "var(--paper-soft)", borderRadius: 10, border: "1px solid var(--border-soft)", display: "flex", gap: 12, alignItems: "center" }}>
        <IconShield size={18} style={{ color: "var(--fg-3)" }} />
        <div style={{ fontSize: 12, color: "var(--fg-2)" }}>
          Audit entries are immutable. Corrections and overrides are recorded as new entries that reference the original. Export captures all visible columns plus actor IP and session ID.
        </div>
      </div>
    </>
  );
};

const SegBtn = ({ children, active, onClick }) => (
  <button onClick={onClick} style={{
    background: active ? "var(--ink)" : "transparent", color: active ? "var(--paper)" : "var(--fg-1)",
    fontSize: 12, fontWeight: 500, padding: "7px 13px", borderRadius: 999,
    border: "1px solid " + (active ? "var(--ink)" : "var(--border)"),
    cursor: "pointer", fontFamily: "inherit",
  }}>{children}</button>
);

const ActivityRow = ({ a, last }) => (
  <div style={{ display: "grid", gridTemplateColumns: "160px minmax(0, 1.4fr) minmax(0, 2fr) 140px 36px", gap: 14, padding: "14px 18px", alignItems: "start", borderBottom: last ? "none" : "1px solid var(--border-soft)", fontSize: 13 }}>
    <div>
      <div style={{ fontWeight: 500, color: "var(--ink)" }}>{a.who}</div>
      <div style={{ ...m7r_meta, marginTop: 2 }}>{a.when}</div>
    </div>
    <div>
      <div style={{ color: "var(--fg-1)" }}>{a.action}{a.count ? ` · ${a.count} records` : ""}</div>
      <div style={{ fontSize: 12, color: "var(--fg-2)" }}>{a.what}</div>
    </div>
    <div style={{ fontSize: 12, color: "var(--fg-2)", lineHeight: 1.5 }}>{a.note}</div>
    <code style={{ fontFamily: "var(--font-mono)", fontSize: 11, color: "var(--fg-3)" }}>{a.ref}</code>
    <IconBtn icon={IconMore} size={28} />
  </div>
);

// ====================== PROGRAMS (CONFIG) ======================
const Programs = () => {
  const [open, setOpen] = useState("rp-annual");
  return (
    <>
      <p style={{ fontSize: 13, color: "var(--fg-2)", marginBottom: 18, maxWidth: 720 }}>
        Recognition programs are tenant-configured: milestone rules, awards, eligibility windows, hour sources, and the labels that appear in volunteer-facing UI. CPW seeds shown below.
      </p>
      <div style={{ display: "flex", flexDirection: "column", gap: 12 }}>
        {RECOG_PROGRAMS.map(p => (
          <ProgramCard key={p.id} p={p} open={open === p.id} onToggle={() => setOpen(open === p.id ? null : p.id)} />
        ))}
        <Btn kind="secondary" icon={IconPlus} style={{ alignSelf: "flex-start" }}>Add recognition program</Btn>
      </div>
    </>
  );
};

const ProgramCard = ({ p, open, onToggle }) => (
  <Card padded={false}>
    <div onClick={onToggle} style={{ display: "grid", gridTemplateColumns: "1fr auto auto", gap: 14, padding: "16px 20px", alignItems: "center", cursor: "pointer" }}>
      <div>
        <div style={{ ...m7r_overline, marginBottom: 4 }}>{p.type === "annual" ? "Annual milestone" : "Rolling benefit"} · {p.tiers.length} tier{p.tiers.length === 1 ? "" : "s"}</div>
        <div style={{ fontSize: 16, fontWeight: 500, color: "var(--ink)" }}>{p.name}</div>
      </div>
      <StatusChip status="active" size="sm" label="Active" />
      <IconChevronD style={{ transform: open ? "rotate(180deg)" : "rotate(0)", transition: "transform 0.18s", color: "var(--fg-3)" }} />
    </div>
    {open && (
      <div style={{ borderTop: "1px solid var(--border-soft)", padding: 20, display: "grid", gridTemplateColumns: "minmax(0, 1.4fr) minmax(280px, 1fr)", gap: 24 }}>
        <div>
          <div style={{ ...m7r_overline, marginBottom: 10 }}>Milestone rules</div>
          {p.tiers.map((t, i) => (
            <div key={t.id} style={{ display: "grid", gridTemplateColumns: "100px 1fr 130px 80px", gap: 10, padding: "12px 0", borderTop: i > 0 ? "1px solid var(--border-soft)" : "none", alignItems: "center" }}>
              <Input defaultValue={t.threshold + " hr"} />
              <Input defaultValue={t.award} />
              <span style={{ fontSize: 11, color: "var(--fg-3)" }}>{t.stock}</span>
              <Btn kind="ghost" size="sm">Remove</Btn>
            </div>
          ))}
          <Btn size="sm" kind="ghost" icon={IconPlus} style={{ marginTop: 10 }}>Add tier</Btn>
        </div>
        <div>
          <div style={{ ...m7r_overline, marginBottom: 10 }}>Window & source</div>
          <Field label="Eligibility window">
            <Select defaultValue={p.type === "annual" ? "calendar" : "rolling12"}
              options={[
                { value: "calendar", label: "Calendar year (Jan 1 – Dec 31)" },
                { value: "fiscal", label: "Fiscal year (Jul 1 – Jun 30)" },
                { value: "rolling12", label: "Rolling 12 months" },
                { value: "rolling6", label: "Rolling 6 months" },
                { value: "lifetime", label: "Lifetime (cumulative)" },
              ]} />
          </Field>
          <Field label="Time zone"><Select defaultValue="America/Denver" options={["America/Denver", "America/New_York", "America/Los_Angeles"]} /></Field>
          <Field label="Hour source"><Select defaultValue="approved" options={[{ value: "approved", label: "Approved hours only" }, { value: "all", label: "All recorded (incl. pending)" }, { value: "audited", label: "Staff-audited only (grant programs)" }]} /></Field>
          <Field label="Exclusions">
            <div style={{ display: "flex", flexDirection: "column", gap: 8 }}>
              <Checkbox checked={true} onChange={() => {}} label="Exclude staff hours" />
              <Checkbox checked={true} onChange={() => {}} label="Exclude community-service hours" />
              <Checkbox checked={true} onChange={() => {}} label="Exclude red-flagged volunteers" />
              <Checkbox checked={false} onChange={() => {}} label="Exclude inactive volunteers" />
            </div>
          </Field>
          {p.type === "rolling" && (
            <Field label="On issuance"><Select defaultValue="reset" options={[{ value: "reset", label: "Reset eligibility window" }, { value: "noreset", label: "Do not reset" }]} /></Field>
          )}
          <div style={{ ...m7r_overline, margin: "16px 0 10px" }}>Volunteer-facing vocabulary</div>
          <Field label="Milestone label"><Input defaultValue={p.labels.milestone} /></Field>
          <Field label="Recipient label"><Input defaultValue={p.labels.recipients} /></Field>
        </div>
      </div>
    )}
  </Card>
);

// ====================== PRIOR-CY FULFILLMENT (FR1.6) ======================
const PriorCY = ({ rows }) => {
  const [year, setYear] = useState("2025");
  const [tier, setTier] = useState("tier-10");
  const [previewOpen, setPreviewOpen] = useState(false);

  // mock: prior-CY data set is bigger than current
  const priorCyCount = { "tier-10": 89, "tier-100": 18, "tier-500": 3 }[tier] || 0;

  return (
    <>
      <p style={{ fontSize: 13, color: "var(--fg-2)", marginBottom: 18, maxWidth: 720 }}>
        Prior-calendar-year milestone eligibility for tenantwide gift fulfillment. Includes mailing fields, award preference,
        and qualifying hours. Exports as Avery&nbsp;5160 labels or CSV with mailing columns.
      </p>

      <Card style={{ marginBottom: 18 }}>
        <div style={{ display: "grid", gridTemplateColumns: "180px 220px 220px 1fr auto", gap: 12, alignItems: "end" }}>
          <Field label="Year">
            <Select value={year} onChange={(e) => setYear(e.target.value)} options={["2025", "2024", "2023", "2022"]} />
          </Field>
          <Field label="Milestone">
            <Select value={tier} onChange={(e) => setTier(e.target.value)}
              options={[
                { value: "tier-10", label: "10-hour gift" },
                { value: "tier-100", label: "100-hour gift" },
                { value: "tier-500", label: "500-hour gift" },
              ]} />
          </Field>
          <Field label="Address validation">
            <Select defaultValue="strict"
              options={[
                { value: "strict", label: "Strict — block missing/invalid addresses" },
                { value: "warn",   label: "Warn — show issues, allow export" },
                { value: "off",    label: "Off — export as-is" },
              ]} />
          </Field>
          <Field label="Include">
            <div style={{ display: "flex", gap: 12, flexWrap: "wrap" }}>
              <Checkbox label="Already-issued" />
              <Checkbox label="Opted-out (annotated)" />
              <Checkbox label="Deceased" />
            </div>
          </Field>
          <div style={{ display: "flex", gap: 8, justifyContent: "flex-end" }}>
            <Btn kind="secondary" size="sm" icon={IconSearch} onClick={() => setPreviewOpen(true)}>Preview</Btn>
            <Btn size="sm" icon={IconDownload}>Run report</Btn>
          </div>
        </div>
      </Card>

      <div style={{ display: "grid", gridTemplateColumns: "minmax(0, 1.6fr) minmax(280px, 1fr)", gap: 14, marginBottom: 18 }}>
        <Card>
          <div style={{ ...m7r_overline, marginBottom: 12 }}>Report definition · prior CY {year} · {tierName(tier).replace("Annual · ", "")}</div>
          <div style={{ display: "grid", gridTemplateColumns: "repeat(3, 1fr)", gap: 14, marginBottom: 16 }}>
            <Kpi label="Recipients" value={String(priorCyCount)} delta={"calendar year " + year} tone="neutral" icon={IconAward} />
            <Kpi label="With mailing address" value={String(priorCyCount - 4)} delta="4 missing" tone="neutral" icon={IconMail} />
            <Kpi label="Already issued" value="2" delta="will be skipped" tone="neutral" icon={IconCheck} />
          </div>
          <div style={{ ...m7r_overline, marginBottom: 10 }}>Output columns</div>
          <div style={{ display: "flex", gap: 6, flexWrap: "wrap" }}>
            {["Full name", "Mailing line 1", "Mailing line 2", "City", "State", "ZIP", "Award preference", "Qualifying hours", "Qualifying date range", "Site", "Program", "Region", "Issuance status", "Last issued date"]
              .map(c => <FilterChip key={c} label={c} />)}
          </div>
        </Card>

        <Card>
          <div style={{ ...m7r_overline, marginBottom: 12 }}>Output formats</div>
          <div style={{ display: "flex", flexDirection: "column", gap: 8 }}>
            <OutFmt label="Avery 5160 (3×10, 30 labels/sheet)" desc="PDF, address-block formatted" primary />
            <OutFmt label="CSV with mailing columns" desc="For external mail-house upload" />
            <OutFmt label="XLSX summary" desc="Includes pivots by program + site" />
            <OutFmt label="Google Sheets" desc="Spreadsheet equivalent · creates a copy" />
          </div>
          <div style={{ marginTop: 16, padding: 12, background: "var(--paper-deep)", borderRadius: 10, fontSize: 12, color: "var(--fg-2)", lineHeight: 1.5 }}>
            Address validation is run before export. Issues are surfaced inline (PO box where ground only, missing ZIP, unverified > 12 months). Scoped admins see only the rows in their region.
          </div>
        </Card>
      </div>

      {previewOpen && <LabelPreview tier={tier} year={year} onClose={() => setPreviewOpen(false)} />}
    </>
  );
};

const OutFmt = ({ label, desc, primary }) => (
  <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", padding: "10px 12px", borderRadius: 10, background: "var(--paper)", border: "1px solid var(--border-soft)" }}>
    <div>
      <div style={{ fontSize: 13, fontWeight: 500 }}>{label}</div>
      <div style={{ ...m7r_meta, marginTop: 2 }}>{desc}</div>
    </div>
    <Btn size="sm" kind={primary ? "primary" : "secondary"} icon={IconDownload}>Export</Btn>
  </div>
);

const LabelPreview = ({ tier, year, onClose }) => {
  // 12 mock labels to look like an Avery 5160 sheet preview
  const labels = [
    { name: "Sasha Arenas", l1: "814 Lemay Ave", city: "Fort Collins, CO 80524" },
    { name: "Maya Okonkwo", l1: "47 Pine Ridge Rd", city: "Boulder, CO 80302" },
    { name: "Aliyah Chen", l1: "1409 16th St #4", city: "Denver, CO 80202" },
    { name: "Rae Kowalski", l1: "89 Aspen Ct", city: "Estes Park, CO 80517" },
    { name: "Jordan Tovar", l1: "312 Garfield Ave", city: "Loveland, CO 80537" },
    { name: "Linh Nguyen", l1: "8801 Federal Blvd", city: "Westminster, CO 80031" },
    { name: "Esteban Mendez", l1: "PO Box 4471", city: "Pueblo, CO 81003" },
    { name: "Tara Walsh", l1: "—", city: "Opted out (donate to general fund)", muted: true },
    { name: "Ben Liu", l1: "2210 N Garfield Ave", city: "Longmont, CO 80501" },
    { name: "Robert Fischer", l1: "Address unverified · 14 mo", city: "Lakewood, CO 80228", warn: true },
    { name: "Devon Park", l1: "8806 W 32nd Ave", city: "Wheat Ridge, CO 80033" },
    { name: "Avery Sanchez", l1: "412 Walnut St", city: "Boulder, CO 80302" },
  ];

  return (
    <div style={overlay} onClick={onClose}>
      <div style={{ ...drawer, width: "min(820px, 100%)" }} onClick={(e) => e.stopPropagation()}>
        <div style={drawerHead}>
          <div>
            <div style={{ ...m7r_overline }}>Print preview · Avery 5160 · CY {year}</div>
            <div style={{ fontSize: 19, fontWeight: 500, color: "var(--ink)", marginTop: 4 }}>{tierName(tier).replace("Annual · ", "")} mailing labels · sheet 1 of 3</div>
          </div>
          <IconBtn icon={IconX} size={32} onClick={onClose} aria-label="Close" />
        </div>
        <div style={{ flex: 1, overflow: "auto", padding: 20 }}>
          <div style={{ background: "#FFFFFF", padding: "40px 18px", margin: "0 auto", maxWidth: 612, border: "1px solid var(--border)", boxShadow: "var(--shadow-sm)" }}>
            <div style={{ display: "grid", gridTemplateColumns: "repeat(3, 1fr)", gap: "8px 12px" }}>
              {labels.map((l, i) => (
                <div key={i} style={{
                  border: "1px dashed " + (l.warn ? "var(--amber-500)" : "var(--stone-200)"),
                  borderRadius: 4, padding: "16px 12px", minHeight: 64,
                  fontFamily: "var(--font-sans)", fontSize: 11, lineHeight: 1.4,
                  color: l.muted ? "var(--fg-3)" : "var(--ink)",
                  background: l.muted ? "var(--paper-deep)" : "#FFFFFF",
                }}>
                  <div style={{ fontWeight: 500 }}>{l.name}</div>
                  <div>{l.l1}</div>
                  <div>{l.city}</div>
                  {l.warn && <div style={{ color: "var(--amber-600)", fontSize: 10, marginTop: 4 }}>⚠ verify before sending</div>}
                </div>
              ))}
            </div>
          </div>
        </div>
        <div style={drawerFoot}>
          <span style={{ fontSize: 12, color: "var(--fg-3)", marginRight: "auto" }}>3 sheets · 4 address issues to resolve</span>
          <Btn kind="secondary" icon={IconDownload}>Download PDF</Btn>
          <Btn icon={IconCheck}>Send to mail-house</Btn>
        </div>
      </div>
    </div>
  );
};

// ============================================================
Object.assign(window, { OrgRecognition });
