// ===== m8-newsletters.jsx =====
// M8 · Newsletters — replaces window.OrgNewsletters
//   FR1  newsletter authoring (email-native, blocks, preview, test-send, schedule)
//   FR2  audience targeting + saved segments + suppression preview
//   FR3  template library with versioning + immutable sent snapshots
//   FR4  personalization tokens with fallback handling
//   FR5  preview/test-send across representative recipients
//   FR6  consent/suppression/red-flag hard gate
//   FR14 collaborative drafts with autosave + ownership
//   FR15 send safety: caps, 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,
  VOLUNTEERS,
} = window;
const { useState: useN, useMemo: useNM, useRef: useNR, useEffect: useNE } = React;

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

// ============================================================
// SEEDS
// ============================================================
const NEWSLETTERS = [
  {
    id: "nl-statewide-may26",
    name: "Statewide volunteer newsletter · May 2026",
    cadence: "Monthly · 1st Tue",
    sender: "CPW Volunteer Program",
    replyTo: "volunteers@cpw.state.co.us",
    audience: "All active volunteers statewide",
    audienceCount: 4127,
    suppressed: 143,
    eligible: 3984,
    sent: 3984, delivered: 3962, opens: 1514, clicks: 184, bounces: 22, unsubs: 8, complaints: 0,
    status: "sent",
    sentAt: "May 5, 2026 · 9:00 am MT",
    ownedBy: "Priya Sandoval",
    snapshot: "v3 — locked at send",
    auditRef: "nl-send-2026-05-05-1a",
  },
  {
    id: "nl-ne-region-may26",
    name: "Northeast regional digest · May 2026",
    cadence: "Monthly · 1st Fri",
    sender: "Priya Sandoval · NE Region",
    replyTo: "priya.s@cpw.state.co.us",
    audience: "NE region active volunteers",
    audienceCount: 968,
    suppressed: 28,
    eligible: 940,
    sent: 940, delivered: 936, opens: 412, clicks: 71, bounces: 4, unsubs: 1, complaints: 0,
    status: "sent",
    sentAt: "May 1, 2026 · 8:00 am MT",
    ownedBy: "Priya Sandoval",
    snapshot: "v6 — locked at send",
    auditRef: "nl-send-2026-05-01-9c",
  },
  {
    id: "nl-camphost-preseason",
    name: "Camp host pre-season · onboarding sequence",
    cadence: "Triggered · April 1 each year",
    sender: "Aliyah Chen · Camping team",
    replyTo: "camp.host@cpw.state.co.us",
    audience: "Approved camp hosts · status = trainee or active",
    audienceCount: 84,
    suppressed: 2,
    eligible: 82,
    sent: 82, delivered: 82, opens: 76, clicks: 41, bounces: 0, unsubs: 0, complaints: 0,
    status: "sent",
    sentAt: "Apr 1, 2026 · 7:00 am MT",
    ownedBy: "Aliyah Chen",
    snapshot: "v2 — locked at send",
    auditRef: "nl-send-2026-04-01-3f",
  },
  {
    id: "nl-hunter-ed-es",
    name: "Hunter ed instructors · español · Q2",
    cadence: "Quarterly",
    sender: "CPW Hunter Outreach",
    replyTo: "hunter.ed@cpw.state.co.us",
    audience: "Hunter ed instructors · language preference = Spanish",
    audienceCount: 38,
    suppressed: 1,
    eligible: 37,
    sent: 0, delivered: 0, opens: 0, clicks: 0, bounces: 0, unsubs: 0, complaints: 0,
    status: "scheduled",
    sentAt: "Scheduled · Jun 3, 2026 · 8:00 am MT",
    ownedBy: "Marcus Chen",
    snapshot: "v1 · locks on send",
  },
  {
    id: "nl-statewide-jun26",
    name: "Statewide volunteer newsletter · June 2026",
    cadence: "Monthly · 1st Tue",
    sender: "CPW Volunteer Program",
    replyTo: "volunteers@cpw.state.co.us",
    audience: "All active volunteers statewide",
    audienceCount: 4127,
    suppressed: 0,
    eligible: 0,
    sent: 0, delivered: 0, opens: 0, clicks: 0, bounces: 0, unsubs: 0, complaints: 0,
    status: "draft",
    sentAt: "—",
    ownedBy: "Priya Sandoval · co-edited by Marcus Chen",
    snapshot: "Draft v4 · autosaved 2 min ago",
  },
  {
    id: "nl-inactive-relapse",
    name: "Re-engagement · lapsed >12 months",
    cadence: "Quarterly campaign",
    sender: "CPW Volunteer Program",
    replyTo: "volunteers@cpw.state.co.us",
    audience: "Inactive volunteers · last hour >12 mo · not deceased · not red-flagged",
    audienceCount: 642,
    suppressed: 142,
    eligible: 500,
    sent: 0, delivered: 0, opens: 0, clicks: 0, bounces: 0, unsubs: 0, complaints: 0,
    status: "draft",
    sentAt: "—",
    ownedBy: "Priya Sandoval",
    snapshot: "Draft v1 · last edited yesterday",
  },
];

const TEMPLATES = [
  { id: "tpl-statewide", name: "Statewide monthly · CPW master", v: "v8", updated: "Apr 22, 2026", uses: 7 },
  { id: "tpl-regional", name: "Regional digest · 3-column", v: "v3", updated: "Mar 10, 2026", uses: 18 },
  { id: "tpl-camphost", name: "Camp host onboarding", v: "v2", updated: "Mar 28, 2026", uses: 4 },
  { id: "tpl-help-needed", name: "Help Needed · simple CTA", v: "v5", updated: "May 3, 2026", uses: 22 },
  { id: "tpl-reengage", name: "Re-engagement (warm)", v: "v1", updated: "May 12, 2026", uses: 0 },
  { id: "tpl-spanish", name: "Statewide · español", v: "v2", updated: "Apr 4, 2026", uses: 3 },
];

// ============================================================
// ROOT
// ============================================================
const OrgNewsletters = ({ go }) => {
  const [view, setView] = useN("list");      // list | detail | compose
  const [activeId, setActiveId] = useN(null);
  const [composeFrom, setComposeFrom] = useN(null);

  const active = NEWSLETTERS.find(n => n.id === activeId);

  if (view === "compose") {
    return <NewsletterComposer
      base={NEWSLETTERS.find(n => n.id === composeFrom) || null}
      onClose={() => { setView("list"); setComposeFrom(null); }} />;
  }
  if (view === "detail" && active) {
    return <NewsletterDetail n={active}
      onBack={() => { setView("list"); setActiveId(null); }}
      onEdit={() => { setComposeFrom(active.id); setView("compose"); }} />;
  }

  return <NewsletterList
    onOpen={(id) => { setActiveId(id); setView("detail"); }}
    onNew={() => { setComposeFrom(null); setView("compose"); }} />;
};

