// ===== m8-communications.jsx =====
// M8 · Communications — the M8 ops hub
// Tabs: Overview · Templates · Campaigns · Help Needed · Send health · Suppressions · Audit timeline · Sender identity
// Covers:
//   FR3  versioned templates + immutable sent snapshots
//   FR4  personalization token catalog
//   FR6  consent / suppression / red-flag enforcement (the hard gate)
//   FR7  bounces, failures, unsubs, suppression management
//   FR8  communication logs & activity history
//   FR10 SMS opt-in / STOP / carrier throttling
//   FR11 one-tap roster broadcasts (entry point)
//   FR12 automated campaigns
//   FR13 Help Needed outreach with eligibility-aware recommendations
//   FR15 send safety: caps, queueing, splitting, master switch
//   FR18 sender identity + reply-to behavior

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,
  IconMail, IconMsg, IconUsers, IconStar, IconClock, IconBell, IconEdit, IconMore,
  IconFilter, IconSearch, IconShield, IconChevron, IconChevronD, IconExternal, IconAward,
  IconCal,
  VOLUNTEERS,
} = window;
const { useState: useC, useMemo: useCM } = React;

const m8c_over = { fontSize: 11, letterSpacing: "0.12em", textTransform: "uppercase", color: "var(--fg-3)", fontWeight: 500 };
const m8c_meta = { fontSize: 11, color: "var(--fg-3)" };

// ============================================================
// ROOT
// ============================================================
const OrgCommunications = ({ go }) => {
  const [tab, setTab] = useC("overview");
  const [viewAs, setViewAs] = useC("universal");

  return (
    <>
      <TopBar
        title="Communications"
        subtitle="Send health · templates · campaigns · suppressions · audit"
        primary={<Btn icon={IconPlus} onClick={() => go("newsletters")}>New newsletter</Btn>}
        secondary={<Btn kind="secondary" icon={IconMsg} onClick={() => go("messages")}>Inbox</Btn>}
      />
      <div style={{ flex: 1, overflow: "auto", padding: "20px 32px 56px" }}>
        <ViewAs viewAs={viewAs} setViewAs={setViewAs} />

        <Tabs active={tab} onChange={setTab} tabs={[
          { id: "overview",     label: "Overview" },
          { id: "templates",    label: "Templates",      count: 14 },
          { id: "campaigns",    label: "Campaigns",      count: 9 },
          { id: "helpneeded",   label: "Help Needed" },
          { id: "health",       label: "Send health" },
          { id: "suppressions", label: "Suppressions",   count: 612 },
          { id: "audit",        label: "Audit timeline" },
          { id: "identity",     label: "Sender identity" },
        ]} />

        {tab === "overview"     && <Overview viewAs={viewAs} go={go} />}
        {tab === "templates"    && <Templates viewAs={viewAs} />}
        {tab === "campaigns"    && <Campaigns viewAs={viewAs} />}
        {tab === "helpneeded"   && <HelpNeeded />}
        {tab === "health"       && <SendHealth />}
        {tab === "suppressions" && <Suppressions />}
        {tab === "audit"        && <AuditTimeline />}
        {tab === "identity"     && <SenderIdentity />}
      </div>
    </>
  );
};

// ============================================================
// VIEW-AS (reused from M7 reports — scope-aware)
// ============================================================
const ViewAs = ({ viewAs, setViewAs }) => {
  const opts = [
    { id: "universal", label: "Universal admin",         desc: "All tenant communications · run any send · master switch + caps visible · audit full" },
    { id: "regional",  label: "Regional admin · NE",     desc: "Northeast only · scoped recipient pool · cannot send statewide · ops health visible" },
    { id: "readonly",  label: "Read-only audit / funder",desc: "Aggregated dashboards · audit + bounce metrics · no compose, no PII reveal, no template edits" },
  ];
  return (
    <div style={{ display: "flex", gap: 10, padding: "10px 14px", marginBottom: 16, borderRadius: 12, background: "var(--paper-soft)", border: "1px solid var(--border-soft)", alignItems: "center", flexWrap: "wrap" }}>
      <div style={{ display: "flex", gap: 6, alignItems: "center", whiteSpace: "nowrap" }}>
        <IconShield size={14} style={{ color: "var(--fg-3)" }} />
        <span style={{ ...m8c_over }}>Preview as</span>
      </div>
      <div style={{ display: "flex", gap: 4 }}>
        {opts.map(o => (
          <button key={o.id} onClick={() => setViewAs(o.id)} style={{
            background: viewAs === o.id ? "var(--ink)" : "transparent",
            color: viewAs === o.id ? "var(--paper)" : "var(--fg-1)",
            border: "1px solid " + (viewAs === o.id ? "var(--ink)" : "var(--border)"),
            padding: "6px 12px", borderRadius: 999, fontSize: 12, fontWeight: 500, cursor: "pointer", fontFamily: "inherit", whiteSpace: "nowrap",
          }}>{o.label}</button>
        ))}
      </div>
      <div style={{ flex: 1, minWidth: 200, fontSize: 12, color: "var(--fg-2)" }}>
        {opts.find(o => o.id === viewAs)?.desc}
      </div>
    </div>
  );
};

// ============================================================
// OVERVIEW
// ============================================================
const Overview = ({ viewAs, go }) => (
  <>
    <div style={{ display: "grid", gridTemplateColumns: "repeat(4, 1fr)", gap: 14, marginBottom: 24 }}>
      <Kpi label="Sent (30d)" value="14,218" delta="email 11.2k · SMS 3.0k" tone="up" icon={IconMail} />
      <Kpi label="Delivery rate" value="99.4%" delta="84 bounces · 2 carrier failures" tone="up" icon={IconCheck} />
      <Kpi label="Active suppressions" value="612" delta="unsubs 184 · bounces 412 · flagged 16" tone="neutral" icon={IconShield} />
      <Kpi label="Master switch" value="ON" delta="prod · sandbox masked: 0 today" tone="up" icon={IconBell} />
    </div>

    <div style={{ display: "grid", gridTemplateColumns: "minmax(0, 1.6fr) minmax(280px, 1fr)", gap: 14, marginBottom: 22 }}>
      <Card>
        <div style={{ ...m8c_over, marginBottom: 14 }}>Send volume · last 14 days</div>
        <div style={{ display: "flex", gap: 4, height: 140, alignItems: "end", marginBottom: 10 }}>
          {[
            { d: "May 10", em: 320, sms: 0 },
            { d: "May 11", em: 480, sms: 22 },
            { d: "May 12", em: 1180, sms: 38 },
            { d: "May 13", em: 720, sms: 14 },
            { d: "May 14", em: 420, sms: 86 },
            { d: "May 15", em: 360, sms: 12 },
            { d: "May 16", em: 220, sms: 8 },
            { d: "May 17", em: 980, sms: 24 },
            { d: "May 18", em: 4280, sms: 18 },  // statewide newsletter
            { d: "May 19", em: 380, sms: 28 },
            { d: "May 20", em: 640, sms: 142 },  // Hunter ed reminders
            { d: "May 21", em: 540, sms: 14 },
            { d: "May 22", em: 1020, sms: 86 },  // weather cancellation broadcast
            { d: "May 23", em: 480, sms: 8 },
          ].map((day, i) => {
            const total = day.em + day.sms;
            const max = 5000;
            return (
              <div key={i} style={{ flex: 1, display: "flex", flexDirection: "column", alignItems: "center", gap: 4 }}>
                <div style={{ width: "100%", height: (total / max) * 124, display: "flex", flexDirection: "column", justifyContent: "flex-end", borderRadius: "4px 4px 0 0", overflow: "hidden" }}>
                  <div style={{ width: "100%", height: `${(day.sms / total) * 100}%`, background: "var(--iris-500)" }} />
                  <div style={{ width: "100%", height: `${(day.em / total) * 100}%`, background: "var(--coral-600)" }} />
                </div>
                <span style={{ ...m8c_meta, fontSize: 9, transform: "rotate(-30deg)", transformOrigin: "center" }}>{day.d.slice(-2)}</span>
              </div>
            );
          })}
        </div>
        <div style={{ display: "flex", gap: 12, fontSize: 11, color: "var(--fg-2)" }}>
          <span><span style={{ display: "inline-block", width: 8, height: 8, background: "var(--coral-600)", marginRight: 4, borderRadius: 2 }} /> Email 11,220</span>
          <span><span style={{ display: "inline-block", width: 8, height: 8, background: "var(--iris-500)", marginRight: 4, borderRadius: 2 }} /> SMS 2,998</span>
          <span style={{ marginLeft: "auto", color: "var(--fg-3)" }}>peaks: May 18 statewide newsletter · May 22 weather cancellation</span>
        </div>
      </Card>
      <Card>
        <div style={{ ...m8c_over, marginBottom: 12 }}>Today · live</div>
        <LiveRow label="Currently sending" value="0" sub="Queue idle" />
        <LiveRow label="Queued for later" value="2" sub="Jun 3 hunter-ed ES · Jun 1 statewide" />
        <LiveRow label="Failed last hour" value="0" sub="Last failure: yest 4:12 pm" />
        <LiveRow label="Unsubs today" value="2" sub="Honored on next send" />
        <LiveRow label="Inbound replies" value="14" sub="9 routed to originators · 5 to central" />
        <div style={{ marginTop: 12, padding: 10, background: viewAs === "readonly" ? "var(--iris-100)" : "var(--paper-deep)", color: viewAs === "readonly" ? "var(--iris-600)" : "var(--fg-2)", borderRadius: 8, fontSize: 11, lineHeight: 1.5 }}>
          {viewAs === "readonly"
            ? "Read-only view. You see aggregate counts and audit refs only. PII, message bodies, and template editing are hidden."
            : "Live counters update as sends complete. Click any number to drill into the send job."}
        </div>
      </Card>
    </div>

    <SectionHead title="Quick actions" />
    <div style={{ display: "grid", gridTemplateColumns: "repeat(3, 1fr)", gap: 12, marginBottom: 22 }}>
      <QuickAction icon={IconUsers} title="Broadcast to a roster" desc="Pick an event roster or waitlist · auto-fills date, location, where-to-meet."
        onClick={() => go("messages")} disabled={viewAs === "readonly"} />
      <QuickAction icon={IconBell} title="Send Help Needed outreach" desc="Eligibility-aware. Targets active volunteers within site/program scope."
        onClick={() => {}} disabled={viewAs === "readonly"} />
      <QuickAction icon={IconMail} title="Run a campaign manually" desc="Trigger inactive re-engagement, hour-recording nudge, or shift reminder series."
        onClick={() => {}} disabled={viewAs === "readonly"} />
    </div>

    <SectionHead title="Recent campaign activity" />
    <Card padded={false}>
      {[
        { who: "Hunter ed class reminders",  what: "Auto-sent · 28 SMS · trigger 'class -24h'", ok: true,  t: "Today · 9:00 am" },
        { who: "Camp host pre-season",       what: "Step 3 of 4 · sent to 84 hosts ·  3 opens still pending", ok: true,  t: "Today · 8:00 am" },
        { who: "Statewide newsletter (May)", what: "Dispatched 3,984 · 1,514 opens · 8 unsubs · audit nl-send-2026-05-05-1a", ok: true, t: "May 5" },
        { who: "Shift reminder · Cherry Creek Jun 14", what: "BLOCKED 1 recipient (red-flagged) · 27 sent · 27 delivered", ok: "warn", t: "Jun 13" },
        { who: "Inactive re-engagement",     what: "Draft pending universal-admin approval · 500 eligible", ok: "pending", t: "yesterday" },
      ].map((r, i, arr) => (
        <div key={i} style={{ display: "grid", gridTemplateColumns: "minmax(220px, 1.4fr) minmax(0, 2fr) 110px 130px", gap: 14, padding: "13px 18px", alignItems: "center", borderBottom: i === arr.length - 1 ? "none" : "1px solid var(--border-soft)", fontSize: 13 }}>
          <div style={{ fontWeight: 500 }}>{r.who}</div>
          <div style={{ fontSize: 12, color: "var(--fg-2)" }}>{r.what}</div>
          <StatusChip status={r.ok === true ? "confirmed" : r.ok === "warn" ? "info" : "pending"} size="sm" label={r.ok === true ? "Sent" : r.ok === "warn" ? "1 blocked" : "Pending"} />
          <div style={{ ...m8c_meta }}>{r.t}</div>
        </div>
      ))}
    </Card>
  </>
);

