// olivia-admin.jsx
// Admin / CMS for Olivia — content creators draft, review, and ship task cards.
// Three-pane layout (list | editor | live mobile preview) inside a browser window.

const { useState, useMemo, useEffect, useRef } = React;

// ── Sample content ────────────────────────────────────────────
// Mirrors the schema from the PRD: id, day, ageMin/Max, kind, task, tip, prayer.
// Extends with admin metadata: status, author, reviewer, updatedAt, theology.

const AGE_BANDS = ['0–3', '4–6', '7–9', '10–12', '13–15', '16–18'];

const KINDS = [
  { name: 'Prayer time',              ageRanges: ['all'] },
  { name: 'Blessing',                 ageRanges: ['all'] },
  { name: 'Faith moment',             ageRanges: ['all'] },
  { name: 'Faith conversation',       ageRanges: ['4–6', '7–9', '10–12', '13–15', '16–18'] },
  { name: 'Bible story',              ageRanges: ['all'] },
  { name: 'Bedtime blessing',         ageRanges: ['all'] },
  { name: 'Mealtime prayer',          ageRanges: ['all'] },
  { name: 'Scripture memorization',  ageRanges: ['all'] },
  { name: 'Character building',       ageRanges: ['all'] },
  { name: 'Conversation starter',     ageRanges: ['4–6', '7–9', '10–12', '13–15', '16–18'] },
];

const STATUSES = {
  draft:    { label: 'Draft',     dot: '#A89E94', bg: '#EFE7D9', fg: '#7A6E66' },
  review:   { label: 'In review', dot: '#E1B45A', bg: '#FBEFC9', fg: '#8A6918' },
  approved: { label: 'Approved',  dot: '#7A8B6F', bg: '#DCE4D2', fg: '#4E6147' },
  shipped:  { label: 'Shipped',   dot: '#D97757', bg: '#FAE7D8', fg: '#9E4B2E' },
};

const SAMPLE_CONTENT = [];

const THEOLOGY_CHECKS = [
  { id: 'denomAgnostic',     label: "Denomination-agnostic",                hint: "No language tied to a specific tradition (e.g. catechism wording, sacraments)." },
  { id: 'ageAppropriate',    label: "Age-appropriate for stated range",     hint: "Concrete, not abstract. No theological complexity above the kid's level." },
  { id: 'parentFacing',      label: "Parent-facing, not child-facing",      hint: "Coaches the parent. Doesn't ask the parent to read AI-generated copy aloud to the child." },
  { id: 'scriptureAccurate', label: "Scripture reference is accurate",      hint: "Verse exists and supports the framing. No paraphrase passed off as scripture." },
  { id: 'nonPrescriptive',   label: "Low-pressure, non-prescriptive tone",  hint: "Doesn't shame parents who skip a day. Invites, doesn't demand." },
];

// ── Admin tokens (extend OLIVIA with admin-specific surface vars) ────────
const ADMIN = {
  pageBg: '#F5EFE6',
  panel: '#FFFCF7',
  panelMute: '#FAF4EA',
  hair: 'rgba(58,46,38,0.08)',
  hairStrong: 'rgba(58,46,38,0.16)',
  ink: '#3A2E26',
  inkSoft: '#7A6E66',
  inkMute: '#A89E94',
  accent: '#D97757',
  accentDeep: '#B85A3D',
  accentWash: '#FAE7D8',
  sage: '#7A8B6F',
  sageDeep: '#4E6147',
};

// ── App ────────────────────────────────────────────────────────
function useDrag(initial, min, max, direction = 1) {
  const [width, setWidth] = useState(initial);
  const onMouseDown = (e) => {
    e.preventDefault();
    const startX = e.clientX;
    const startW = width;
    const onMove = (e) => {
      const delta = (e.clientX - startX) * direction;
      setWidth(Math.max(min, Math.min(max, startW + delta)));
    };
    const onUp = () => {
      document.removeEventListener('mousemove', onMove);
      document.removeEventListener('mouseup', onUp);
      document.body.style.cursor = '';
      document.body.style.userSelect = '';
    };
    document.body.style.cursor = 'col-resize';
    document.body.style.userSelect = 'none';
    document.addEventListener('mousemove', onMove);
    document.addEventListener('mouseup', onUp);
  };
  return [width, onMouseDown];
}