// ============================================================
// LIST + OVERVIEW
// ============================================================
const NewsletterList = ({ onOpen, onNew }) => {
  const [tab, setTab] = useN("all");
  return (
    <>
      <TopBar
        title="Newsletters"
        subtitle="Email-native sends · drafts, schedules, sent history · last 30 days · 7,962 delivered · 38% avg open"
        primary={<Btn icon={IconPlus} onClick={onNew}>New newsletter</Btn>}
        secondary={<Btn kind="secondary" icon={IconEdit}>Templates</Btn>}
      />
      <div style={{ flex: 1, overflow: "auto", padding: "20px 32px 56px" }}>
        <div style={{ display: "grid", gridTemplateColumns: "repeat(4, 1fr)", gap: 14, marginBottom: 24 }}>
          <Kpi label="Delivered (30d)" value="7,962" delta="across 5 sends" tone="up" icon={IconMail} />
          <Kpi label="Avg open rate" value="38%" delta="+2pp vs prior 30d" tone="up" icon={IconCheck} />
          <Kpi label="Click-thru" value="4.6%" delta="primary CTA: 'See what's needed'" tone="up" icon={IconArrow} />
          <Kpi label="Unsubscribes" value="9" delta="0.1% · all honored on next send" tone="neutral" icon={IconX} />
        </div>

        <Tabs active={tab} onChange={setTab} tabs={[
          { id: "all",       label: "All",        count: NEWSLETTERS.length },
          { id: "draft",     label: "Drafts",     count: NEWSLETTERS.filter(n => n.status === "draft").length },
          { id: "scheduled", label: "Scheduled",  count: NEWSLETTERS.filter(n => n.status === "scheduled").length },
          { id: "sent",      label: "Sent",       count: NEWSLETTERS.filter(n => n.status === "sent").length },
          { id: "templates", label: "Templates",  count: TEMPLATES.length },
        ]} />

        {tab === "templates" ? <TemplatesGrid /> : (
          <Card padded={false}>
            <div style={{ display: "grid", gridTemplateColumns: "minmax(240px, 2fr) 130px 120px 120px 110px 110px 36px", gap: 14, padding: "12px 18px", fontSize: 11, letterSpacing: "0.1em", textTransform: "uppercase", color: "var(--fg-3)", borderBottom: "1px solid var(--border)" }}>
              <span>Newsletter</span><span>Audience</span><span>Sent / scheduled</span><span>Open</span><span>Click</span><span>State</span><span />
            </div>
            {NEWSLETTERS.filter(n => tab === "all" ? true : n.status === tab).map((n, i, arr) => (
              <div key={n.id} onClick={() => onOpen(n.id)} style={{
                display: "grid", gridTemplateColumns: "minmax(240px, 2fr) 130px 120px 120px 110px 110px 36px", gap: 14,
                padding: "16px 18px", alignItems: "center",
                borderBottom: i === arr.length - 1 ? "none" : "1px solid var(--border-soft)",
                cursor: "pointer",
              }}>
                <div>
                  <div style={{ fontSize: 14, fontWeight: 500, color: "var(--ink)" }}>{n.name}</div>
                  <div style={{ ...m8n_meta, marginTop: 4, lineHeight: 1.4 }}>{n.cadence} · owner {n.ownedBy.split(" · ")[0]}</div>
                </div>
                <div style={{ fontSize: 12, color: "var(--fg-2)" }}>
                  <div style={{ fontVariantNumeric: "tabular-nums", color: "var(--ink)", fontWeight: 500 }}>{n.audienceCount.toLocaleString()}</div>
                  {n.suppressed > 0 && <div style={{ ...m8n_meta, marginTop: 2 }}>{n.suppressed} suppressed</div>}
                </div>
                <div style={{ fontSize: 12, color: "var(--fg-2)", lineHeight: 1.4 }}>{n.sentAt}</div>
                <div style={{ fontSize: 13, fontVariantNumeric: "tabular-nums", color: "var(--ink)" }}>
                  {n.status === "sent" ? `${Math.round((n.opens / n.delivered) * 100)}%` : "—"}
                  {n.status === "sent" && <div style={{ ...m8n_meta }}>{n.opens.toLocaleString()} opens</div>}
                </div>
                <div style={{ fontSize: 13, fontVariantNumeric: "tabular-nums", color: "var(--ink)" }}>
                  {n.status === "sent" ? `${((n.clicks / n.delivered) * 100).toFixed(1)}%` : "—"}
                  {n.status === "sent" && <div style={{ ...m8n_meta }}>{n.clicks} clicks</div>}
                </div>
                <StatusChip
                  status={n.status === "sent" ? "confirmed" : n.status === "scheduled" ? "info" : "draft"}
                  size="sm"
                  label={n.status === "sent" ? "Sent" : n.status === "scheduled" ? "Scheduled" : "Draft"} />
                <IconBtn icon={IconMore} size={28} />
              </div>
            ))}
          </Card>
        )}
      </div>
    </>
  );
};

const TemplatesGrid = () => (
  <div style={{ display: "grid", gridTemplateColumns: "repeat(3, 1fr)", gap: 14 }}>
    {TEMPLATES.map(t => (
      <Card key={t.id}>
        <div style={{ aspectRatio: "16 / 10", borderRadius: 10, background: "var(--paper-deep)", border: "1px solid var(--border-soft)", marginBottom: 12, display: "flex", flexDirection: "column", padding: 14 }}>
          <div style={{ height: 18, width: "60%", background: "var(--ink)", borderRadius: 4, marginBottom: 8 }} />
          <div style={{ height: 10, width: "80%", background: "var(--stone-200)", borderRadius: 3, marginBottom: 4 }} />
          <div style={{ height: 10, width: "70%", background: "var(--stone-200)", borderRadius: 3, marginBottom: 4 }} />
          <div style={{ height: 10, width: "50%", background: "var(--stone-200)", borderRadius: 3, marginBottom: 10 }} />
          <div style={{ height: 30, width: "40%", background: "var(--coral-600)", borderRadius: 6, marginTop: "auto" }} />
        </div>
        <div style={{ display: "flex", justifyContent: "space-between", alignItems: "baseline", marginBottom: 6 }}>
          <span style={{ fontSize: 13, fontWeight: 500 }}>{t.name}</span>
          <span style={{ fontSize: 10, padding: "2px 7px", borderRadius: 999, background: "var(--paper-deep)", color: "var(--fg-2)", fontWeight: 500, fontFamily: "var(--font-mono)" }}>{t.v}</span>
        </div>
        <div style={{ ...m8n_meta, marginBottom: 12 }}>Used {t.uses} times · updated {t.updated}</div>
        <div style={{ display: "flex", gap: 6 }}>
          <Btn size="sm" kind="secondary">Preview</Btn>
          <Btn size="sm" iconRight={IconArrow}>Start from this</Btn>
        </div>
      </Card>
    ))}
  </div>
);

// ============================================================
// DETAIL (post-send view)
// ============================================================
const NewsletterDetail = ({ n, onBack, onEdit }) => {
  const [tab, setTab] = useN("results");
  const isSent = n.status === "sent";
  return (
    <>
      <TopBar
        title={n.name}
        breadcrumb={["Newsletters", n.name]} onBack={onBack}
        subtitle={`${n.audience} · ${n.sentAt} · snapshot ${n.snapshot}`}
        primary={isSent ? <Btn icon={IconPlus} onClick={onEdit}>Duplicate</Btn> : <Btn icon={IconEdit} onClick={onEdit}>Edit draft</Btn>}
        secondary={<Btn kind="secondary" icon={IconDownload}>Export results</Btn>}
      />
      <div style={{ flex: 1, overflow: "auto", padding: "20px 32px 56px" }}>
        {isSent && (
          <div style={{ display: "grid", gridTemplateColumns: "repeat(6, 1fr)", gap: 12, marginBottom: 24 }}>
            <Kpi label="Sent" value={n.sent.toLocaleString()} delta="post-suppression" tone="neutral" icon={IconMail} />
            <Kpi label="Delivered" value={n.delivered.toLocaleString()} delta={`${((n.delivered / n.sent) * 100).toFixed(1)}%`} tone="up" icon={IconCheck} />
            <Kpi label="Opens" value={n.opens.toLocaleString()} delta={`${Math.round((n.opens / n.delivered) * 100)}%`} tone="up" icon={IconUsers} />
            <Kpi label="Clicks" value={n.clicks.toLocaleString()} delta={`${((n.clicks / n.delivered) * 100).toFixed(1)}%`} tone="up" icon={IconArrow} />
            <Kpi label="Bounces" value={n.bounces.toString()} delta={`${((n.bounces / n.sent) * 100).toFixed(2)}%`} tone={n.bounces > 0 ? "down" : "neutral"} icon={IconX} />
            <Kpi label="Unsubs" value={n.unsubs.toString()} delta="suppressed for next send" tone="neutral" icon={IconBell} />
          </div>
        )}

        <Tabs active={tab} onChange={setTab} tabs={[
          { id: "results",  label: isSent ? "Results" : "Plan" },
          { id: "content",  label: "Content snapshot" },
          { id: "audience", label: "Audience" },
          { id: "delivery", label: "Delivery & audit" },
          { id: "settings", label: "Settings" },
        ]} />

        {tab === "results"  && (isSent ? <NlResults n={n} /> : <NlPlan n={n} />)}
        {tab === "content"  && <NlContentSnapshot n={n} />}
        {tab === "audience" && <NlAudience n={n} />}
        {tab === "delivery" && <NlDelivery n={n} />}
        {tab === "settings" && <NlSettings n={n} />}
      </div>
    </>
  );
};