const LiveRow = ({ label, value, sub }) => (
  <div style={{ display: "grid", gridTemplateColumns: "1fr auto", gap: 10, padding: "9px 0", borderBottom: "1px dashed var(--border-soft)", alignItems: "baseline" }}>
    <div>
      <div style={{ fontSize: 12, color: "var(--fg-1)" }}>{label}</div>
      <div style={{ ...m8c_meta, marginTop: 2 }}>{sub}</div>
    </div>
    <div style={{ fontFamily: "var(--font-display)", fontSize: 22, color: "var(--ink)", fontVariantNumeric: "tabular-nums" }}>{value}</div>
  </div>
);

const QuickAction = ({ icon: Icon, title, desc, onClick, disabled }) => (
  <Card style={{ cursor: disabled ? "not-allowed" : "pointer", opacity: disabled ? 0.5 : 1 }} onClick={disabled ? null : 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 }}>{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}>Open</Btn>
  </Card>
);

// ============================================================
// TEMPLATES
// ============================================================
const TEMPLATES = [
  { id: "tpl-stm",     name: "Statewide monthly · CPW master",      v: "v8", channel: "email", uses: 7,  by: "Priya Sandoval",  updated: "Apr 22, 2026" },
  { id: "tpl-reg",     name: "Regional digest · 3-column",          v: "v3", channel: "email", uses: 18, by: "Marcus Chen",     updated: "Mar 10, 2026" },
  { id: "tpl-ch",      name: "Camp host onboarding · welcome",      v: "v2", channel: "email", uses: 4,  by: "Aliyah Chen",     updated: "Mar 28, 2026" },
  { id: "tpl-hn",      name: "Help Needed · simple CTA",            v: "v5", channel: "email", uses: 22, by: "Priya Sandoval",  updated: "May 3, 2026" },
  { id: "tpl-reeng",   name: "Re-engagement (warm)",                v: "v1", channel: "email", uses: 0,  by: "Priya Sandoval",  updated: "May 12, 2026" },
  { id: "tpl-es",      name: "Statewide · español",                 v: "v2", channel: "email", uses: 3,  by: "Marcus Chen",     updated: "Apr 4, 2026" },
  { id: "tpl-hr",      name: "Monthly hours statement",             v: "v4", channel: "email", uses: 12, by: "System",          updated: "Feb 14, 2026" },
  { id: "tpl-ty",      name: "Thank-you (post-event)",              v: "v6", channel: "email", uses: 84, by: "Priya Sandoval",  updated: "Apr 18, 2026" },
  { id: "tpl-sms-rem", name: "Shift reminder · SMS · 24h",          v: "v3", channel: "sms",   uses: 142, by: "Marcus Chen",    updated: "Apr 30, 2026" },
  { id: "tpl-sms-2h",  name: "Shift reminder · SMS · 2h",           v: "v2", channel: "sms",   uses: 86, by: "Priya Sandoval",  updated: "May 1, 2026" },
  { id: "tpl-sms-cx",  name: "Cancellation · SMS",                  v: "v2", channel: "sms",   uses: 6,  by: "Priya Sandoval",  updated: "May 14, 2026" },
  { id: "tpl-sms-hed", name: "Hunter ed class · -24h SMS",          v: "v1", channel: "sms",   uses: 28, by: "Aliyah Chen",     updated: "May 12, 2026" },
  { id: "tpl-sms-hn",  name: "Help Needed · SMS · short",           v: "v3", channel: "sms",   uses: 38, by: "Priya Sandoval",  updated: "May 8, 2026" },
  { id: "tpl-sv",      name: "Survey · post-event invite",          v: "v4", channel: "email", uses: 124, by: "Priya Sandoval", updated: "Mar 28, 2026" },
];