function ResizeHandle({ onMouseDown }) {
  const [hovered, setHovered] = useState(false);
  return (
    <div
      onMouseDown={onMouseDown}
      onMouseEnter={() => setHovered(true)}
      onMouseLeave={() => setHovered(false)}
      style={{
        width: 5, flexShrink: 0, cursor: 'col-resize',
        background: hovered ? ADMIN.accent : 'transparent',
        transition: 'background 0.15s',
        position: 'relative', zIndex: 10,
      }}
    >
      <div style={{
        position: 'absolute', top: '50%', left: '50%',
        transform: 'translate(-50%, -50%)',
        width: 2, height: 32, borderRadius: 2,
        background: hovered ? ADMIN.accent : ADMIN.hairStrong,
        transition: 'background 0.15s',
      }}/>
    </div>
  );
}

function AdminApp({ tweaks }) {
  const [items, setItems] = useState(SAMPLE_CONTENT);
  const [selectedId, setSelectedId] = useState(null);
  const [statusFilter, setStatusFilter] = useState('all');
  const [search, setSearch] = useState('');
  const [previewChild, setPreviewChild] = useState('Emma');
  const [previewScreen, setPreviewScreen] = useState('task');
  const [kinds, setKinds] = useState(KINDS);
  const [milestones, setMilestones] = useState([]);
  const [page, setPage] = useState('overview');
  const [sequences, setSequences] = useState(Object.fromEntries(AGE_BANDS.map(b => [b, []])));
  const [shippedBands, setShippedBands] = useState({});
  const [shippedCards, setShippedCards] = useState(Object.fromEntries(AGE_BANDS.map(b => [b, []])));
  const [lastShippedSequence, setLastShippedSequence] = useState({});
  const [childrenPerFamily, setChildrenPerFamily] = useState(1.8);
  const [adminProfile, setAdminProfile] = useState({ name: '', email: '' });
  const [appLinks, setAppLinks] = useState({ ios: '', android: '' });
  const [liveStats, setLiveStats] = useState(null);
  const [statsLoading, setStatsLoading] = useState(true);

  useEffect(() => {
    const stop = pollOverviewStats(stats => {
      setLiveStats(stats);
      setStatsLoading(false);
    });
    setStatsLoading(true);
    return stop;
  }, []);

  const [leftWidth, onLeftDrag] = useDrag(300, 200, 480, 1);
  const [rightWidth, onRightDrag] = useDrag(420, 300, 580, -1);

  const selected = items.find(i => i.id === selectedId) || null;
  const dayMap = useMemo(() => Object.fromEntries(items.map((it, i) => [it.id, i + 1])), [items]);

  const filtered = items.filter(it => {
    if (statusFilter !== 'all' && it.status !== statusFilter) return false;
    if (search && !`${it.task} ${it.tip} ${it.kind}`.toLowerCase().includes(search.toLowerCase())) return false;
    return true;
  });

  const createNewCard = () => {
    const id = `c-${Date.now()}`;
    const card = {
      id,
      kind: kinds[0]?.name || '',
      task: '', tip: '', prayer: [], notes: '',
      estMinutes: 3,
      status: 'draft',
      author: 'You', reviewer: null,
      updatedAt: 'just now',
      theology: { denomAgnostic: null, ageAppropriate: null, parentFacing: null, scriptureAccurate: null, nonPrescriptive: null },
    };
    setItems(prev => [...prev, card]);
    setSelectedId(id);
  };

  const reorderItems = (draggedId, targetId) => {
    setItems(prev => {
      const copy = [...prev];
      const from = copy.findIndex(i => i.id === draggedId);
      const to = copy.findIndex(i => i.id === targetId);
      const [item] = copy.splice(from, 1);
      copy.splice(to, 0, item);
      return copy;
    });
  };

  const updateSelected = (patch) => {
    if (!selected) return;
    setItems(items.map(i => i.id === selected.id ? { ...i, ...patch, updatedAt: 'just now' } : i));
  };

  const updateTheology = (key, value) => {
    if (!selected) return;
    updateSelected({ theology: { ...selected.theology, [key]: value } });
  };

  const deleteSelected = () => {
    if (!selected) return;
    setItems(prev => prev.filter(i => i.id !== selected.id));
    setSelectedId(null);
  };

  const renameKind = (oldName, newName) => {
    setItems(prev => prev.map(card =>
      card.kind === oldName ? { ...card, kind: newName } : card
    ));
  };

  const shipSequence = (band) => {
    const seq = sequences[band] || [];
    const newlyShipped = items.filter(it => seq.includes(it.id) && it.status === 'approved');
    setShippedCards(prev => {
      const existing = (prev[band] || [])
        .filter(s => seq.includes(s.id))
        .filter(s => !newlyShipped.find(it => it.id === s.id));
      return { ...prev, [band]: [...existing, ...newlyShipped.map(it => ({ ...it }))] };
    });
    setLastShippedSequence(prev => ({ ...prev, [band]: [...seq] }));
    setShippedBands(prev => ({ ...prev, [band]: new Date().toLocaleString() }));
  };

  return (
    <div style={{
      width: '100%', height: '100%', background: ADMIN.pageBg,
      color: ADMIN.ink, fontFamily: OLIVIA.fontBody,
      display: 'flex', flexDirection: 'column', overflow: 'hidden',
    }}>
      <AdminTopBar
        search={search} setSearch={setSearch}
        onNewCard={createNewCard}
        page={page} setPage={setPage}
      />
      <div style={{ flex: 1, display: 'flex', minHeight: 0 }}>
        {page === 'overview' ? (
          <OverviewPage childrenPerFamily={childrenPerFamily} liveStats={liveStats} statsLoading={statsLoading}/>
        ) : page === 'tracks' ? (
          <TracksPage/>
        ) : page === 'review' ? (
          <ReviewPage/>
        ) : page === 'sequence' ? (
          <SequencePage sequences={sequences} setSequences={setSequences} items={items} kinds={kinds} onShipSequence={shipSequence} shippedBands={shippedBands} shippedCards={shippedCards} lastShippedSequence={lastShippedSequence}/>
        ) : page === 'milestones' ? (
          <MilestonesPage milestones={milestones} setMilestones={setMilestones} kinds={kinds}/>
        ) : page === 'settings' ? (
          <SettingsPage
            adminProfile={adminProfile} setAdminProfile={setAdminProfile}
            childrenPerFamily={childrenPerFamily} setChildrenPerFamily={setChildrenPerFamily}
            appLinks={appLinks} setAppLinks={setAppLinks}
            items={items} setItems={setItems}
          />
        ) : (
          <KindsPage kinds={kinds} setKinds={setKinds} items={items} onRenameKind={renameKind}/>
        )}
      </div>
    </div>
  );
}