const NlResults = ({ n }) => (
  <>
    <div style={{ display: "grid", gridTemplateColumns: "minmax(0, 1.4fr) minmax(280px, 1fr)", gap: 14 }}>
      <Card>
        <div style={{ ...m8n_over, marginBottom: 14 }}>Engagement over 7 days</div>
        <div style={{ display: "flex", gap: 6, height: 140, alignItems: "end", marginBottom: 12 }}>
          {[18, 32, 28, 14, 8, 5, 3].map((h, i) => (
            <div key={i} style={{ flex: 1, display: "flex", flexDirection: "column", alignItems: "center", gap: 4 }}>
              <div style={{ width: "100%", height: h * 3.6, background: "var(--coral-600)", borderRadius: "4px 4px 0 0" }} />
              <span style={{ ...m8n_meta }}>{["D0", "D1", "D2", "D3", "D4", "D5", "D6"][i]}</span>
            </div>
          ))}
        </div>
        <div style={{ ...m8n_over, margin: "18px 0 10px" }}>Top clicks</div>
        {[
          { url: "https://volunteer.cpw.state.co.us/opportunities", clicks: 84, label: "'See what's needed' (primary CTA)" },
          { url: "https://volunteer.cpw.state.co.us/account/hours/add", clicks: 42, label: "'Add hours' link" },
          { url: "https://cpw.state.co.us/learn/Pages/Hunter-Education.aspx", clicks: 28, label: "Hunter ed feature link" },
          { url: "https://volunteer.cpw.state.co.us/account/profile", clicks: 18, label: "'Update profile' footer link" },
          { url: "mailto:volunteers@cpw.state.co.us", clicks: 12, label: "Footer email" },
        ].map((c, i) => (
          <div key={i} style={{ display: "grid", gridTemplateColumns: "1fr 60px", padding: "9px 0", gap: 10, borderTop: "1px dashed var(--border-soft)", fontSize: 12 }}>
            <div style={{ minWidth: 0 }}>
              <div style={{ color: "var(--ink)", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{c.label}</div>
              <div style={{ ...m8n_meta, fontFamily: "var(--font-mono)", marginTop: 2, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{c.url}</div>
            </div>
            <div style={{ fontVariantNumeric: "tabular-nums", textAlign: "right", color: "var(--ink)", fontWeight: 500 }}>{c.clicks}</div>
          </div>
        ))}
      </Card>
      <Card>
        <div style={{ ...m8n_over, marginBottom: 14 }}>Funnel</div>
        {[
          { l: "Eligible", v: n.eligible, pct: 100 },
          { l: "Sent", v: n.sent, pct: (n.sent / n.eligible) * 100 },
          { l: "Delivered", v: n.delivered, pct: (n.delivered / n.eligible) * 100 },
          { l: "Opened", v: n.opens, pct: (n.opens / n.eligible) * 100 },
          { l: "Clicked", v: n.clicks, pct: (n.clicks / n.eligible) * 100 },
        ].map((s, i) => (
          <div key={s.l} style={{ marginBottom: 11 }}>
            <div style={{ display: "flex", justifyContent: "space-between", fontSize: 12, marginBottom: 4 }}>
              <span style={{ color: "var(--fg-1)" }}>{s.l}</span>
              <span style={{ color: "var(--fg-3)", fontVariantNumeric: "tabular-nums" }}>{s.v.toLocaleString()}</span>
            </div>
            <div style={{ height: 8, background: "var(--paper-deep)", borderRadius: 4, overflow: "hidden" }}>
              <div style={{ width: `${s.pct}%`, height: "100%", background: "var(--coral-600)" }} />
            </div>
          </div>
        ))}
        <div style={{ ...m8n_over, margin: "18px 0 8px" }}>Suppression breakdown</div>
        <div style={{ display: "flex", flexDirection: "column", gap: 6 }}>
          {[
            { l: "Communication opt-out", v: 62 },
            { l: "Hard-bounced previously", v: 38 },
            { l: "Red/yellow flag", v: 22 },
            { l: "Deceased / inactive", v: 14 },
            { l: "Channel consent revoked", v: 7 },
          ].map(s => (
            <div key={s.l} style={{ display: "flex", justifyContent: "space-between", fontSize: 12, color: "var(--fg-2)" }}>
              <span>· {s.l}</span><span style={{ fontVariantNumeric: "tabular-nums" }}>{s.v}</span>
            </div>
          ))}
        </div>
      </Card>
    </div>

    <SectionHead title="Recipient sample" />
    <Card padded={false}>
      <div style={{ display: "grid", gridTemplateColumns: "minmax(200px, 1.4fr) 1fr 120px 110px 130px 110px 110px", gap: 14, padding: "12px 18px", fontSize: 11, letterSpacing: "0.1em", textTransform: "uppercase", color: "var(--fg-3)", borderBottom: "1px solid var(--border)" }}>
        <span>Volunteer</span><span>Site</span><span>Sent</span><span>Delivered</span><span>Opened</span><span>Clicked</span><span>State</span>
      </div>
      {VOLUNTEERS.slice(0, 6).map((v, i, arr) => {
        const opened = i % 3 !== 2;
        const clicked = i < 2;
        return (
          <div key={v.id} style={{ display: "grid", gridTemplateColumns: "minmax(200px, 1.4fr) 1fr 120px 110px 130px 110px 110px", gap: 14, padding: "13px 18px", alignItems: "center", borderBottom: i === arr.length - 1 ? "none" : "1px solid var(--border-soft)", fontSize: 12 }}>
            <div style={{ display: "flex", gap: 10, alignItems: "center" }}><Avatar {...v} /><span style={{ fontWeight: 500, color: "var(--ink)" }}>{v.name}</span></div>
            <span style={{ color: "var(--fg-2)" }}>{v.site}</span>
            <span style={{ ...m8n_meta }}>9:00:0{i + 2}</span>
            <span style={{ ...m8n_meta }}>9:00:0{i + 3}</span>
            <span style={{ ...m8n_meta }}>{opened ? `9:1${i + 3}` : "—"}</span>
            <span style={{ ...m8n_meta }}>{clicked ? `9:1${i + 4}` : "—"}</span>
            <StatusChip status={clicked ? "confirmed" : opened ? "info" : "pending"} size="sm" label={clicked ? "Clicked" : opened ? "Opened" : "Delivered"} />
          </div>
        );
      })}
    </Card>
  </>
);

const NlPlan = ({ n }) => (
  <Card>
    <div style={{ ...m8n_over, marginBottom: 10 }}>Send plan</div>
    <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 10, marginBottom: 16 }}>
      <Field label="Eligible audience"><span style={{ fontFamily: "var(--font-display)", fontSize: 30 }}>{n.eligible.toLocaleString()}</span></Field>
      <Field label="Suppressed"><span style={{ fontFamily: "var(--font-display)", fontSize: 30 }}>{n.suppressed.toLocaleString()}</span></Field>
    </div>
    <p style={{ fontSize: 13, color: "var(--fg-2)", lineHeight: 1.5 }}>This newsletter is {n.status}. {n.status === "scheduled" ? "It will send at the scheduled time. Permissions and suppressions are re-evaluated at send." : "Resume the composer to edit, preview, and schedule."}</p>
  </Card>
);

// ============================================================
// CONTENT SNAPSHOT — actual rendered newsletter
// ============================================================
const NlContentSnapshot = ({ n }) => (
  <>
    <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: 12 }}>
      <div style={{ ...m8n_over }}>What was sent · {n.snapshot}</div>
      <div style={{ display: "flex", gap: 6 }}>
        <Btn size="sm" kind="ghost">View HTML</Btn>
        <Btn size="sm" kind="ghost">View plain text</Btn>
        <Btn size="sm" kind="secondary" icon={IconDownload}>Download .eml</Btn>
      </div>
    </div>
    <div style={{ display: "grid", gridTemplateColumns: "minmax(0, 1.4fr) minmax(280px, 1fr)", gap: 14 }}>
      <Card padded={false}>
        <div style={{ background: "var(--paper-deep)", padding: "10px 16px", borderBottom: "1px solid var(--border)", display: "flex", justifyContent: "space-between", fontSize: 11, color: "var(--fg-3)" }}>
          <span>cpw.state.co.us · seen by recipient</span>
          <span style={{ fontFamily: "var(--font-mono)" }}>HTML · 240 KB</span>
        </div>
        <RenderedNewsletter n={n} />
      </Card>
      <Card>
        <div style={{ ...m8n_over, marginBottom: 12 }}>Token resolution · sample recipient</div>
        <div style={{ display: "flex", gap: 10, alignItems: "center", marginBottom: 14, padding: 10, background: "var(--paper-deep)", borderRadius: 8 }}>
          <Avatar {...VOLUNTEERS[0]} />
          <div>
            <div style={{ fontSize: 13, fontWeight: 500 }}>{VOLUNTEERS[0].name}</div>
            <div style={{ ...m8n_meta }}>Boyd Lake SP · NE region</div>
          </div>
        </div>
        {[
          { t: "{{first_name}}", v: "Sasha" },
          { t: "{{anniversary}}", v: "Mar 14 (8 years)" },
          { t: "{{ytd_hours}}", v: "42" },
          { t: "{{rolling_12_hours}}", v: "118" },
          { t: "{{lifetime_hours}}", v: "1,284" },
          { t: "{{help_needed_14d}}", v: "3 nearby opportunities" },
          { t: "{{profile_url}}", v: "vol.cpw.../v-arenas" },
          { t: "{{sender_signature}}", v: "Priya Sandoval, NE Region" },
        ].map(t => (
          <div key={t.t} style={{ display: "grid", gridTemplateColumns: "1fr 1fr", padding: "7px 0", borderTop: "1px dashed var(--border-soft)", fontSize: 12 }}>
            <code style={{ fontFamily: "var(--font-mono)", color: "var(--coral-700)" }}>{t.t}</code>
            <span style={{ color: "var(--fg-1)", textAlign: "right" }}>{t.v}</span>
          </div>
        ))}
        <div style={{ marginTop: 14, padding: 10, background: "var(--sage-100)", color: "var(--sage-700)", borderRadius: 8, fontSize: 11, lineHeight: 1.5 }}>
          All tokens resolved. No fallbacks used. Send-time gate passed.
        </div>
      </Card>
    </div>
  </>
);