const Templates = ({ viewAs }) => {
  const [filter, setFilter] = useC("all");
  const [activeId, setActiveId] = useC("tpl-stm");
  const list = TEMPLATES.filter(t => filter === "all" ? true : t.channel === filter);
  const active = TEMPLATES.find(t => t.id === activeId);

  return (
    <div style={{ display: "grid", gridTemplateColumns: "minmax(0, 1.4fr) minmax(320px, 1fr)", gap: 14 }}>
      <div>
        <div style={{ display: "flex", gap: 8, marginBottom: 12, alignItems: "center" }}>
          <SegBtn active={filter === "all"} onClick={() => setFilter("all")}>All</SegBtn>
          <SegBtn active={filter === "email"} onClick={() => setFilter("email")}>Email</SegBtn>
          <SegBtn active={filter === "sms"} onClick={() => setFilter("sms")}>SMS</SegBtn>
          <div style={{ marginLeft: "auto", display: "flex", gap: 6 }}>
            <Btn size="sm" kind="secondary" icon={IconPlus} disabled={viewAs === "readonly"}>New template</Btn>
          </div>
        </div>
        <Card padded={false}>
          <div style={{ display: "grid", gridTemplateColumns: "minmax(220px, 1.6fr) 70px 90px 110px 130px 36px", gap: 12, padding: "12px 16px", fontSize: 11, letterSpacing: "0.1em", textTransform: "uppercase", color: "var(--fg-3)", borderBottom: "1px solid var(--border)" }}>
            <span>Template</span><span>Channel</span><span>Version</span><span>Uses</span><span>Updated</span><span />
          </div>
          {list.map((t, i) => (
            <div key={t.id} onClick={() => setActiveId(t.id)} style={{
              display: "grid", gridTemplateColumns: "minmax(220px, 1.6fr) 70px 90px 110px 130px 36px", gap: 12,
              padding: "13px 16px", alignItems: "center",
              borderBottom: i === list.length - 1 ? "none" : "1px solid var(--border-soft)",
              cursor: "pointer", background: activeId === t.id ? "var(--paper-soft)" : "transparent",
              borderLeft: activeId === t.id ? "3px solid var(--coral-600)" : "3px solid transparent",
            }}>
              <div>
                <div style={{ fontSize: 13, fontWeight: 500 }}>{t.name}</div>
                <div style={{ ...m8c_meta, marginTop: 2 }}>by {t.by}</div>
              </div>
              <span style={{ fontSize: 10, padding: "2px 7px", borderRadius: 999, background: t.channel === "sms" ? "var(--iris-100)" : "var(--paper-deep)", color: t.channel === "sms" ? "var(--iris-600)" : "var(--fg-1)", fontWeight: 500, textTransform: "uppercase", letterSpacing: "0.06em", textAlign: "center" }}>{t.channel}</span>
              <code style={{ fontFamily: "var(--font-mono)", fontSize: 11, color: "var(--fg-3)" }}>{t.v}</code>
              <span style={{ fontSize: 12, fontVariantNumeric: "tabular-nums" }}>{t.uses.toLocaleString()}</span>
              <span style={{ fontSize: 12, color: "var(--fg-2)" }}>{t.updated}</span>
              <IconBtn icon={IconMore} size={28} />
            </div>
          ))}
        </Card>
      </div>

      {active && <TemplateDetail t={active} viewAs={viewAs} />}
    </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 TemplateDetail = ({ t, viewAs }) => (
  <Card>
    <div style={{ display: "flex", justifyContent: "space-between", alignItems: "start", marginBottom: 12 }}>
      <div>
        <div style={{ ...m8c_over, marginBottom: 4 }}>{t.channel === "sms" ? "SMS template" : "Email template"} · {t.v}</div>
        <div style={{ fontSize: 16, fontWeight: 500 }}>{t.name}</div>
      </div>
      <div style={{ display: "flex", gap: 6 }}>
        <Btn size="sm" kind="ghost">Preview</Btn>
        <Btn size="sm" disabled={viewAs === "readonly"} icon={IconEdit}>Edit</Btn>
      </div>
    </div>

    <div style={{ ...m8c_over, marginBottom: 8 }}>Version history</div>
    <div style={{ display: "flex", flexDirection: "column", gap: 4, marginBottom: 14 }}>
      {[
        { v: t.v, who: t.by, when: t.updated + " · current" },
        { v: bumpDown(t.v, 1), who: "Marcus Chen", when: "Feb 14, 2026" },
        { v: bumpDown(t.v, 2), who: t.by, when: "Nov 4, 2025" },
        { v: "v1", who: "Priya Sandoval", when: "Sep 8, 2025 · initial" },
      ].map((h, i) => (
        <div key={i} style={{ display: "grid", gridTemplateColumns: "60px 1fr 130px", gap: 10, padding: "7px 0", borderTop: i === 0 ? "none" : "1px dashed var(--border-soft)", fontSize: 12, alignItems: "center" }}>
          <code style={{ fontFamily: "var(--font-mono)", color: i === 0 ? "var(--coral-700)" : "var(--fg-3)" }}>{h.v}</code>
          <span style={{ color: "var(--fg-1)" }}>{h.who}</span>
          <span style={{ ...m8c_meta }}>{h.when}</span>
        </div>
      ))}
    </div>

    <div style={{ ...m8c_over, marginBottom: 8 }}>Sent snapshots referencing this template</div>
    <div style={{ padding: 10, background: "var(--paper-deep)", borderRadius: 8, fontSize: 12, color: "var(--fg-2)", lineHeight: 1.5 }}>
      <strong style={{ color: "var(--ink)" }}>{t.uses.toLocaleString()} sends</strong> reference this template. Each send is tied to an immutable content snapshot of the version that was active at send. Editing this template does not retroactively change any sent message.
    </div>

    <div style={{ ...m8c_over, margin: "18px 0 8px" }}>Tokens used</div>
    <div style={{ display: "flex", gap: 6, flexWrap: "wrap" }}>
      {(t.channel === "sms"
        ? ["{{first_name}}", "{{event_title}}", "{{event_time}}", "{{site_name}}"]
        : ["{{first_name}}", "{{ytd_hours}}", "{{rolling_12_hours}}", "{{help_needed_14d}}", "{{profile_url}}", "{{sender_signature}}"]
      ).map(tk => (
        <code key={tk} style={{ fontFamily: "var(--font-mono)", fontSize: 11, padding: "2px 8px", background: "var(--paper-deep)", borderRadius: 4, color: "var(--coral-700)" }}>{tk}</code>
      ))}
    </div>
  </Card>
);

function bumpDown(v, n) {
  const num = parseInt(v.replace(/[^\d]/g, ""), 10);
  return "v" + Math.max(1, num - n);
}

// ============================================================
// CAMPAIGNS
// ============================================================
const CAMPAIGNS = [
  {
    id: "c-shift-rem", name: "Shift reminders", desc: "48h email + 2h SMS for every confirmed shift.", state: "active",
    trigger: "Shift start − 48h (email) + 2h (SMS)", audience: "Confirmed roster · per shift", cadence: "Per shift",
    sent30d: 1284, opens: 612, replies: 38, opt_outs: 4, blocked: 12,
    steps: [
      { offset: "−48 h", channel: "email", template: "tpl-rem-48 · v3", stop: "Volunteer cancels OR shift cancels" },
      { offset: "−2 h",  channel: "sms",   template: "tpl-sms-2h · v2", stop: "Volunteer cancels OR shift cancels" },
    ],
  },
  {
    id: "c-thanks", name: "Thank-you after a shift", desc: "Triggered 4 hours after hours are recorded.", state: "active",
    trigger: "On hour-record · +4 h", audience: "Any volunteer with recorded hours", cadence: "Per shift",
    sent30d: 612, opens: 412, replies: 24, opt_outs: 1, blocked: 2,
    steps: [{ offset: "+4 h", channel: "email", template: "tpl-ty · v6", stop: "Volunteer marked deceased / inactive" }],
  },
  {
    id: "c-hr-rem", name: "Hour-recording reminder", desc: "Nudges volunteer to log hours within 7 days of a shift.", state: "active",
    trigger: "Shift complete + 3 days · no hours yet", audience: "Volunteers with attended shift but no logged hours", cadence: "Once per shift",
    sent30d: 92, opens: 71, replies: 12, opt_outs: 0, blocked: 1,
    steps: [{ offset: "+3 d", channel: "email", template: "tpl-hr-rem · v2", stop: "Hours logged OR +14 days no response" }],
  },
  {
    id: "c-reengage", name: "Inactive re-engagement", desc: "Warm reactivation for volunteers lapsed >12 months.", state: "draft",
    trigger: "Last hour > 365 days", audience: "Inactive · not deceased · not red-flagged · email consent intact", cadence: "Quarterly",
    sent30d: 0, opens: 0, replies: 0, opt_outs: 0, blocked: 0,
    steps: [
      { offset: "Day 0",  channel: "email", template: "tpl-reeng · v1", stop: "Volunteer responds OR books a shift" },
      { offset: "+7 d",   channel: "email", template: "tpl-reeng-2 · draft", stop: "Volunteer responds OR books a shift" },
      { offset: "+30 d",  channel: "email", template: "tpl-reeng-3 · draft", stop: "Step ends · volunteer marked archived if no engagement" },
    ],
  },
  {
    id: "c-camphost", name: "Camp host pre-season", desc: "4-step onboarding from approval to season start.", state: "active",
    trigger: "Camp host status = approved", audience: "Approved camp hosts", cadence: "Per host",
    sent30d: 84, opens: 76, replies: 41, opt_outs: 0, blocked: 0,
    steps: [
      { offset: "Day 0",  channel: "email", template: "tpl-ch-welcome · v2", stop: "—" },
      { offset: "+3 d",   channel: "email", template: "tpl-ch-orient · v2", stop: "—" },
      { offset: "+14 d",  channel: "sms",   template: "tpl-ch-arrival · v1", stop: "—" },
      { offset: "−7 d",   channel: "email", template: "tpl-ch-checklist · v3", stop: "Season start" },
    ],
  },
  {
    id: "c-hunter", name: "Hunter ed class reminders", desc: "Class -24h SMS + post-class survey (Hunter Outreach grant).", state: "active",
    trigger: "Hunter ed class scheduled", audience: "Confirmed instructors + registered students", cadence: "Per class",
    sent30d: 28, opens: 24, replies: 18, opt_outs: 0, blocked: 0,
    steps: [
      { offset: "−24 h",  channel: "sms",   template: "tpl-sms-hed · v1", stop: "Class cancels" },
      { offset: "+2 h",   channel: "email", template: "tpl-sv · v4 (post-class survey)", stop: "Class cancels" },
    ],
  },
  {
    id: "c-survey-annual", name: "Annual statewide survey", desc: "Scheduled blast + 3 reminders to non-respondents.", state: "scheduled",
    trigger: "Jun 1, 2026 · 8:00 am MT", audience: "All active CPW volunteers statewide", cadence: "Annual",
    sent30d: 0, opens: 0, replies: 0, opt_outs: 0, blocked: 0,
    steps: [
      { offset: "Day 0",  channel: "email", template: "tpl-sv-annual · v3", stop: "—" },
      { offset: "+3 d",   channel: "email", template: "tpl-sv-rem · v2",    stop: "Volunteer responded" },
      { offset: "+7 d",   channel: "email", template: "tpl-sv-rem · v2",    stop: "Volunteer responded" },
      { offset: "+14 d",  channel: "sms",   template: "tpl-sms-sv · v1",    stop: "Volunteer responded" },
    ],
  },
  {
    id: "c-anniv", name: "Service anniversary", desc: "Personal recognition note on hire-date anniversary.", state: "active",
    trigger: "Anniversary date · 0:00 MT", audience: "Volunteers active in last 12 months", cadence: "Per volunteer",
    sent30d: 38, opens: 30, replies: 6, opt_outs: 0, blocked: 0,
    steps: [{ offset: "Day 0", channel: "email", template: "tpl-anniv · v2", stop: "—" }],
  },
  {
    id: "c-cancel-wx", name: "Weather cancellation broadcast", desc: "Manual trigger from an event roster.", state: "active",
    trigger: "Manual · from event roster", audience: "Confirmed roster + waitlist", cadence: "Ad hoc",
    sent30d: 28, opens: 26, replies: 22, opt_outs: 2, blocked: 1,
    steps: [{ offset: "On send", channel: "sms", template: "tpl-sms-cx · v2", stop: "—" }],
  },
];

const Campaigns = ({ viewAs }) => {
  const [activeId, setActiveId] = useC("c-shift-rem");
  const a = CAMPAIGNS.find(c => c.id === activeId);
  return (
    <div style={{ display: "grid", gridTemplateColumns: "minmax(0, 1fr) minmax(380px, 1.2fr)", gap: 14 }}>
      <Card padded={false}>
        <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", padding: "12px 16px", borderBottom: "1px solid var(--border)" }}>
          <div style={{ ...m8c_over }}>{CAMPAIGNS.length} campaigns</div>
          <Btn size="sm" kind="secondary" icon={IconPlus} disabled={viewAs === "readonly"}>New campaign</Btn>
        </div>
        {CAMPAIGNS.map((c, i) => (
          <div key={c.id} onClick={() => setActiveId(c.id)} style={{
            display: "grid", gridTemplateColumns: "1fr 110px", gap: 12, padding: "13px 16px", alignItems: "center",
            borderBottom: i === CAMPAIGNS.length - 1 ? "none" : "1px solid var(--border-soft)",
            cursor: "pointer",
            background: activeId === c.id ? "var(--paper-soft)" : "transparent",
            borderLeft: activeId === c.id ? "3px solid var(--coral-600)" : "3px solid transparent",
          }}>
            <div>
              <div style={{ fontSize: 13, fontWeight: 500 }}>{c.name}</div>
              <div style={{ ...m8c_meta, marginTop: 3 }}>{c.steps.length} step{c.steps.length === 1 ? "" : "s"} · {c.cadence.toLowerCase()}</div>
            </div>
            <StatusChip status={c.state === "active" ? "confirmed" : c.state === "scheduled" ? "info" : "draft"} size="sm" label={c.state[0].toUpperCase() + c.state.slice(1)} />
          </div>
        ))}
      </Card>
      {a && <CampaignBuilder c={a} viewAs={viewAs} />}
    </div>
  );
};

const CampaignBuilder = ({ c, viewAs }) => (
  <Card>
    <div style={{ display: "flex", justifyContent: "space-between", alignItems: "start", marginBottom: 14, gap: 10 }}>
      <div>
        <div style={{ ...m8c_over, marginBottom: 4 }}>Campaign</div>
        <div style={{ fontSize: 18, fontWeight: 500 }}>{c.name}</div>
        <div style={{ ...m8c_meta, marginTop: 4 }}>{c.desc}</div>
      </div>
      <div style={{ display: "flex", gap: 6 }}>
        <Btn size="sm" kind="ghost">History</Btn>
        <Btn size="sm" disabled={viewAs === "readonly"} icon={IconEdit}>Edit</Btn>
        <Toggle checked={c.state === "active"} onChange={() => {}} />
      </div>
    </div>

    <div style={{ display: "grid", gridTemplateColumns: "repeat(4, 1fr)", gap: 10, marginBottom: 20 }}>
      <Kpi label="Sent (30d)" value={c.sent30d.toLocaleString()} tone="up" icon={IconMail} />
      <Kpi label="Opens" value={c.opens.toLocaleString()} delta={c.sent30d ? Math.round((c.opens / c.sent30d) * 100) + "%" : "—"} tone="up" icon={IconCheck} />
      <Kpi label="Replies" value={c.replies.toString()} tone="neutral" icon={IconMsg} />
      <Kpi label="Suppressed" value={(c.opt_outs + c.blocked).toString()} delta={`${c.opt_outs} opt · ${c.blocked} blocked`} tone="neutral" icon={IconShield} />
    </div>

    <div style={{ display: "grid", gridTemplateColumns: "120px 1fr", gap: 14 }}>
      <div style={{ ...m8c_over }}>Trigger</div>
      <div style={{ fontSize: 13 }}>{c.trigger}</div>
      <div style={{ ...m8c_over }}>Audience</div>
      <div style={{ fontSize: 13 }}>{c.audience}</div>
      <div style={{ ...m8c_over }}>Cadence</div>
      <div style={{ fontSize: 13 }}>{c.cadence}</div>
    </div>

    <div style={{ ...m8c_over, margin: "20px 0 10px" }}>Steps</div>
    <div style={{ position: "relative" }}>
      {c.steps.map((s, i) => (
        <div key={i} style={{ display: "grid", gridTemplateColumns: "100px 36px 1fr", gap: 14, padding: "12px 0", borderBottom: i === c.steps.length - 1 ? "none" : "1px dashed var(--border-soft)", alignItems: "start" }}>
          <div style={{ display: "flex", alignItems: "center", gap: 6 }}>
            <span style={{ width: 24, height: 24, borderRadius: 999, background: s.channel === "sms" ? "var(--iris-100)" : "var(--coral-100)", color: s.channel === "sms" ? "var(--iris-600)" : "var(--coral-700)", display: "flex", alignItems: "center", justifyContent: "center" }}>
              {s.channel === "sms" ? <IconMsg size={12} /> : <IconMail size={12} />}
            </span>
            <span style={{ fontSize: 12, fontWeight: 500, fontFamily: "var(--font-display)", letterSpacing: "-0.01em" }}>{s.offset}</span>
          </div>
          <span style={{ fontSize: 11, color: "var(--fg-3)", textAlign: "center", paddingTop: 4 }}>→</span>
          <div>
            <code style={{ fontFamily: "var(--font-mono)", fontSize: 12, color: "var(--ink)" }}>{s.template}</code>
            <div style={{ ...m8c_meta, marginTop: 4 }}>Stop: {s.stop}</div>
          </div>
        </div>
      ))}
      <Btn size="sm" kind="ghost" icon={IconPlus} disabled={viewAs === "readonly"} style={{ marginTop: 8 }}>Add step</Btn>
    </div>

    <div style={{ ...m8c_over, margin: "20px 0 10px" }}>Always-applied stop conditions</div>
    <div style={{ display: "flex", flexDirection: "column", gap: 6 }}>
      {[
        "Volunteer becomes red-flagged or yellow-flagged",
        "Volunteer status changes to deceased / inactive",
        "Volunteer revokes channel consent (email or SMS)",
        "Volunteer marks the campaign 'not interested'",
        "Hard bounce on email (or carrier-permanent on SMS)",
      ].map(s => (
        <div key={s} style={{ display: "flex", gap: 8, padding: "8px 10px", borderRadius: 8, background: "var(--paper-deep)", color: "var(--fg-2)", fontSize: 12, alignItems: "center" }}>
          <IconShield size={14} style={{ color: "var(--fg-3)" }} />{s}
        </div>
      ))}
    </div>
  </Card>
);

// ============================================================
// HELP NEEDED OUTREACH
// ============================================================
const HelpNeeded = () => (
  <>
    <p style={{ fontSize: 13, color: "var(--fg-2)", marginBottom: 18, maxWidth: 720 }}>
      Help Needed broadcasts target eligible volunteers near an opportunity. Eligibility uses training, certification, background-check state, geography, history, and stated preferences. Suppression rules apply at send.
    </p>
    <div style={{ display: "grid", gridTemplateColumns: "minmax(0, 1.4fr) minmax(280px, 1fr)", gap: 14 }}>
      <Card>
        <div style={{ ...m8c_over, marginBottom: 10 }}>Opportunity needing volunteers</div>
        <Card style={{ background: "var(--paper)", marginBottom: 14 }}>
          <div style={{ display: "flex", justifyContent: "space-between", alignItems: "baseline", marginBottom: 6 }}>
            <div>
              <div style={{ fontSize: 15, fontWeight: 500 }}>Lake Pueblo trash haul</div>
              <div style={{ ...m8c_meta, marginTop: 3 }}>Sat, Jun 28 · 8:00 – 11:30 am · Lake Pueblo SP · south boat ramp</div>
            </div>
            <StatusChip status="info" size="sm" label="6 of 10 confirmed" />
          </div>
          <div style={{ display: "flex", gap: 10, marginTop: 12 }}>
            <span style={{ fontSize: 11, padding: "3px 9px", borderRadius: 999, background: "var(--paper-deep)", color: "var(--fg-1)" }}>Role: General volunteer</span>
            <span style={{ fontSize: 11, padding: "3px 9px", borderRadius: 999, background: "var(--paper-deep)", color: "var(--fg-1)" }}>Bring: gloves, water</span>
            <span style={{ fontSize: 11, padding: "3px 9px", borderRadius: 999, background: "var(--paper-deep)", color: "var(--fg-1)" }}>No special training required</span>
          </div>
        </Card>

        <div style={{ ...m8c_over, marginBottom: 8 }}>Eligibility-aware recommendations</div>
        <div style={{ ...m8c_meta, marginBottom: 12 }}>Top 8 of 142 eligible volunteers, ranked by fit. Eligibility uses approved roles, history, geography, preferences, training, certification, and screening state. Anyone not eligible, opted out, suppressed, deceased, or red-flagged is excluded.</div>
        <Card padded={false}>
          <div style={{ display: "grid", gridTemplateColumns: "30px minmax(180px, 1.4fr) 1fr 110px 110px", gap: 12, padding: "11px 16px", fontSize: 11, letterSpacing: "0.1em", textTransform: "uppercase", color: "var(--fg-3)", borderBottom: "1px solid var(--border)" }}>
            <Checkbox checked={true} onChange={() => {}} aria-label="Select all" />
            <span>Volunteer</span><span>Why this volunteer</span><span>Distance</span><span>Last shift</span>
          </div>
          {[
            { v: VOLUNTEERS[3], why: "4 past Lake Pueblo trips · 'within 25mi' preference matches", dist: "3 mi", last: "Apr 27" },
            { v: VOLUNTEERS[0], why: "3 trail-crew shifts at neighboring sites · weekend availability", dist: "62 mi", last: "May 17" },
            { v: VOLUNTEERS[1], why: "Recent 100-hr milestone · prefers cleanup/conservation work", dist: "84 mi", last: "May 10" },
            { v: VOLUNTEERS[5], why: "Stated interest in 'cleanup' · attended 2 of last 3 Lake Pueblo events", dist: "12 mi", last: "Apr 13" },
            { v: VOLUNTEERS[6], why: "Eligible · available Saturdays · 'within 50mi' preference", dist: "48 mi", last: "May 4" },
            { v: VOLUNTEERS[7], why: "Eligible · 'within 100mi' preference · 8 prior cleanups", dist: "92 mi", last: "Apr 20" },
          ].map((r, i, arr) => (
            <div key={i} style={{ display: "grid", gridTemplateColumns: "30px minmax(180px, 1.4fr) 1fr 110px 110px", gap: 12, padding: "11px 16px", alignItems: "center", borderBottom: i === arr.length - 1 ? "none" : "1px solid var(--border-soft)", fontSize: 12 }}>
              <Checkbox checked={true} onChange={() => {}} />
              <div style={{ display: "flex", gap: 10, alignItems: "center" }}><Avatar {...r.v} /><span style={{ fontSize: 13, fontWeight: 500 }}>{r.v.name}</span></div>
              <span style={{ color: "var(--fg-2)", lineHeight: 1.4 }}>{r.why}</span>
              <span style={{ color: "var(--fg-2)" }}>{r.dist}</span>
              <span style={{ ...m8c_meta }}>{r.last}</span>
            </div>
          ))}
        </Card>

        <div style={{ ...m8c_over, margin: "20px 0 8px" }}>Message preview</div>
        <Card style={{ background: "var(--paper)" }}>
          <div style={{ fontSize: 13, lineHeight: 1.6, color: "var(--ink)" }}>
            <div style={{ fontWeight: 500 }}>Subject: Help needed Saturday at Lake Pueblo</div>
            <div style={{ marginTop: 10 }}>Hi {`{{first_name}}`},</div>
            <div style={{ marginTop: 8 }}>We're short a few volunteers for the Lake Pueblo trash haul on Sat Jun 28 (8–11:30 am). Based on your past trips, it's a good fit — it's only {`{{distance_mi}}`} miles from you and your stated preference is cleanup work.</div>
            <div style={{ marginTop: 8 }}>If you're in, just RSVP from your dashboard. Otherwise no worries, more coming up in July.</div>
            <div style={{ marginTop: 8 }}>— Priya, NE Region</div>
          </div>
        </Card>
      </Card>
      <Card>
        <div style={{ ...m8c_over, marginBottom: 12 }}>Audience funnel</div>
        <CountRow label="Approved for this role" n={324} />
        <CountRow label="Within geo preference" n={186} />
        <CountRow label="Available Saturday morning" n={142} />
        <CountRow label="− opted out of Help Needed" n={18} sub />
        <CountRow label="− already on this roster" n={6} sub />
        <CountRow label="− red/yellow flagged" n={4} sub />
        <CountRow label="− deceased / inactive" n={2} sub />
        <CountRow label="Final eligible" n={112} bold />
        <div style={{ ...m8c_over, margin: "16px 0 8px" }}>Ranking factors</div>
        <ul style={{ margin: 0, paddingLeft: 18, fontSize: 12, color: "var(--fg-2)", lineHeight: 1.7 }}>
          <li>Distance from event location</li>
          <li>Stated interest tags (cleanup, conservation)</li>
          <li>History at the same site / same kind of event</li>
          <li>Availability for stated day-of-week</li>
          <li>Training, certification, screening currency</li>
        </ul>
        <div style={{ marginTop: 14, padding: 10, background: "var(--paper-deep)", borderRadius: 8, fontSize: 11, color: "var(--fg-2)", lineHeight: 1.5 }}>
          Ranking does not use AI. Recommendations don't reveal private contact info or notes about other volunteers.
        </div>
        <Btn icon={IconMail} style={{ marginTop: 14, width: "100%" }}>Send to top 8 selected</Btn>
        <Btn kind="secondary" style={{ marginTop: 8, width: "100%" }}>Send to all 112 eligible</Btn>
      </Card>
    </div>
  </>
);

const CountRow = ({ label, n, sub, bold }) => (
  <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", padding: "6px 0", borderBottom: bold ? "none" : "1px dashed var(--border-soft)" }}>
    <span style={{ fontSize: 12, color: sub ? "var(--fg-3)" : "var(--ink)" }}>{label}</span>
    <span style={{ fontSize: bold ? 16 : 13, fontWeight: bold ? 500 : 400, color: bold ? "var(--ink)" : sub ? "var(--crimson-600)" : "var(--ink)", fontVariantNumeric: "tabular-nums" }}>
      {sub ? "−" : ""}{n.toLocaleString()}
    </span>
  </div>
);

// ============================================================
// SEND HEALTH (FR15 + FR7)
// ============================================================
const SendHealth = () => (
  <>
    <div style={{ display: "grid", gridTemplateColumns: "minmax(0, 1.4fr) minmax(280px, 1fr)", gap: 14, marginBottom: 22 }}>
      <Card>
        <div style={{ ...m8c_over, marginBottom: 12 }}>Outbound queues</div>
        <QueueRow channel="Email · transactional" inflight={0} pending={0} cap="500 / sec" health="healthy" sub="DKIM/SPF/DMARC pass · 2 warm pools" />
        <QueueRow channel="Email · marketing"     inflight={0} pending={1} cap="200 / sec" health="healthy" sub="Bounce 0.6% (last 30d, well under 2%)" />
        <QueueRow channel="SMS · transactional"  inflight={0} pending={0} cap="60 / sec"  health="healthy" sub="10DLC throughput · 18 senders" />
        <QueueRow channel="SMS · marketing"      inflight={0} pending={0} cap="20 / sec"  health="healthy" sub="Carrier throttled at peak hours" />
        <div style={{ ...m8c_over, margin: "16px 0 8px" }}>Caps & splitting</div>
        <SR label="BCC cap" v="450 (default) · automatic splitting" />
        <SR label="Daily email cap" v="50,000 (cur tier)" />
        <SR label="Daily SMS cap" v="3,000 (carrier)" />
        <SR label="Throttle ramp on new templates" v="100 / 500 / 2,000 over 24h" />
        <SR label="Dedupe window" v="48h (no duplicate per recipient per content hash)" />
      </Card>
      <Card>
        <div style={{ ...m8c_over, marginBottom: 12 }}>Tenant master switch</div>
        <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", padding: "14px 16px", background: "var(--sage-100)", color: "var(--sage-700)", borderRadius: 12, marginBottom: 12 }}>
          <div>
            <div style={{ fontSize: 16, fontWeight: 500, color: "var(--ink)" }}>Production · ON</div>
            <div style={{ ...m8c_meta, color: "var(--sage-700)" }}>Real volunteers receive sends. Last changed: Mar 22, 2026 by Aliyah Chen.</div>
          </div>
          <Toggle checked={true} onChange={() => {}} />
        </div>
        <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", padding: "14px 16px", background: "var(--amber-100)", color: "var(--amber-600)", borderRadius: 12, marginBottom: 12 }}>
          <div>
            <div style={{ fontSize: 16, fontWeight: 500, color: "var(--ink)" }}>Sandbox · OFF</div>
            <div style={{ ...m8c_meta, color: "var(--amber-600)" }}>Outbound is captured to an in-app inbox. No real delivery. Volunteer addresses are masked.</div>
          </div>
          <Toggle checked={false} onChange={() => {}} />
        </div>
        <div style={{ padding: 10, background: "var(--paper-deep)", borderRadius: 8, fontSize: 11, color: "var(--fg-2)", lineHeight: 1.5 }}>
          Switching the master kill is logged in the audit timeline with actor, prior state, reason. Sandbox cannot accept production API keys.
        </div>
      </Card>
    </div>

    <SectionHead title="Recent send jobs" />
    <Card padded={false}>
      <div style={{ display: "grid", gridTemplateColumns: "minmax(220px, 1.6fr) 100px 110px 110px 100px 130px 36px", gap: 12, padding: "12px 16px", fontSize: 11, letterSpacing: "0.1em", textTransform: "uppercase", color: "var(--fg-3)", borderBottom: "1px solid var(--border)" }}>
        <span>Send</span><span>Channel</span><span>Recipients</span><span>Delivered</span><span>Bounce</span><span>State</span><span />
      </div>
      {[
        { what: "Statewide newsletter · May 2026", ch: "email", rec: 4127, supp: 143, sent: 3984, del: 3962, b: 22, state: "Sent", auditRef: "nl-send-2026-05-05-1a" },
        { what: "Cherry Creek weather cancellation", ch: "sms", rec: 28, supp: 0, sent: 28, del: 28, b: 0, state: "Sent", auditRef: "sms-broadcast-2026-06-13-2k" },
        { what: "Hunter ed class reminders (Jul 5)",  ch: "sms", rec: 28, supp: 0, sent: 28, del: 28, b: 0, state: "Sent", auditRef: "sms-hed-2026-07-04-9w" },
        { what: "Thank-you · Boyd Lake Jun 7",        ch: "email", rec: 18, supp: 0, sent: 18, del: 18, b: 0, state: "Sent", auditRef: "em-ty-2026-06-07-1k" },
        { what: "Camp host arrival reminder",          ch: "sms",  rec: 84, supp: 2, sent: 82, del: 82, b: 0, state: "Sent", auditRef: "sms-camp-2026-05-22-6c" },
        { what: "Statewide newsletter · June 2026",   ch: "email", rec: 968, supp: 56, sent: 0, del: 0, b: 0, state: "Scheduled · Jun 2", auditRef: "nl-send-2026-06-02-7x" },
        { what: "Inactive re-engagement (draft)",     ch: "email", rec: 642, supp: 142, sent: 0, del: 0, b: 0, state: "Draft · pending approval", auditRef: "—" },
      ].map((j, i, arr) => (
        <div key={i} style={{ display: "grid", gridTemplateColumns: "minmax(220px, 1.6fr) 100px 110px 110px 100px 130px 36px", gap: 12, padding: "13px 16px", alignItems: "center", borderBottom: i === arr.length - 1 ? "none" : "1px solid var(--border-soft)" }}>
          <div>
            <div style={{ fontSize: 13, fontWeight: 500 }}>{j.what}</div>
            <code style={{ ...m8c_meta, fontFamily: "var(--font-mono)" }}>{j.auditRef}</code>
          </div>
          <span style={{ fontSize: 10, padding: "2px 7px", borderRadius: 999, background: j.ch === "sms" ? "var(--iris-100)" : "var(--paper-deep)", color: j.ch === "sms" ? "var(--iris-600)" : "var(--fg-1)", fontWeight: 500, textTransform: "uppercase", letterSpacing: "0.06em", textAlign: "center" }}>{j.ch}</span>
          <div style={{ fontSize: 12, fontVariantNumeric: "tabular-nums" }}>
            <div style={{ color: "var(--ink)", fontWeight: 500 }}>{j.rec.toLocaleString()}</div>
            {j.supp > 0 && <div style={{ ...m8c_meta }}>{j.supp} suppressed</div>}
          </div>
          <span style={{ fontSize: 13, fontVariantNumeric: "tabular-nums" }}>{j.del ? j.del.toLocaleString() : "—"}</span>
          <span style={{ fontSize: 12, color: j.b > 0 ? "var(--crimson-600)" : "var(--fg-3)", fontVariantNumeric: "tabular-nums" }}>{j.b}</span>
          <span style={{ fontSize: 12 }}>{j.state}</span>
          <IconBtn icon={IconMore} size={28} />
        </div>
      ))}
    </Card>

    <SectionHead title="Deliverability · last 30 days" />
    <div style={{ display: "grid", gridTemplateColumns: "repeat(4, 1fr)", gap: 12 }}>
      <Card>
        <div style={{ ...m8c_over, marginBottom: 8 }}>Domain reputation</div>
        <div style={{ fontFamily: "var(--font-display)", fontSize: 32, color: "var(--ink)" }}>96<span style={{ fontSize: 14, color: "var(--fg-3)" }}> / 100</span></div>
        <div style={{ ...m8c_meta, marginTop: 4 }}>Postmaster: good · no warnings</div>
      </Card>
      <Card>
        <div style={{ ...m8c_over, marginBottom: 8 }}>Bounce rate</div>
        <div style={{ fontFamily: "var(--font-display)", fontSize: 32, color: "var(--ink)" }}>0.6<span style={{ fontSize: 14, color: "var(--fg-3)" }}> %</span></div>
        <div style={{ ...m8c_meta, marginTop: 4 }}>Threshold: pause if > 2%</div>
      </Card>
      <Card>
        <div style={{ ...m8c_over, marginBottom: 8 }}>Spam complaints</div>
        <div style={{ fontFamily: "var(--font-display)", fontSize: 32, color: "var(--ink)" }}>0.01<span style={{ fontSize: 14, color: "var(--fg-3)" }}> %</span></div>
        <div style={{ ...m8c_meta, marginTop: 4 }}>4 marks · all auto-suppressed</div>
      </Card>
      <Card>
        <div style={{ ...m8c_over, marginBottom: 8 }}>SMS delivery</div>
        <div style={{ fontFamily: "var(--font-display)", fontSize: 32, color: "var(--ink)" }}>99.9<span style={{ fontSize: 14, color: "var(--fg-3)" }}> %</span></div>
        <div style={{ ...m8c_meta, marginTop: 4 }}>2 carrier-permanent failures</div>
      </Card>
    </div>
  </>
);

const QueueRow = ({ channel, inflight, pending, cap, health, sub }) => (
  <div style={{ display: "grid", gridTemplateColumns: "200px 80px 80px 130px 80px 1fr", gap: 14, padding: "10px 0", borderBottom: "1px dashed var(--border-soft)", alignItems: "center", fontSize: 12 }}>
    <div style={{ fontWeight: 500 }}>{channel}</div>
    <div><span style={{ ...m8c_meta }}>in-flight</span><div style={{ fontVariantNumeric: "tabular-nums", color: "var(--ink)", fontSize: 13 }}>{inflight}</div></div>
    <div><span style={{ ...m8c_meta }}>queued</span><div style={{ fontVariantNumeric: "tabular-nums", color: "var(--ink)", fontSize: 13 }}>{pending}</div></div>
    <div><span style={{ ...m8c_meta }}>cap</span><div style={{ fontFamily: "var(--font-mono)", color: "var(--fg-1)", fontSize: 12 }}>{cap}</div></div>
    <StatusChip status="confirmed" size="sm" label={health} />
    <span style={{ ...m8c_meta }}>{sub}</span>
  </div>
);

// ============================================================
// SUPPRESSIONS
// ============================================================
const Suppressions = () => {
  const [cat, setCat] = useC("all");
  const data = [
    { v: VOLUNTEERS[7] || VOLUNTEERS[0], reason: "Email · unsubscribed (Apr 22, 2026)", channel: "email", category: "unsub", source: "Footer link · statewide May newsletter", state: "honored" },
    { v: VOLUNTEERS[4] || VOLUNTEERS[0], reason: "Email · hard bounce (Mar 14, 2026)", channel: "email", category: "bounce", source: "Permanent · mailbox does not exist", state: "honored" },
    { v: VOLUNTEERS[3], reason: "SMS · STOP keyword (Jun 13, 2026)", channel: "sms", category: "unsub", source: "Weather cancellation broadcast", state: "honored" },
    { v: VOLUNTEERS[6] || VOLUNTEERS[0], reason: "Email · marked as spam (May 8, 2026)", channel: "email", category: "complaint", source: "May newsletter", state: "honored" },
    { v: VOLUNTEERS[5], reason: "Email + SMS · red-flagged (May 1, 2026)", channel: "all", category: "flag", source: "Manual · pending HR review", state: "active" },
    { v: VOLUNTEERS[2], reason: "Email + SMS · communication consent revoked (Apr 9, 2026)", channel: "all", category: "consent", source: "Volunteer self-service preferences", state: "honored" },
    { v: VOLUNTEERS[0], reason: "Email · soft-bounce (3 in 30d, escalating)", channel: "email", category: "bounce", source: "Provider 4xx · last 3 sends", state: "watch" },
  ];
  const filtered = cat === "all" ? data : data.filter(d => d.category === cat);
  return (
    <>
      <p style={{ fontSize: 13, color: "var(--fg-2)", marginBottom: 14, maxWidth: 720 }}>
        Suppression list across all channels. Entries here are excluded from sends. Recovery requires an authorized re-consent path — volunteers cannot be silently re-subscribed.
      </p>
      <div style={{ display: "flex", gap: 8, marginBottom: 14, alignItems: "center", flexWrap: "wrap" }}>
        {[
          { id: "all", t: "All", n: 612 },
          { id: "unsub", t: "Unsubscribes", n: 184 },
          { id: "bounce", t: "Hard bounces", n: 412 },
          { id: "complaint", t: "Spam complaints", n: 14 },
          { id: "flag", t: "Red/yellow flag", n: 16 },
          { id: "consent", t: "Consent revoked", n: 38 },
        ].map(c => (
          <button key={c.id} onClick={() => setCat(c.id)} style={{
            padding: "7px 11px", borderRadius: 999, fontSize: 12, fontWeight: 500, cursor: "pointer", fontFamily: "inherit",
            background: cat === c.id ? "var(--coral-100)" : "transparent",
            color: cat === c.id ? "var(--coral-700)" : "var(--fg-1)",
            border: "1px solid " + (cat === c.id ? "var(--coral-200)" : "var(--border)"),
          }}>{c.t} <span style={{ opacity: 0.65, marginLeft: 4, fontVariantNumeric: "tabular-nums" }}>{c.n}</span></button>
        ))}
        <div style={{ marginLeft: "auto", display: "flex", gap: 6 }}>
          <Btn size="sm" kind="ghost" icon={IconFilter}>More filters</Btn>
          <Btn size="sm" kind="secondary" icon={IconDownload}>Export</Btn>
        </div>
      </div>
      <Card padded={false}>
        <div style={{ display: "grid", gridTemplateColumns: "minmax(200px, 1.4fr) minmax(220px, 1.6fr) 90px 110px 36px", gap: 12, padding: "12px 16px", fontSize: 11, letterSpacing: "0.1em", textTransform: "uppercase", color: "var(--fg-3)", borderBottom: "1px solid var(--border)" }}>
          <span>Volunteer</span><span>Reason</span><span>Channel</span><span>State</span><span />
        </div>
        {filtered.map((s, i, arr) => (
          <div key={i} style={{ display: "grid", gridTemplateColumns: "minmax(200px, 1.4fr) minmax(220px, 1.6fr) 90px 110px 36px", gap: 12, padding: "13px 16px", alignItems: "center", borderBottom: i === arr.length - 1 ? "none" : "1px solid var(--border-soft)" }}>
            <div style={{ display: "flex", gap: 10, alignItems: "center" }}><Avatar {...s.v} /><div><div style={{ fontSize: 13, fontWeight: 500 }}>{s.v.name}</div><div style={{ ...m8c_meta }}>{s.v.site}</div></div></div>
            <div><div style={{ fontSize: 13 }}>{s.reason}</div><div style={{ ...m8c_meta, marginTop: 2 }}>{s.source}</div></div>
            <span style={{ fontSize: 11, padding: "2px 8px", borderRadius: 999, background: s.channel === "sms" ? "var(--iris-100)" : s.channel === "email" ? "var(--paper-deep)" : "var(--amber-100)", color: s.channel === "sms" ? "var(--iris-600)" : s.channel === "email" ? "var(--fg-1)" : "var(--amber-600)", fontWeight: 500, textTransform: "uppercase", letterSpacing: "0.06em", textAlign: "center" }}>{s.channel === "all" ? "All" : s.channel.toUpperCase()}</span>
            <StatusChip status={s.state === "honored" ? "confirmed" : s.state === "watch" ? "info" : "pending"} size="sm" label={s.state[0].toUpperCase() + s.state.slice(1)} />
            <IconBtn icon={IconMore} size={28} />
          </div>
        ))}
      </Card>
      <div style={{ marginTop: 14, padding: 12, background: "var(--paper-soft)", borderRadius: 10, border: "1px solid var(--border-soft)", fontSize: 12, color: "var(--fg-2)", lineHeight: 1.5 }}>
        <IconShield size={14} style={{ verticalAlign: "middle", marginRight: 6, color: "var(--fg-3)" }} />
        Suppression list is the source of truth: sends are blocked even if a segment rule would otherwise include the recipient. Recovery paths (re-verify email, re-confirm SMS opt-in) are role-gated and audit-logged.
      </div>
    </>
  );
};

// ============================================================
// AUDIT TIMELINE
// ============================================================
const AuditTimeline = () => (
  <>
    <p style={{ fontSize: 13, color: "var(--fg-2)", marginBottom: 14, maxWidth: 720 }}>
      Immutable, searchable record of every communication-related action across the tenant. Includes sender, recipient set, content snapshot link, send result, and result mutations (bounce, unsub, reply).
    </p>
    <div style={{ display: "flex", gap: 8, marginBottom: 14, alignItems: "center" }}>
      <Input placeholder="Search audit log…" style={{ flex: 1, maxWidth: 360 }} />
      <Select defaultValue="14" options={[{ value: "1", label: "Last 24 hours" }, { value: "7", label: "Last 7 days" }, { value: "14", label: "Last 14 days" }, { value: "30", label: "Last 30 days" }, { value: "90", label: "Last 90 days" }]} />
      <Select defaultValue="all" options={[{ value: "all", label: "All event types" }, { value: "send", label: "Sends" }, { value: "draft", label: "Drafts / edits" }, { value: "consent", label: "Consent changes" }, { value: "admin", label: "Admin actions" }]} />
      <div style={{ marginLeft: "auto" }}><Btn size="sm" kind="secondary" icon={IconDownload}>Export</Btn></div>
    </div>
    <Card padded={false}>
      {AUDIT_EVENTS.map((a, i, arr) => (
        <div key={i} style={{ display: "grid", gridTemplateColumns: "60px 1fr 200px 180px 110px", gap: 14, padding: "14px 18px", alignItems: "start", borderBottom: i === arr.length - 1 ? "none" : "1px solid var(--border-soft)" }}>
          <div style={{ width: 28, height: 28, borderRadius: 999, background: bgFor(a.k), color: fgFor(a.k), display: "flex", alignItems: "center", justifyContent: "center", flexShrink: 0 }}>
            {iconFor(a.k)}
          </div>
          <div>
            <div style={{ display: "flex", gap: 8, alignItems: "baseline", marginBottom: 2 }}>
              <span style={{ fontSize: 13, fontWeight: 500 }}>{a.who}</span>
              <span style={{ ...m8c_meta }}>· {a.t}</span>
            </div>
            <div style={{ fontSize: 13, color: "var(--fg-1)", marginBottom: 2 }}>{a.what}</div>
            {a.note && <div style={{ ...m8c_meta, lineHeight: 1.4 }}>{a.note}</div>}
          </div>
          <div style={{ fontSize: 11, color: "var(--fg-3)" }}>
            {a.target && <div>Target: <span style={{ color: "var(--ink)" }}>{a.target}</span></div>}
            {a.channel && <div>Channel: {a.channel}</div>}
          </div>
          <code style={{ fontFamily: "var(--font-mono)", fontSize: 11, color: "var(--fg-3)" }}>{a.ref}</code>
          <span style={{ fontSize: 11, padding: "3px 8px", borderRadius: 999, background: "var(--iris-100)", color: "var(--iris-600)", fontWeight: 500, textAlign: "center", height: "fit-content" }}>Immutable</span>
        </div>
      ))}
    </Card>
  </>
);

const AUDIT_EVENTS = [
  { k: "send",   who: "System", what: "Hunter ed class -24h SMS dispatched", note: "28 recipients · 0 blocked · template tpl-sms-hed · v1", target: "Jul 5 hunter ed class", channel: "SMS", ref: "sms-hed-2026-07-04-9w", t: "Today · 9:00 am" },
  { k: "send",   who: "System", what: "Camp host arrival reminder dispatched", note: "82 of 84 sent · 2 suppressed (consent revoked) · template tpl-ch-arrival · v1", target: "Camp host campaign", channel: "SMS", ref: "sms-camp-2026-05-22-6c", t: "Today · 8:00 am" },
  { k: "reply",  who: "Maya Okonkwo", what: "Inbound SMS reply routed to originator", note: "'Got it, thank you...' → Priya Sandoval", target: "Driver's check thread", channel: "SMS", ref: "sms-in-okonkwo-3f", t: "Today · 11:42 am" },
  { k: "unsub",  who: "Rae Kowalski", what: "STOP keyword recorded · SMS channel suppressed", note: "Future SMS to this number suppressed until re-consent", target: "Volunteer record", channel: "SMS", ref: "supp-sms-kowalski-2x", t: "Yest · 4:42 pm" },
  { k: "block",  who: "System", what: "Send blocked · recipient red-flagged", note: "Sender saw warning before confirming. Send suppressed, content captured in audit.", target: "Robert Fischer", channel: "SMS", ref: "sms-blocked-fischer-2x", t: "Tue · 11:30 am" },
  { k: "draft",  who: "Priya Sandoval", what: "Edited statewide newsletter (June) draft", note: "Hero copy · added 'See what's needed' CTA · 6 edits", target: "nl-statewide-jun26", channel: "Email", ref: "edit-nl-jun-1c", t: "Mon · 4:18 pm" },
  { k: "approve",who: "Aliyah Chen", what: "Approved newsletter for send", note: "Statewide June 2026 · scheduled Jun 2 9:00 am MT", target: "nl-statewide-jun26", channel: "Email", ref: "appr-nl-jun-1d", t: "Mon · 5:02 pm" },
  { k: "send",   who: "Priya Sandoval", what: "Weather cancellation broadcast dispatched", note: "28 recipients · 1 already opted out · routed replies to Priya", target: "Cherry Creek Jun 14 roster", channel: "SMS", ref: "sms-broadcast-2026-06-13-2k", t: "Sat · 4:18 pm" },
  { k: "admin",  who: "Aliyah Chen", what: "Master switch verified · production ON", note: "Quarterly verification · no change", target: "Tenant master switch", channel: "—", ref: "tenant-mskey-q2-2026", t: "May 1 · 9:00 am" },
  { k: "send",   who: "System", what: "Statewide May 2026 newsletter dispatched", note: "3,984 delivered · 143 suppressed · 22 bounces · template tpl-stm · v8", target: "All active statewide", channel: "Email", ref: "nl-send-2026-05-05-1a", t: "May 5 · 9:00 am" },
];

const iconFor = (k) => {
  if (k === "send")    return <IconMail size={14} />;
  if (k === "reply")   return <IconMsg size={14} />;
  if (k === "unsub" || k === "block") return <IconShield size={14} />;
  if (k === "draft")   return <IconEdit size={14} />;
  if (k === "approve") return <IconCheck size={14} />;
  return <IconBell size={14} />;
};
const bgFor = (k) => {
  if (k === "send" || k === "approve") return "var(--sage-100)";
  if (k === "reply") return "var(--iris-100)";
  if (k === "unsub" || k === "block")  return "var(--amber-100)";
  if (k === "draft") return "var(--paper-deep)";
  return "var(--paper-deep)";
};
const fgFor = (k) => {
  if (k === "send" || k === "approve") return "var(--sage-700)";
  if (k === "reply") return "var(--iris-600)";
  if (k === "unsub" || k === "block")  return "var(--amber-600)";
  return "var(--fg-2)";
};

// ============================================================
// SENDER IDENTITY (FR18)
// ============================================================
const SenderIdentity = () => (
  <>
    <p style={{ fontSize: 13, color: "var(--fg-2)", marginBottom: 14, maxWidth: 720 }}>
      Per-site and per-program sender identities. Authorized staff can send from these identities; unauthorized staff cannot spoof another sender. Reply-to routes to the sender or to a monitored central inbox.
    </p>

    <Card padded={false} style={{ marginBottom: 18 }}>
      <div style={{ display: "grid", gridTemplateColumns: "minmax(200px, 1.4fr) minmax(220px, 1.6fr) minmax(160px, 1fr) 130px 100px 36px", gap: 12, padding: "12px 16px", fontSize: 11, letterSpacing: "0.1em", textTransform: "uppercase", color: "var(--fg-3)", borderBottom: "1px solid var(--border)" }}>
        <span>Display name</span><span>Email address</span><span>Reply-to</span><span>Authorized staff</span><span>SMS sender</span><span />
      </div>
      {[
        { name: "CPW Volunteer Program",     em: "volunteers@cpw.state.co.us", reply: "Central inbox",       staff: "Universal admins (4)",         sms: "+1 720-555-1100", site: "All regions" },
        { name: "Priya Sandoval · NE Region", em: "priya.s@cpw.state.co.us",    reply: "Sender (Priya)",       staff: "Priya Sandoval only",          sms: "+1 720-555-1101", site: "Northeast" },
        { name: "Marcus Chen · NE Region",   em: "marcus.c@cpw.state.co.us",   reply: "Sender (Marcus)",      staff: "Marcus Chen only",             sms: "+1 720-555-1102", site: "Northeast" },
        { name: "Aliyah Chen · Camp Program",em: "camp.host@cpw.state.co.us",  reply: "Sender (Aliyah)",      staff: "Aliyah Chen + delegates (2)",  sms: "+1 720-555-1110", site: "Statewide camp" },
        { name: "CPW Hunter Outreach",       em: "hunter.ed@cpw.state.co.us",  reply: "Hunter ed team",       staff: "Hunter ed coordinators (3)",   sms: "+1 720-555-1120", site: "Statewide" },
      ].map((s, i, arr) => (
        <div key={i} style={{ display: "grid", gridTemplateColumns: "minmax(200px, 1.4fr) minmax(220px, 1.6fr) minmax(160px, 1fr) 130px 100px 36px", gap: 12, padding: "13px 16px", alignItems: "center", borderBottom: i === arr.length - 1 ? "none" : "1px solid var(--border-soft)" }}>
          <div>
            <div style={{ fontSize: 13, fontWeight: 500 }}>{s.name}</div>
            <div style={{ ...m8c_meta, marginTop: 2 }}>{s.site}</div>
          </div>
          <code style={{ fontFamily: "var(--font-mono)", fontSize: 12, color: "var(--fg-1)" }}>{s.em}</code>
          <span style={{ fontSize: 12 }}>{s.reply}</span>
          <span style={{ fontSize: 12, color: "var(--fg-2)" }}>{s.staff}</span>
          <code style={{ fontFamily: "var(--font-mono)", fontSize: 12, color: "var(--fg-1)" }}>{s.sms}</code>
          <IconBtn icon={IconMore} size={28} />
        </div>
      ))}
    </Card>

    <div style={{ display: "grid", gridTemplateColumns: "repeat(2, 1fr)", gap: 14 }}>
      <Card>
        <div style={{ ...m8c_over, marginBottom: 12 }}>Reply-to behavior</div>
        <ul style={{ margin: 0, paddingLeft: 18, fontSize: 13, color: "var(--fg-1)", lineHeight: 1.7 }}>
          <li>For staff-identity sends, replies route back to the originating sender.</li>
          <li>For automated/system identities (e.g. CPW Volunteer Program), replies route to the monitored central inbox and are assigned by triage.</li>
          <li>SMS replies follow the same routing. The sender's 10DLC number is reserved per identity.</li>
          <li>If a sender loses their role, future replies fall through to the central inbox.</li>
          <li>Unauthorized staff can't compose under another sender's identity. Delegated send requires explicit grant.</li>
        </ul>
      </Card>
      <Card>
        <div style={{ ...m8c_over, marginBottom: 12 }}>Domain authentication</div>
        <SR label="Sending domain" v="cpw.state.co.us" />
        <SR label="SPF" v="pass (state.co.us policy)" />
        <SR label="DKIM" v="pass (2048-bit, rotated quarterly)" />
        <SR label="DMARC" v="reject (p=reject, pct=100)" />
        <SR label="BIMI logo" v="verified (CPW elk mark)" />
        <SR label="Warm-up pool" v="2 IPs · 14-day warm cycle on new pool" />
      </Card>
    </div>
  </>
);

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