// ── Top bar ────────────────────────────────────────────────────
function AdminTopBar({ search, setSearch, onNewCard, page, setPage }) {
  return (
    <div style={{
      height: 60, padding: '0 20px',
      display: 'flex', alignItems: 'center', gap: 16,
      borderBottom: `1px solid ${ADMIN.hair}`,
      background: ADMIN.panel,
      flexShrink: 0,
    }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
        <OliviaMark size={28}/>
        <div>
          <div style={{
            fontFamily: OLIVIA.fontDisplay, fontSize: 17, fontWeight: 600,
            color: ADMIN.ink, letterSpacing: '-0.01em',
          }}>Olivia</div>
          <div style={{
            fontFamily: OLIVIA.fontBody, fontSize: 11, fontWeight: 500,
            color: ADMIN.inkMute, letterSpacing: '0.06em', textTransform: 'uppercase',
            marginTop: -2,
          }}>Content studio</div>
        </div>
      </div>

      {/* Nav tabs */}
      <div style={{ display: 'flex', gap: 2 }}>
        {[
          ['overview',   'Overview',   'home'],
          ['tracks',    'Tracks',    'book'],
          ['review',     'Review',     'star'],
          ['kinds',      'Kinds',      'sparkle'],
          ['sequence',   'Sequence',   'list'],
          ['milestones', 'Milestones', 'star'],
          ['settings',   'Settings',   'gear'],
        ].map(([k, label, icon]) => {
          const on = page === k;
          return (
            <button key={k} onClick={() => setPage(k)} style={{
              appearance: 'none', border: 'none', cursor: 'pointer',
              display: 'flex', alignItems: 'center', gap: 6,
              padding: '7px 14px', borderRadius: 9,
              background: on ? ADMIN.accentWash : 'transparent',
              color: on ? ADMIN.accentDeep : ADMIN.inkSoft,
              fontFamily: OLIVIA.fontBody, fontSize: 13, fontWeight: on ? 600 : 500,
              transition: 'all 0.12s',
            }}>
              <Icon name={icon} size={14} color={on ? ADMIN.accent : ADMIN.inkSoft}/>
              {label}
            </button>
          );
        })}
      </div>

      <div style={{ flex: 1 }}/>

      {page !== 'overview' && page !== 'tracks' && (
        <div style={{
          display: 'flex', alignItems: 'center', gap: 8,
          background: ADMIN.pageBg, borderRadius: 10, padding: '0 12px',
          height: 36, width: 260, border: `1px solid ${ADMIN.hair}`,
        }}>
          <Icon name="sparkle" size={14} color={ADMIN.inkMute}/>
          <input value={search} onChange={(e) => setSearch(e.target.value)}
            placeholder="Search cards…"
            style={{
              flex: 1, border: 'none', outline: 'none', background: 'transparent',
              fontFamily: OLIVIA.fontBody, fontSize: 13, color: ADMIN.ink,
            }}/>
        </div>
      )}


    </div>
  );
}


// ── Review page (contributor applications + submitted tracks) ──
function ReviewPage() {
  const [tab, setTab] = useState('tracks'); // 'tracks' | 'contributors'
  return (
    <div style={{ flex: 1, display: 'flex', flexDirection: 'column', overflow: 'hidden',
      background: ADMIN.pageBg }}>
      {/* sub-tabs */}
      <div style={{ display: 'flex', gap: 2, padding: '14px 24px 0',
        borderBottom: `1px solid ${ADMIN.hair}`, background: ADMIN.panel, flexShrink: 0 }}>
        {[['tracks', 'Submitted tracks'], ['contributors', 'Contributor applications']].map(([k, label]) => {
          const on = tab === k;
          return (
            <button key={k} onClick={() => setTab(k)} style={{
              appearance: 'none', border: 'none', cursor: 'pointer',
              padding: '9px 18px', borderRadius: '9px 9px 0 0',
              background: on ? ADMIN.pageBg : 'transparent',
              color: on ? ADMIN.accentDeep : ADMIN.inkSoft,
              fontFamily: OLIVIA.fontBody, fontSize: 14, fontWeight: on ? 600 : 500,
              borderBottom: on ? `2px solid ${ADMIN.accent}` : '2px solid transparent',
              marginBottom: -1, transition: 'color .15s',
            }}>
              {label}
            </button>
          );
        })}
      </div>
      <div style={{ flex: 1, overflow: 'auto', padding: 24 }}>
        {tab === 'tracks'       ? <SubmittedTracksPanel /> : <ContributorApplicationsPanel />}
      </div>
    </div>
  );
}

function SubmittedTracksPanel() {
  const [tracks,   setTracks]   = useState(null);
  const [rejectId, setRejectId] = useState(null);
  const [note,     setNote]     = useState('');
  const [busy,     setBusy]     = useState('');
  const [flash,    setFlash]    = useState('');

  useEffect(() => { load(); }, []);
  const load = () => fetchSubmittedTracks().then(setTracks);

  const ok  = (msg) => { setFlash(msg); setTimeout(() => setFlash(''), 2500); };

  const publish = async (id) => {
    setBusy(id);
    const res = await publishTrack(id);
    if (res.error) { alert(res.error); } else { ok('Published!'); load(); }
    setBusy('');
  };

  const sendReject = async () => {
    if (!note.trim()) return;
    setBusy(rejectId);
    const res = await rejectTrackWithNote(rejectId, note.trim());
    if (res.error) { alert(res.error); } else { ok('Sent back to contributor.'); load(); }
    setRejectId(null); setNote(''); setBusy('');
  };

  if (!tracks) return <div style={{ color: ADMIN.inkMute, fontFamily: OLIVIA.fontBody, fontSize: 14 }}>Loading…</div>;

  return (
    <div style={{ maxWidth: 760 }}>
      {flash && (
        <div style={{ background: '#DCE4D2', color: ADMIN.sageDeep, borderRadius: 12,
          padding: '10px 16px', marginBottom: 18, fontFamily: OLIVIA.fontBody,
          fontSize: 14, fontWeight: 600 }}>
          {flash}
        </div>
      )}

      {tracks.length === 0 && (
        <div style={{ color: ADMIN.inkMute, fontFamily: OLIVIA.fontBody, fontSize: 14,
          background: ADMIN.panel, borderRadius: 18, padding: '40px 24px', textAlign: 'center' }}>
          No tracks awaiting review.
        </div>
      )}

      {tracks.map(t => (
        <div key={t.id} style={{ background: ADMIN.panel, borderRadius: 18,
          marginBottom: 14, padding: 20, boxShadow: `0 1px 0 ${ADMIN.hair}` }}>
          <div style={{ display: 'flex', gap: 16, alignItems: 'flex-start' }}>
            {t.cover_image && (
              <img src={t.cover_image} alt="" style={{ width: 80, height: 80,
                objectFit: 'cover', borderRadius: 12, flexShrink: 0 }} />
            )}
            <div style={{ flex: 1, minWidth: 0 }}>
              <div style={{ fontFamily: OLIVIA.fontDisplay, fontSize: 18, fontWeight: 600,
                color: ADMIN.ink, marginBottom: 4 }}>
                {t.title}
              </div>
              <div style={{ fontSize: 12, color: ADMIN.inkMute, fontFamily: OLIVIA.fontBody, marginBottom: 6 }}>
                by {t.profiles?.name || 'Unknown'} · {t.age_band} · {t.duration_days} days
              </div>
              {t.about && (
                <div style={{ fontSize: 14, color: ADMIN.inkSoft, fontFamily: OLIVIA.fontBody,
                  lineHeight: 1.5, marginBottom: 10 }}>
                  {t.about}
                </div>
              )}
              <div style={{ display: 'flex', gap: 8 }}>
                <button onClick={() => publish(t.id)} disabled={busy === t.id}
                  style={{ background: ADMIN.sage, color: '#fff', border: 'none', cursor: 'pointer',
                    borderRadius: 999, padding: '9px 20px', fontFamily: OLIVIA.fontBody,
                    fontSize: 13, fontWeight: 600, opacity: busy === t.id ? 0.6 : 1 }}>
                  {busy === t.id ? 'Publishing…' : '✓ Publish'}
                </button>
                <button onClick={() => { setRejectId(t.id); setNote(''); }}
                  style={{ background: ADMIN.accentWash, color: ADMIN.accentDeep, border: 'none',
                    cursor: 'pointer', borderRadius: 999, padding: '9px 20px',
                    fontFamily: OLIVIA.fontBody, fontSize: 13, fontWeight: 600 }}>
                  Request changes
                </button>
              </div>
            </div>
          </div>

          {/* reject note inline */}
          {rejectId === t.id && (
            <div style={{ marginTop: 14, borderTop: `1px solid ${ADMIN.hair}`, paddingTop: 14 }}>
              <div style={{ fontSize: 13, fontWeight: 600, color: ADMIN.inkSoft,
                fontFamily: OLIVIA.fontBody, marginBottom: 6 }}>
                Note for contributor
              </div>
              <textarea value={note} onChange={e => setNote(e.target.value)}
                placeholder="Tell the contributor what needs to change…"
                rows={3}
                style={{ width: '100%', background: ADMIN.pageBg, border: `1.5px solid ${ADMIN.hair}`,
                  borderRadius: 10, padding: '10px 12px', fontFamily: OLIVIA.fontBody,
                  fontSize: 14, color: ADMIN.ink, resize: 'vertical', outline: 'none' }}
              />
              <div style={{ display: 'flex', gap: 8, marginTop: 8 }}>
                <button onClick={sendReject} disabled={!note.trim() || busy === t.id}
                  style={{ background: ADMIN.accent, color: '#fff', border: 'none', cursor: 'pointer',
                    borderRadius: 999, padding: '8px 18px', fontFamily: OLIVIA.fontBody,
                    fontSize: 13, fontWeight: 600, opacity: (!note.trim() || busy) ? 0.5 : 1 }}>
                  Send back
                </button>
                <button onClick={() => setRejectId(null)}
                  style={{ background: 'transparent', border: `1px solid ${ADMIN.hair}`, cursor: 'pointer',
                    borderRadius: 999, padding: '8px 16px', fontFamily: OLIVIA.fontBody,
                    fontSize: 13, color: ADMIN.inkSoft }}>
                  Cancel
                </button>
              </div>
            </div>
          )}
        </div>
      ))}
    </div>
  );
}

function ContributorApplicationsPanel() {
  const [applicants, setApplicants] = useState(null);
  const [busy,       setBusy]       = useState('');
  const [flash,      setFlash]      = useState('');

  useEffect(() => { load(); }, []);
  const load = () => fetchContributorApplications().then(setApplicants);
  const ok   = (msg) => { setFlash(msg); setTimeout(() => setFlash(''), 2500); };

  const approve = async (id) => {
    setBusy(id);
    const res = await approveContributor(id);
    if (res.error) { alert(res.error); } else { ok('Approved!'); load(); }
    setBusy('');
  };

  const reject = async (id) => {
    setBusy(id);
    const res = await rejectContributor(id);
    if (res.error) { alert(res.error); } else { ok('Application rejected.'); load(); }
    setBusy('');
  };

  const STATUS_BADGE = {
    pending:  { label: 'Pending',  bg: '#FBEFC9', color: '#8A6918' },
    approved: { label: 'Approved', bg: '#DCE4D2', color: '#4E6147' },
    rejected: { label: 'Rejected', bg: '#FAE7D8', color: '#9E4B2E' },
  };

  if (!applicants) return <div style={{ color: ADMIN.inkMute, fontFamily: OLIVIA.fontBody, fontSize: 14 }}>Loading…</div>;

  return (
    <div style={{ maxWidth: 680 }}>
      {flash && (
        <div style={{ background: '#DCE4D2', color: ADMIN.sageDeep, borderRadius: 12,
          padding: '10px 16px', marginBottom: 18, fontFamily: OLIVIA.fontBody,
          fontSize: 14, fontWeight: 600 }}>
          {flash}
        </div>
      )}

      {applicants.length === 0 && (
        <div style={{ color: ADMIN.inkMute, fontFamily: OLIVIA.fontBody, fontSize: 14,
          background: ADMIN.panel, borderRadius: 18, padding: '40px 24px', textAlign: 'center' }}>
          No contributor applications yet.
        </div>
      )}

      {applicants.map(p => {
        const badge = STATUS_BADGE[p.contributor_status] || STATUS_BADGE.pending;
        return (
          <div key={p.id} style={{ background: ADMIN.panel, borderRadius: 18,
            marginBottom: 12, padding: '16px 20px',
            display: 'flex', gap: 14, alignItems: 'center',
            boxShadow: `0 1px 0 ${ADMIN.hair}` }}>
            {/* avatar */}
            <div style={{ width: 44, height: 44, borderRadius: '50%', flexShrink: 0,
              background: '#C9D3BD',
              backgroundImage: p.photo_url ? `url(${p.photo_url})` : 'none',
              backgroundSize: 'cover', backgroundPosition: 'center' }} />
            {/* info */}
            <div style={{ flex: 1, minWidth: 0 }}>
              <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 2 }}>
                <span style={{ fontFamily: OLIVIA.fontBody, fontSize: 15, fontWeight: 600, color: ADMIN.ink }}>
                  {p.name || 'No name'}
                </span>
                <span style={{ display: 'inline-flex', padding: '2px 9px', borderRadius: 999,
                  background: badge.bg, color: badge.color,
                  fontSize: 11, fontWeight: 600, fontFamily: OLIVIA.fontBody }}>
                  {badge.label}
                </span>
              </div>
              {p.bio && (
                <div style={{ fontSize: 13, color: ADMIN.inkSoft, fontFamily: OLIVIA.fontBody,
                  lineHeight: 1.5, marginBottom: 4 }}>
                  {p.bio}
                </div>
              )}
              <div style={{ fontSize: 11, color: ADMIN.inkMute, fontFamily: OLIVIA.fontBody }}>
                Applied {new Date(p.created_at).toLocaleDateString()}
              </div>
            </div>
            {/* actions — only for pending */}
            {p.contributor_status === 'pending' && (
              <div style={{ display: 'flex', gap: 8, flexShrink: 0 }}>
                <button onClick={() => approve(p.id)} disabled={busy === p.id}
                  style={{ background: ADMIN.sage, color: '#fff', border: 'none', cursor: 'pointer',
                    borderRadius: 999, padding: '8px 16px', fontFamily: OLIVIA.fontBody,
                    fontSize: 13, fontWeight: 600, opacity: busy === p.id ? 0.6 : 1 }}>
                  Approve
                </button>
                <button onClick={() => reject(p.id)} disabled={busy === p.id}
                  style={{ background: ADMIN.accentWash, color: ADMIN.accentDeep, border: 'none',
                    cursor: 'pointer', borderRadius: 999, padding: '8px 14px',
                    fontFamily: OLIVIA.fontBody, fontSize: 13, fontWeight: 600 }}>
                  Reject
                </button>
              </div>
            )}
          </div>
        );
      })}
    </div>
  );
}

Object.assign(window, {
  AdminApp, ADMIN, SAMPLE_CONTENT, STATUSES, KINDS, THEOLOGY_CHECKS, AGE_BANDS,
});