const RenderedNewsletter = ({ n }) => (
  <div style={{ background: "#FFFFFF", padding: 0, fontFamily: "Georgia, 'Times New Roman', serif", maxWidth: 600, margin: "0 auto", border: "none" }}>
    {/* email header */}
    <div style={{ background: "var(--ink)", color: "var(--paper)", padding: "26px 32px" }}>
      <div style={{ fontFamily: "var(--font-display)", fontSize: 26, letterSpacing: "-0.01em" }}>Colorado Parks &amp; Wildlife</div>
      <div style={{ fontSize: 12, opacity: 0.7, marginTop: 4, textTransform: "uppercase", letterSpacing: "0.1em" }}>Volunteer newsletter · May 2026</div>
    </div>
    {/* hero photo placeholder */}
    <div style={{ height: 220, background: "linear-gradient(135deg, var(--sage-700), var(--sage-500))", display: "flex", alignItems: "flex-end", padding: 18, color: "#FFFFFF" }}>
      <div>
        <div style={{ fontSize: 11, letterSpacing: "0.1em", textTransform: "uppercase", opacity: 0.85 }}>Spring trail crews · 1,284 hours so far</div>
        <div style={{ fontFamily: "var(--font-display)", fontSize: 26, lineHeight: 1.2, marginTop: 6 }}>Thank you for showing up — even when it was raining.</div>
      </div>
    </div>
    {/* body */}
    <div style={{ padding: "26px 32px", fontFamily: "Georgia, 'Times New Roman', serif", fontSize: 16, lineHeight: 1.55, color: "#1F1B16" }}>
      <p style={{ marginTop: 0 }}>Sasha,</p>
      <p>You've put in 42 hours this calendar year and 118 over the last twelve months — thank you. We've got a few things to share from the field this month.</p>
      <h3 style={{ fontFamily: "var(--font-sans)", fontSize: 14, letterSpacing: "0.06em", textTransform: "uppercase", marginTop: 28, marginBottom: 10, color: "var(--fg-3)" }}>Coming up near you</h3>
      <div style={{ background: "var(--paper-soft)", border: "1px solid var(--border-soft)", borderRadius: 10, padding: 14, marginBottom: 18 }}>
        <div style={{ fontWeight: 500 }}>Cherry Creek shoreline cleanup · Sat, Jun 14 · 9–11:30 am</div>
        <div style={{ fontSize: 13, color: "var(--fg-2)", marginTop: 4 }}>South swim beach · meet at the volunteer tent. Coffee provided.</div>
      </div>
      <div style={{ background: "var(--paper-soft)", border: "1px solid var(--border-soft)", borderRadius: 10, padding: 14, marginBottom: 18 }}>
        <div style={{ fontWeight: 500 }}>Boyd Lake trail crew · Sun, Jun 22 · 8 am – 1 pm</div>
        <div style={{ fontSize: 13, color: "var(--fg-2)", marginTop: 4 }}>Tools provided. Bring water and gloves.</div>
      </div>
      <a href="#" style={{ display: "inline-block", background: "var(--coral-600)", color: "#FFFFFF", padding: "12px 22px", borderRadius: 8, textDecoration: "none", fontFamily: "var(--font-sans)", fontWeight: 600, fontSize: 14 }}>See what's needed</a>

      <h3 style={{ fontFamily: "var(--font-sans)", fontSize: 14, letterSpacing: "0.06em", textTransform: "uppercase", marginTop: 32, marginBottom: 10, color: "var(--fg-3)" }}>Milestones this month</h3>
      <p>Three of our long-tenured volunteers crossed the 500-hour mark this spring. We'll celebrate them at the regional gathering on Jun 28.</p>
    </div>
    <div style={{ background: "var(--paper-deep)", padding: "20px 32px", fontSize: 12, color: "var(--fg-3)", fontFamily: "var(--font-sans)", lineHeight: 1.6 }}>
      <div>Sent by <strong>{n.sender}</strong> · reply to <a href={`mailto:${n.replyTo}`} style={{ color: "var(--coral-700)" }}>{n.replyTo}</a></div>
      <div style={{ marginTop: 6 }}>You're receiving this because you're an active CPW volunteer. <a href="#" style={{ color: "var(--coral-700)" }}>Manage preferences</a> · <a href="#" style={{ color: "var(--coral-700)" }}>Unsubscribe</a></div>
      <div style={{ marginTop: 6 }}>Colorado Parks &amp; Wildlife · 6060 Broadway, Denver CO 80216</div>
    </div>
  </div>
);

// ============================================================
// AUDIENCE TAB (post-send)
// ============================================================
const NlAudience = ({ n }) => (
  <>
    <div style={{ display: "grid", gridTemplateColumns: "minmax(0, 1.4fr) minmax(280px, 1fr)", gap: 14 }}>
      <Card>
        <div style={{ ...m8n_over, marginBottom: 12 }}>Targeting rules · locked at send</div>
        <div style={{ display: "flex", flexDirection: "column", gap: 8 }}>
          <RuleRow op="Include" text="Saved segment: All active CPW volunteers (CY 2026)" />
          <RuleRow op="Include" text="Communication preference: 'Monthly newsletter' = on" />
          <RuleRow op="Exclude" text="Status = deceased OR inactive" tone="warn" />
          <RuleRow op="Exclude" text="Red flag OR yellow flag" tone="warn" />
          <RuleRow op="Exclude" text="Email channel consent = revoked" tone="warn" />
          <RuleRow op="Exclude" text="Hard-bounced previously" tone="warn" />
          <RuleRow op="Exclude" text="Tag = newsletter-optout" tone="warn" />
        </div>
        <div style={{ marginTop: 14, padding: 10, background: "var(--paper-deep)", borderRadius: 8, fontSize: 11, color: "var(--fg-2)" }}>
          Audience rules and snapshot are immutable for this send. Recipients are not recomputed retroactively if the segment changes.
        </div>
      </Card>
      <Card>
        <div style={{ ...m8n_over, marginBottom: 12 }}>Audience funnel</div>
        <CountRow label="Match include rules" n={n.audienceCount} />
        <CountRow label="Removed — comm opt-out" n={62} sub />
        <CountRow label="Removed — hard-bounced" n={38} sub />
        <CountRow label="Removed — flag" n={22} sub />
        <CountRow label="Removed — deceased / inactive" n={14} sub />
        <CountRow label="Removed — channel revoked" n={7} sub />
        <CountRow label="Final eligible" n={n.eligible} bold />
        <div style={{ ...m8n_meta, marginTop: 10 }}>Suppression categories are visible to authorized staff. Per-recipient reasons appear in the audience CSV export.</div>
        <Btn size="sm" kind="secondary" icon={IconDownload} style={{ marginTop: 12 }}>Recipients CSV</Btn>
      </Card>
    </div>
  </>
);

const RuleRow = ({ op, text, tone }) => (
  <div style={{ display: "flex", alignItems: "center", gap: 10, padding: "9px 12px", borderRadius: 10, background: tone === "warn" ? "var(--amber-100)" : "var(--paper)", border: "1px solid " + (tone === "warn" ? "rgba(154,106,27,0.2)" : "var(--border-soft)") }}>
    <span style={{ fontSize: 10, padding: "2px 7px", borderRadius: 4, background: op === "Include" ? "var(--sage-100)" : "var(--crimson-100)", color: op === "Include" ? "var(--sage-700)" : "var(--crimson-600)", fontWeight: 500, textTransform: "uppercase", letterSpacing: "0.08em" }}>{op}</span>
    <span style={{ fontSize: 13, color: "var(--ink)" }}>{text}</span>
  </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>
);

// ============================================================
// DELIVERY & AUDIT TAB
// ============================================================
const NlDelivery = ({ n }) => (
  <>
    <div style={{ display: "grid", gridTemplateColumns: "minmax(0, 1.4fr) minmax(280px, 1fr)", gap: 14 }}>
      <Card>
        <div style={{ ...m8n_over, marginBottom: 12 }}>Send job · {n.auditRef || "pending"}</div>
        <table style={{ width: "100%", fontSize: 13, borderCollapse: "collapse" }}>
          <tbody>
            {[
              ["Sender", `${n.sender}`],
              ["Reply-to", n.replyTo],
              ["Subject", "Spring trail crews · 1,284 hours so far · what's coming up"],
              ["Preheader", "A field roundup, milestones, and what's near you."],
              ["From IP / pool", "outbound-1.cpw.state.co.us (warm pool)"],
              ["DKIM / SPF / DMARC", "pass · pass · pass"],
              ["Send mode", "Broadcast · split into 9 chunks of 450 BCC max"],
              ["Throttle", "120 emails / sec (provider cap 200)"],
              ["Master switch", "ON · sandbox masked recipients: 0"],
              ["Authored by", n.ownedBy],
              ["Locked snapshot", n.snapshot],
            ].map(([k, v]) => (
              <tr key={k}><td style={{ padding: "8px 0", color: "var(--fg-3)", width: 180, borderBottom: "1px dashed var(--border-soft)" }}>{k}</td><td style={{ padding: "8px 0", color: "var(--ink)", borderBottom: "1px dashed var(--border-soft)" }}>{v}</td></tr>
            ))}
          </tbody>
        </table>
      </Card>
      <Card>
        <div style={{ ...m8n_over, marginBottom: 12 }}>Audit timeline</div>
        {[
          { who: "Priya Sandoval", what: "Created draft", t: "Apr 28 · 10:14 am" },
          { who: "Marcus Chen",    what: "Co-edited · 6 edits", t: "Apr 29 · 2:02 pm" },
          { who: "Priya Sandoval", what: "Test-sent to self", t: "Apr 30 · 4:48 pm" },
          { who: "Priya Sandoval", what: "Test-sent to NE coordinators (3 people)", t: "May 1 · 9:12 am" },
          { who: "Priya Sandoval", what: "Scheduled send · May 5 9:00 am MT", t: "May 1 · 9:30 am" },
          { who: "Aliyah Chen", what: "Approved (tenant policy)", t: "May 1 · 11:14 am" },
          { who: "System",     what: "Re-checked permissions + suppression at send", t: "May 5 · 8:59 am" },
          { who: "System",     what: "Dispatched in 9 chunks · 3,984 delivered", t: "May 5 · 9:00–9:02 am" },
          { who: "System",     what: "Locked snapshot — content immutable", t: "May 5 · 9:00 am" },
        ].map((e, i, arr) => (
          <div key={i} style={{ padding: "10px 0", borderTop: i === 0 ? "none" : "1px dashed var(--border-soft)" }}>
            <div style={{ display: "flex", justifyContent: "space-between", fontSize: 12 }}>
              <span style={{ fontWeight: 500, color: "var(--ink)" }}>{e.who}</span>
              <span style={{ ...m8n_meta }}>{e.t}</span>
            </div>
            <div style={{ fontSize: 12, color: "var(--fg-2)", marginTop: 2 }}>{e.what}</div>
          </div>
        ))}
      </Card>
    </div>
  </>
);

const NlSettings = ({ n }) => (
  <Card>
    <Field label="Newsletter name"><Input defaultValue={n.name} /></Field>
    <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 14 }}>
      <Field label="Sender display name"><Input defaultValue={n.sender} /></Field>
      <Field label="Reply-to"><Input defaultValue={n.replyTo} /></Field>
      <Field label="Cadence"><Select defaultValue="monthly" options={[{ value: "manual", label: "Manual send" }, { value: "monthly", label: "Monthly" }, { value: "quarterly", label: "Quarterly" }, { value: "trigger", label: "Trigger-based" }]} /></Field>
      <Field label="Time zone"><Select defaultValue="America/Denver" options={["America/Denver", "America/New_York"]} /></Field>
    </div>
    <Field label="Owners + collaborators">
      <div style={{ display: "flex", gap: 6, flexWrap: "wrap" }}>
        <span style={{ fontSize: 12, padding: "5px 10px", borderRadius: 999, background: "var(--paper-deep)", color: "var(--fg-1)" }}>Priya Sandoval (owner)</span>
        <span style={{ fontSize: 12, padding: "5px 10px", borderRadius: 999, background: "var(--paper-deep)", color: "var(--fg-1)" }}>Marcus Chen (editor)</span>
        <Btn size="sm" kind="ghost" icon={IconPlus}>Add</Btn>
      </div>
    </Field>
  </Card>
);

// ============================================================
// COMPOSER — 6-step flow
// ============================================================
const NewsletterComposer = ({ base, onClose }) => {
  const [step, setStep] = useN(1);
  const [autosaved, setAutosaved] = useN("just now");

  const steps = ["Audience", "Content", "Personalization", "Pre-flight", "Schedule", "Sending"];

  useNE(() => {
    const i = setInterval(() => setAutosaved(["just now", "1 min ago", "2 min ago"][Math.floor(Math.random() * 3)]), 12000);
    return () => clearInterval(i);
  }, []);

  return (
    <>
      <TopBar
        title="New newsletter"
        breadcrumb={["Newsletters", "New"]} onBack={onClose}
        subtitle={`Step ${step} of 6 · ${steps[step - 1]} · autosaved ${autosaved} · co-edited by Marcus Chen`}
        primary={<Btn icon={IconCheck}>Save draft & close</Btn>}
        secondary={<Btn kind="secondary" icon={IconMail}>Send test</Btn>}
      />
      <div style={{ flex: 1, overflow: "auto", padding: "20px 32px 56px" }}>
        <ComposerSteps step={step} setStep={setStep} steps={steps} />

        {step === 1 && <Step1Audience />}
        {step === 2 && <Step2Content />}
        {step === 3 && <Step3Personalization />}
        {step === 4 && <Step4Preflight />}
        {step === 5 && <Step5Schedule />}
        {step === 6 && <Step6Result onClose={onClose} />}

        <div style={{ display: "flex", marginTop: 24, gap: 10 }}>
          {step > 1 && step < 6 && <Btn kind="ghost" icon={IconArrowL} onClick={() => setStep(step - 1)}>Back</Btn>}
          <div style={{ marginLeft: "auto", display: "flex", gap: 8 }}>
            {step < 5 && <Btn iconRight={IconArrow} onClick={() => setStep(step + 1)}>Continue</Btn>}
            {step === 5 && <Btn icon={IconCheck} onClick={() => setStep(6)}>Schedule & dispatch</Btn>}
            {step === 6 && <Btn icon={IconCheck} onClick={onClose}>Done</Btn>}
          </div>
        </div>
      </div>
    </>
  );
};

const ComposerSteps = ({ step, setStep, steps }) => (
  <div style={{ display: "flex", gap: 0, marginBottom: 22, padding: "8px 12px", background: "var(--paper-soft)", borderRadius: 12, border: "1px solid var(--border-soft)" }}>
    {steps.map((label, i) => {
      const n = i + 1;
      const done = n < step;
      const active = n === step;
      return (
        <button key={label} onClick={() => setStep(n)} style={{
          flex: 1, padding: "10px 8px", border: "none", background: "transparent",
          textAlign: "left", cursor: "pointer", fontFamily: "inherit",
          borderBottom: "2px solid " + (active ? "var(--coral-600)" : "transparent"),
          opacity: active || done ? 1 : 0.55,
        }}>
          <div style={{ display: "flex", gap: 8, alignItems: "center" }}>
            <span style={{
              width: 22, height: 22, borderRadius: 999, display: "flex", alignItems: "center", justifyContent: "center",
              background: done ? "var(--sage-700)" : active ? "var(--coral-600)" : "var(--paper-deep)",
              color: done || active ? "#FFFFFF" : "var(--fg-3)",
              fontSize: 11, fontWeight: 600,
            }}>{done ? "✓" : n}</span>
            <span style={{ fontSize: 12, fontWeight: 500, color: "var(--ink)" }}>{label}</span>
          </div>
        </button>
      );
    })}
  </div>
);

// --- Step 1: Audience ---
const Step1Audience = () => (
  <div style={{ display: "grid", gridTemplateColumns: "minmax(0, 1.4fr) minmax(280px, 1fr)", gap: 14 }}>
    <Card>
      <div style={{ ...m8n_over, marginBottom: 12 }}>Target audience</div>
      <Field label="Start with">
        <Select defaultValue="segment" options={[
          { value: "all", label: "All permitted volunteers" },
          { value: "segment", label: "Saved segment" },
          { value: "smart", label: "Smart list" },
          { value: "tag", label: "Tag combination" },
          { value: "csv", label: "Upload from CSV (scoped + suppression-checked)" },
        ]} />
      </Field>
      <Field label="Saved segment">
        <Select defaultValue="active-ne" options={[
          { value: "active-statewide", label: "All active CPW volunteers (statewide)" },
          { value: "active-ne", label: "Active volunteers · NE region" },
          { value: "ongoing", label: "Ongoing-role volunteers" },
          { value: "episodic", label: "One-time / episodic volunteers" },
          { value: "camphost", label: "Camp hosts · approved" },
          { value: "hunter-instr", label: "Hunter ed instructors" },
          { value: "es-pref", label: "Spanish language preference" },
        ]} />
      </Field>
      <div style={{ ...m8n_over, margin: "16px 0 10px" }}>Refine with rules</div>
      <div style={{ display: "flex", flexDirection: "column", gap: 8 }}>
        <RuleRow op="Include" text="Active or ongoing-role status" />
        <RuleRow op="Include" text="Rolling 12-month hours ≥ 1" />
        <RuleRow op="Include" text="Site IN [NE region]" />
        <RuleRow op="Exclude" text="Tag = newsletter-optout" tone="warn" />
        <Btn size="sm" kind="ghost" icon={IconPlus} style={{ alignSelf: "flex-start" }}>Add rule</Btn>
      </div>
      <div style={{ ...m8n_over, margin: "16px 0 10px" }}>Always applied</div>
      <div style={{ display: "flex", flexDirection: "column", gap: 6 }}>
        {[
          "Red / yellow flag",
          "Deceased / inactive",
          "Email channel consent revoked",
          "Hard-bounced previously",
          "Unsubscribed from newsletters",
        ].map(r => (
          <div key={r} style={{ display: "flex", gap: 10, padding: "8px 10px", borderRadius: 8, background: "var(--amber-100)", color: "var(--amber-600)", fontSize: 12, alignItems: "center" }}>
            <IconShield size={14} /> Excluded · {r}
          </div>
        ))}
      </div>
    </Card>
    <Card>
      <div style={{ ...m8n_over, marginBottom: 12 }}>Audience preview · live</div>
      <div style={{ display: "flex", alignItems: "baseline", gap: 10, marginBottom: 14 }}>
        <span style={{ fontFamily: "var(--font-display)", fontSize: 44, color: "var(--ink)", lineHeight: 1 }}>968</span>
        <span style={{ fontSize: 12, color: "var(--fg-3)" }}>final eligible recipients</span>
      </div>
      <CountRow label="Match include rules" n={1024} />
      <CountRow label="− comm opt-out" n={32} sub />
      <CountRow label="− hard-bounced" n={14} sub />
      <CountRow label="− flag" n={6} sub />
      <CountRow label="− deceased / inactive" n={4} sub />
      <CountRow label="Final eligible" n={968} bold />
      <div style={{ ...m8n_over, margin: "18px 0 8px" }}>Recipient mix</div>
      <div style={{ display: "flex", gap: 6, height: 12, borderRadius: 6, overflow: "hidden", marginBottom: 8 }}>
        <div style={{ flex: 4.2, background: "var(--coral-600)" }} title="Ongoing" />
        <div style={{ flex: 3.6, background: "var(--coral-400)" }} title="Episodic" />
        <div style={{ flex: 1.4, background: "var(--sage-500)" }} title="Camp hosts" />
        <div style={{ flex: 0.8, background: "var(--iris-500)" }} title="Hunter ed" />
      </div>
      <div style={{ display: "flex", gap: 10, flexWrap: "wrap", fontSize: 11, color: "var(--fg-2)" }}>
        <span><span style={{ display: "inline-block", width: 8, height: 8, background: "var(--coral-600)", marginRight: 4, borderRadius: 2 }} /> Ongoing 412</span>
        <span><span style={{ display: "inline-block", width: 8, height: 8, background: "var(--coral-400)", marginRight: 4, borderRadius: 2 }} /> Episodic 354</span>
        <span><span style={{ display: "inline-block", width: 8, height: 8, background: "var(--sage-500)", marginRight: 4, borderRadius: 2 }} /> Camp hosts 134</span>
        <span><span style={{ display: "inline-block", width: 8, height: 8, background: "var(--iris-500)", marginRight: 4, borderRadius: 2 }} /> Hunter ed 68</span>
      </div>
      <Btn size="sm" kind="secondary" icon={IconDownload} style={{ marginTop: 14 }}>Preview recipient list</Btn>
    </Card>
  </div>
);

// --- Step 2: Content ---
const Step2Content = () => {
  const [blocks] = useN([
    { t: "hero",    label: "Hero · spring trail crews" },
    { t: "text",    label: "Personal greeting + hours summary" },
    { t: "cards",   label: "Upcoming opportunities · 2 cards" },
    { t: "cta",     label: "CTA · See what's needed" },
    { t: "text",    label: "Milestones this month" },
    { t: "footer",  label: "Footer · preferences + unsubscribe" },
  ]);
  return (
    <div style={{ display: "grid", gridTemplateColumns: "240px minmax(0, 1.6fr) minmax(280px, 1fr)", gap: 14, alignItems: "start" }}>
      <Card padded={false}>
        <div style={{ padding: "12px 14px", borderBottom: "1px solid var(--border-soft)" }}>
          <div style={{ ...m8n_over }}>Add block</div>
        </div>
        {[
          { id: "hero", label: "Hero with image" },
          { id: "text", label: "Text block" },
          { id: "cards", label: "Card row" },
          { id: "cta", label: "Button CTA" },
          { id: "data", label: "Hours / progress block" },
          { id: "quote", label: "Pull quote" },
          { id: "footer", label: "Footer" },
          { id: "video", label: "Video (poster + link)" },
        ].map(b => (
          <div key={b.id} style={{ padding: "10px 14px", borderBottom: "1px solid var(--border-soft)", cursor: "pointer", display: "flex", alignItems: "center", gap: 8, fontSize: 12 }}>
            <IconPlus size={12} style={{ color: "var(--fg-3)" }} /> {b.label}
          </div>
        ))}
        <div style={{ padding: "12px 14px", borderTop: "1px solid var(--border)" }}>
          <div style={{ ...m8n_over, marginBottom: 8 }}>Brand</div>
          <div style={{ display: "flex", gap: 6 }}>
            {["var(--ink)", "var(--sage-700)", "var(--coral-600)", "var(--iris-500)"].map(c => (
              <div key={c} style={{ width: 22, height: 22, borderRadius: 6, background: c, border: "1px solid var(--border)" }} />
            ))}
          </div>
        </div>
      </Card>
      <Card padded={false}>
        <div style={{ padding: "10px 12px", background: "var(--paper-deep)", borderBottom: "1px solid var(--border)", display: "flex", gap: 10, alignItems: "center" }}>
          <Select defaultValue="email" options={[{ value: "email", label: "Email (600 px)" }, { value: "mobile", label: "Mobile (375 px)" }]} />
          <Input placeholder="Subject" defaultValue="Spring trail crews · 1,284 hours so far · what's coming up" style={{ flex: 1 }} />
          <Btn size="sm" kind="ghost">Plain text</Btn>
          <Btn size="sm" kind="ghost">Accessibility</Btn>
        </div>
        <div style={{ background: "var(--paper-deep)", padding: 20 }}>
          <RenderedNewsletter n={{ sender: "CPW Volunteer Program", replyTo: "volunteers@cpw.state.co.us" }} />
        </div>
      </Card>
      <Card>
        <div style={{ ...m8n_over, marginBottom: 12 }}>Blocks (drag to reorder)</div>
        <div style={{ display: "flex", flexDirection: "column", gap: 6 }}>
          {blocks.map((b, i) => (
            <div key={i} style={{ display: "flex", gap: 8, alignItems: "center", padding: "8px 10px", background: "var(--paper)", border: "1px solid var(--border-soft)", borderRadius: 8 }}>
              <span style={{ fontFamily: "var(--font-mono)", fontSize: 10, color: "var(--fg-3)", width: 16 }}>⋮⋮</span>
              <span style={{ fontSize: 12, flex: 1 }}>{b.label}</span>
              <IconBtn icon={IconEdit} size={24} />
            </div>
          ))}
        </div>
        <div style={{ ...m8n_over, margin: "16px 0 8px" }}>Accessibility</div>
        <CheckRow ok="ok" t="Headings in order (H1 → H3)" />
        <CheckRow ok="ok" t="All images have alt text" />
        <CheckRow ok="warn" t="Coral CTA · contrast 4.31 (passes AA)" />
        <CheckRow ok="ok" t="Mobile preview fits 320px" />
        <CheckRow ok="ok" t="Link text is descriptive (no 'click here')" />
      </Card>
    </div>
  );
};

const CheckRow = ({ ok, t }) => (
  <div style={{ display: "flex", gap: 10, padding: "7px 0", alignItems: "center" }}>
    <span style={{ width: 18, height: 18, borderRadius: 999, background: ok === "ok" ? "var(--sage-100)" : "var(--amber-100)", color: ok === "ok" ? "var(--sage-700)" : "var(--amber-600)", display: "flex", alignItems: "center", justifyContent: "center", fontSize: 10, fontWeight: 600 }}>{ok === "ok" ? "✓" : "!"}</span>
    <span style={{ fontSize: 12, color: ok === "ok" ? "var(--fg-1)" : "var(--amber-600)" }}>{t}</span>
  </div>
);

// --- Step 3: Personalization preview ---
const Step3Personalization = () => {
  const [recipient, setRecipient] = useN(VOLUNTEERS[0].id);
  const v = VOLUNTEERS.find(x => x.id === recipient) || VOLUNTEERS[0];
  return (
    <div style={{ display: "grid", gridTemplateColumns: "minmax(0, 1.4fr) minmax(280px, 1fr)", gap: 14 }}>
      <Card padded={false}>
        <div style={{ padding: "10px 12px", background: "var(--paper-deep)", borderBottom: "1px solid var(--border)", display: "flex", justifyContent: "space-between", alignItems: "center" }}>
          <div style={{ ...m8n_over }}>Preview as recipient</div>
          <Select value={recipient} onChange={(e) => setRecipient(e.target.value)}
            options={VOLUNTEERS.slice(0, 8).map(x => ({ value: x.id, label: x.name + " · " + x.site }))} />
        </div>
        <div style={{ background: "var(--paper-deep)", padding: 20 }}>
          <RenderedNewsletter n={{ sender: "CPW Volunteer Program", replyTo: "volunteers@cpw.state.co.us" }} />
        </div>
      </Card>
      <Card>
        <div style={{ ...m8n_over, marginBottom: 12 }}>Token resolution</div>
        {[
          { t: "{{first_name}}", v: v.name.split(" ")[0], state: "ok" },
          { t: "{{anniversary}}", v: `${v.joined}`, state: "ok" },
          { t: "{{ytd_hours}}", v: v.ytdHours, state: "ok" },
          { t: "{{rolling_12_hours}}", v: v.last12moHours, state: "ok" },
          { t: "{{lifetime_hours}}", v: v.lifetimeHours.toLocaleString(), state: "ok" },
          { t: "{{help_needed_14d}}", v: "3 nearby opportunities", state: "ok" },
          { t: "{{help_needed_30d}}", v: "7 nearby opportunities", state: "ok" },
          { t: "{{site_label}}", v: v.site, state: "ok" },
          { t: "{{profile_url}}", v: "vol.cpw.../" + v.id, state: "ok" },
          { t: "{{sender_signature}}", v: "Priya Sandoval, NE Region", state: "ok" },
          { t: "{{custom.preferred_park}}", v: v.id === "v-walsh" ? "—" : "Boyd Lake SP", state: v.id === "v-walsh" ? "fallback" : "ok" },
        ].map((t, i) => (
          <div key={i} style={{ display: "grid", gridTemplateColumns: "1fr 1fr 60px", padding: "8px 0", borderTop: i === 0 ? "none" : "1px dashed var(--border-soft)", fontSize: 12, alignItems: "center" }}>
            <code style={{ fontFamily: "var(--font-mono)", color: "var(--coral-700)" }}>{t.t}</code>
            <span style={{ color: "var(--ink)", textAlign: "right" }}>{t.v}</span>
            <span style={{ textAlign: "right" }}>
              {t.state === "ok" ? <StatusChip status="confirmed" size="sm" label="OK" /> : <StatusChip status="pending" size="sm" label="Fallback" />}
            </span>
          </div>
        ))}
        <div style={{ marginTop: 14, padding: 10, background: v.id === "v-walsh" ? "var(--amber-100)" : "var(--sage-100)", color: v.id === "v-walsh" ? "var(--amber-600)" : "var(--sage-700)", borderRadius: 8, fontSize: 11, lineHeight: 1.5 }}>
          {v.id === "v-walsh"
            ? "1 token used a safe fallback. Required tokens block send when unrenderable. This token is optional, so the send proceeds."
            : "All tokens rendered for this recipient. No fallbacks used."}
        </div>
        <Btn size="sm" kind="secondary" icon={IconMail} style={{ marginTop: 14 }}>Send test to {v.name.split(" ")[0]}'s test address</Btn>
      </Card>
    </div>
  );
};

// --- Step 4: Pre-flight checks ---
const Step4Preflight = () => (
  <div style={{ display: "grid", gridTemplateColumns: "repeat(2, 1fr)", gap: 14 }}>
    <Card>
      <div style={{ ...m8n_over, marginBottom: 12 }}>Pre-flight checks · 11 / 12 pass</div>
      <CheckRow ok="ok" t="From-name and reply-to set" />
      <CheckRow ok="ok" t="Subject line set · 76 characters · no spam triggers" />
      <CheckRow ok="ok" t="Preheader set · 96 characters · reads with subject" />
      <CheckRow ok="ok" t="All required tokens resolve for sample of 50 recipients" />
      <CheckRow ok="ok" t="No PII or sensitive data in subject or body" />
      <CheckRow ok="ok" t="All images have alt text" />
      <CheckRow ok="ok" t="DKIM / SPF / DMARC pass on volunteers@cpw.state.co.us" />
      <CheckRow ok="ok" t="Unsubscribe + preference link present" />
      <CheckRow ok="ok" t="Tenant master-switch ON · sandbox masked: 0" />
      <CheckRow ok="ok" t="Suppression cache fresh (under 60s old)" />
      <CheckRow ok="ok" t="Send within send-rate budget (968 of 50k daily cap)" />
      <CheckRow ok="warn" t="Spanish version not detected for 38 ES-preference recipients · they'll receive English fallback" />
    </Card>
    <Card>
      <div style={{ ...m8n_over, marginBottom: 12 }}>Send safety</div>
      <SR label="BCC cap" v="450 (default) · auto-split into 3 chunks" />
      <SR label="Throttle" v="120 emails / sec" />
      <SR label="Retry policy" v="3 retries · exponential backoff 1m / 5m / 30m" />
      <SR label="Bounce threshold" v="Pause if hard-bounce > 2% in first 200" />
      <SR label="Approval required" v="Yes · 1 of 2 universal admins has approved" />
      <SR label="Sandbox mode" v="OFF · this will send to real volunteers" />
      <div style={{ marginTop: 16, padding: 12, background: "var(--amber-100)", color: "var(--amber-600)", borderRadius: 10, fontSize: 12, lineHeight: 1.5 }}>
        This is a production send. After scheduling, recipients are re-evaluated at run time. Suppression, consent, and red-flag rules are applied a second time before dispatch.
      </div>
    </Card>
  </div>
);
const SR = ({ label, v }) => (
  <div style={{ display: "flex", justifyContent: "space-between", padding: "7px 0", borderBottom: "1px dashed var(--border-soft)", fontSize: 12 }}>
    <span style={{ color: "var(--fg-3)" }}>{label}</span>
    <span style={{ color: "var(--ink)", textAlign: "right" }}>{v}</span>
  </div>
);

// --- Step 5: Schedule ---
const Step5Schedule = () => (
  <div style={{ display: "grid", gridTemplateColumns: "repeat(2, 1fr)", gap: 14 }}>
    <Card>
      <div style={{ ...m8n_over, marginBottom: 12 }}>When to send</div>
      <div style={{ display: "grid", gridTemplateColumns: "repeat(3, 1fr)", gap: 10, marginBottom: 16 }}>
        {[
          { id: "now", t: "Send now", d: "After approval is final." },
          { id: "sched", t: "Schedule", d: "Pick a date and time.", active: true },
          { id: "drip", t: "Drip across day", d: "Even arrival times by tz." },
        ].map(o => (
          <Card key={o.id} style={{ padding: 14, cursor: "pointer", borderColor: o.active ? "var(--coral-500)" : "var(--border-soft)", borderWidth: o.active ? 2 : 1 }}>
            <div style={{ fontSize: 13, fontWeight: 500 }}>{o.t}</div>
            <div style={{ ...m8n_meta, marginTop: 4 }}>{o.d}</div>
          </Card>
        ))}
      </div>
      <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 10 }}>
        <Field label="Date" required><Input type="date" defaultValue="2026-06-02" /></Field>
        <Field label="Time" required><Input type="time" defaultValue="09:00" /></Field>
        <Field label="Time zone"><Select defaultValue="America/Denver" options={["America/Denver", "America/New_York"]} /></Field>
        <Field label="Cap arrival window"><Select defaultValue="immediate" options={[{ value: "immediate", label: "Immediate" }, { value: "30m", label: "Spread over 30 min" }, { value: "2h", label: "Spread over 2 hours" }]} /></Field>
      </div>
      <div style={{ ...m8n_over, margin: "16px 0 10px" }}>If anything changes before send</div>
      <div style={{ display: "flex", flexDirection: "column", gap: 8 }}>
        <Checkbox checked={true} onChange={() => {}} label="Recompute suppression list at send time" />
        <Checkbox checked={true} onChange={() => {}} label="Re-evaluate red-flag / inactive / deceased state" />
        <Checkbox checked={true} onChange={() => {}} label="Re-evaluate channel consent" />
        <Checkbox checked={true} onChange={() => {}} label="Verify sender identity is still authorized" />
      </div>
    </Card>
    <Card>
      <div style={{ ...m8n_over, marginBottom: 12 }}>Send plan summary</div>
      <SR label="Audience" v="968 recipients · 56 suppressed" />
      <SR label="When" v="Tue, Jun 2, 2026 · 9:00 am MT" />
      <SR label="From" v="CPW Volunteer Program (Priya Sandoval)" />
      <SR label="Reply-to" v="volunteers@cpw.state.co.us" />
      <SR label="Subject" v="Spring trail crews · 1,284 hours so far · what's coming up" />
      <SR label="Snapshot" v="Will lock at v4 on send" />
      <SR label="Approver" v="Aliyah Chen (1 of 1)" />
      <SR label="Audit ref" v={`nl-send-${new Date().toISOString().slice(0, 10)}-${Math.random().toString(36).slice(2, 5)}`} />
      <div style={{ marginTop: 14, padding: 10, background: "var(--paper-deep)", borderRadius: 8, fontSize: 11, color: "var(--fg-2)", lineHeight: 1.5 }}>
        Recipients are scoped to your permitted regions. Once dispatched, the content snapshot is immutable.
      </div>
    </Card>
  </div>
);

// --- Step 6: Result ---
const Step6Result = ({ onClose }) => (
  <Card>
    <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)" }}>Scheduled · Jun 2, 9:00 am MT</div>
      <div style={{ fontSize: 13, color: "var(--fg-2)", marginTop: 6 }}>968 recipients · 56 suppressed · audit ref <code style={{ background: "var(--paper-deep)", padding: "2px 7px", borderRadius: 4, fontFamily: "var(--font-mono)", fontSize: 12 }}>nl-send-2026-06-02-7x</code></div>
    </div>
    <div style={{ display: "grid", gridTemplateColumns: "repeat(3, 1fr)", gap: 10, marginTop: 16 }}>
      <ResultStep n="1" t="Snapshot locked" d="Content v4 captured. Source template can change without affecting this send." />
      <ResultStep n="2" t="Audience saved" d="968 recipients + 56 suppression reasons recorded for audit." />
      <ResultStep n="3" t="Queued" d="Will dispatch in 9 chunks of 450 BCC max from outbound-1 warm pool." />
    </div>
    <div style={{ marginTop: 18, padding: 12, background: "var(--paper-deep)", borderRadius: 10, fontSize: 12, color: "var(--fg-2)" }}>
      Cancel up to 5 minutes before send. Recipients are re-checked at run time — if a volunteer becomes red-flagged or revokes consent between now and Jun 2, they're automatically excluded.
    </div>
  </Card>
);

const ResultStep = ({ n, t, d }) => (
  <Card style={{ padding: 14 }}>
    <div style={{ display: "flex", gap: 10, alignItems: "baseline", marginBottom: 6 }}>
      <span style={{ fontFamily: "var(--font-display)", fontSize: 22, color: "var(--coral-700)" }}>{n}</span>
      <span style={{ fontSize: 13, fontWeight: 500 }}>{t}</span>
    </div>
    <div style={{ ...m8n_meta, lineHeight: 1.4 }}>{d}</div>
  </Card>
);

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