
(function () {
  const { useState, useEffect, useCallback, useRef } = React;
  const { fmtNum, calcTotals, getATConfig, saveATConfig, fetchATTable } = window.DashData;

  // ─── Shared modal styles helper ───────────────────────────────────────────
  function modalStyles(isDark) {
    return {
      bg:     isDark ? '#161616' : '#fff',
      border: isDark ? '#2e2e2e' : '#e8e8e8',
      text:   isDark ? '#e0e0e0' : '#1a1a18',
      sub:    isDark ? '#888'    : '#999',
      inp:    { width: '100%', padding: '9px 12px', border: `1px solid ${isDark ? '#2e2e2e' : '#e8e8e8'}`, borderRadius: 8, background: isDark ? '#1e1e1e' : '#fafaf8', color: isDark ? '#e0e0e0' : '#1a1a18', fontFamily: "'Afacad', sans-serif", fontSize: 13, boxSizing: 'border-box', outline: 'none' },
      lbl:    { fontSize: 11, color: isDark ? '#888' : '#999', fontFamily: "'Afacad', sans-serif", letterSpacing: '0.05em', display: 'block', marginBottom: 5 },
    };
  }

  function ModalShell({ onClose, title, subtitle, children, isDark, maxWidth }) {
    const s = modalStyles(isDark);
    return (
      <div style={{ position: 'fixed', inset: 0, background: '#00000066', display: 'flex', alignItems: 'center', justifyContent: 'center', zIndex: 1000, padding: 20 }}>
        <div style={{ background: s.bg, borderRadius: 16, padding: 32, maxWidth: maxWidth || 480, width: '100%', border: `1px solid ${s.border}`, maxHeight: '90vh', overflow: 'auto' }}>
          <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', marginBottom: 24 }}>
            <div>
              <h2 style={{ margin: 0, fontFamily: "'Cormorant Garamond', serif", fontSize: 24, fontWeight: 500, color: s.text }}>{title}</h2>
              {subtitle && <p style={{ margin: '6px 0 0', fontSize: 13, color: s.sub, fontFamily: "'Afacad', sans-serif" }}>{subtitle}</p>}
            </div>
            <button onClick={onClose} style={{ background: 'none', border: 'none', fontSize: 22, cursor: 'pointer', color: s.sub, padding: '0 4px', lineHeight: 1 }}>×</button>
          </div>
          {children}
        </div>
      </div>
    );
  }

  function StatusBox({ status, isDark }) {
    if (!status) return null;
    const bg    = status.ok === true  ? '#d4edda' : status.ok === false ? '#f8d7da' : isDark ? '#1e2a36' : '#e8f4fd';
    const color = status.ok === true  ? '#1a6b2e' : status.ok === false ? '#721c24' : isDark ? '#7ec8e3' : '#0c5464';
    return <div style={{ padding: '10px 14px', borderRadius: 8, background: bg, color, fontSize: 13, fontFamily: "'Afacad', sans-serif", lineHeight: 1.5 }}>{status.msg}</div>;
  }

  // ─── Token expiry helpers ────────────────────────────────────────────────
  const META_TOKEN_EXPIRY = new Date('2026-07-06');
  function metaDaysLeft() {
    return Math.max(0, Math.ceil((META_TOKEN_EXPIRY - new Date()) / 86400000));
  }

  // ─── Settings Modal (gear icon) — all platforms in one place ─────────────
  // Accessible via the subtle ⚙ icon in the nav bar; not a required step.
  function SettingsModal({ theme, onClose, onRefresh }) {
    const isDark = theme === 'dark';
    const s = modalStyles(isDark);
    const [section, setSection] = React.useState('meta');
    const daysLeft = metaDaysLeft();

    // ── Meta ──
    const [userToken, setUserToken]   = React.useState('');
    const [metaStatus, setMetaStatus] = React.useState(null);
    const [metaLoading, setMetaLoading] = React.useState(false);

    async function renewMeta() {
      if (!userToken) return;
      setMetaLoading(true);
      setMetaStatus({ ok: null, msg: 'Extending to 60-day token…' });
      try {
        const cfg = window.MetaService.getMetaConfig() || {};
        const longLived = await window.MetaService.extendMetaToken(userToken, cfg.appId, cfg.appSecret);
        setMetaStatus({ ok: null, msg: 'Getting page token…' });
        const pt = await window.MetaService.getPageToken(longLived, cfg.pageId);
        window.MetaService.saveMetaConfig({ ...cfg, userToken, pageToken: pt });
        setMetaStatus({ ok: true, msg: '✓ Token renewed — good for another 60 days.' });
        if (onRefresh) onRefresh();
      } catch(e) { setMetaStatus({ ok: false, msg: e.message }); }
      setMetaLoading(false);
    }

    // ── TikTok ──
    const ttExisting = window.TikTokService.getTikTokConfig() || {};
    const [ttToken, setTtToken]   = React.useState(ttExisting.accessToken || '');
    const [ttStatus, setTtStatus] = React.useState(ttExisting.accessToken ? { ok: true, msg: '✓ TikTok Research API token saved.' } : null);
    const [ttLoading, setTtLoading] = React.useState(false);

    // ── AdSanity ──
    const asExisting = getAdStatsConfig() || {};
    const [asKey, setAsKey]       = React.useState(asExisting.apiKey || LOCALE_AD_STATS_DEFAULT_KEY);
    const [asStatus, setAsStatus] = React.useState(null);
    async function saveAdStats() {
      saveAdStatsConfig({ ...asExisting, apiKey: asKey, endpoint: asExisting.endpoint || 'https://localemagazine.com/wp-json/locale/v1/ad-stats' });
      // Quick smoke-test: hit the endpoint with the key
      setAsStatus({ ok: null, msg: 'Testing…' });
      try {
        const ep = asExisting.endpoint || 'https://localemagazine.com/wp-json/locale/v1/ad-stats';
        const r  = await fetch(ep, { headers: { 'X-Locale-Key': asKey } });
        if (r.status === 401) throw new Error('Invalid key — server returned 401.');
        if (!r.ok) throw new Error(`Server error ${r.status}`);
        const d = await r.json();
        const count = Array.isArray(d) ? d.length : 1;
        setAsStatus({ ok: true, msg: `✓ Key accepted — ${count} ad(s) returned.` });
      } catch(e) { setAsStatus({ ok: false, msg: e.message }); }
    }

    async function saveTikTok() {
      if (!ttToken) return;
      setTtLoading(true);
      setTtStatus({ ok: null, msg: 'Testing token…' });
      try {
        const testUrl = 'https://www.tiktok.com/@localemag/video/7565221539243756813';
        const r = await fetch(`/api/tiktok/video-stats?url=${encodeURIComponent(testUrl)}`, { headers: { 'x-tiktok-token': ttToken } });
        const d = await r.json();
        if (!r.ok) throw new Error(d.error || 'TikTok API error');
        window.TikTokService.saveTikTokConfig({ accessToken: ttToken });
        setTtStatus({ ok: true, msg: `✓ Connected — views: ${(d.views||0).toLocaleString()}` });
        if (onRefresh) onRefresh();
      } catch(e) { setTtStatus({ ok: false, msg: e.message }); }
      setTtLoading(false);
    }

    const urgentColor = daysLeft <= 7 ? '#721c24' : daysLeft <= 14 ? '#856404' : '#1a6b2e';
    const urgentBg    = daysLeft <= 7 ? '#f8d7da' : daysLeft <= 14 ? '#fff3cd' : '#d4edda';

    const sections = [
      { id: 'meta',      label: 'Meta',      color: '#1877F2' },
      { id: 'tiktok',    label: 'TikTok',    color: '#010101' },
      { id: 'adsanity',  label: 'Ad Stats',  color: '#E55A2B' },
      { id: 'airtable',  label: 'Airtable',  color: '#C8975A' },
    ];

    return (
      <ModalShell onClose={onClose} title="Settings" subtitle="All platforms auto-connected — use this to rotate tokens" isDark={isDark} maxWidth={540}>
        {/* Section tabs */}
        <div style={{ display: 'flex', gap: 6, marginBottom: 24, borderBottom: `1px solid ${s.border}`, paddingBottom: 12 }}>
          {sections.map(sec => (
            <button key={sec.id} onClick={() => setSection(sec.id)} style={{ padding: '6px 14px', background: section === sec.id ? sec.color : 'transparent', border: `1px solid ${section === sec.id ? sec.color : s.border}`, borderRadius: 20, cursor: 'pointer', fontSize: 12, fontWeight: 600, color: section === sec.id ? '#fff' : s.sub, fontFamily: "'Afacad', sans-serif", transition: 'all 0.15s' }}>
              {sec.label}
            </button>
          ))}
        </div>

        {section === 'meta' && (
          <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
            <div style={{ padding: '10px 14px', background: urgentBg, borderRadius: 8, border: `1px solid ${urgentColor}33`, fontSize: 12, color: urgentColor, fontFamily: "'Afacad', sans-serif", lineHeight: 1.6 }}>
              <strong>{daysLeft <= 7 ? '⚠ Token expiring soon!' : daysLeft <= 14 ? '⚠ Renewal recommended' : '✓ Token active'}</strong>
              {' '}— expires 07/06/2026 ({daysLeft} days left).
              To renew: go to <a href="https://developers.facebook.com/tools/explorer/" target="_blank" style={{ color: urgentColor, fontWeight: 600 }}>Graph API Explorer</a>, generate a fresh User Access Token, paste it below and click Renew.
            </div>
            <div>
              <label style={s.lbl}>NEW USER ACCESS TOKEN</label>
              <input style={s.inp} type="password" placeholder="EAAV… (1-hour token from Graph API Explorer)" value={userToken} onChange={e => setUserToken(e.target.value)} />
            </div>
            <StatusBox status={metaStatus} isDark={isDark} />
            <button onClick={renewMeta} disabled={metaLoading || !userToken} style={{ padding: '11px 0', background: '#1877F2', border: 'none', borderRadius: 8, cursor: metaLoading || !userToken ? 'not-allowed' : 'pointer', fontFamily: "'Afacad', sans-serif", fontWeight: 600, fontSize: 13, color: '#fff', opacity: metaLoading || !userToken ? 0.6 : 1 }}>
              {metaLoading ? (metaStatus?.msg || 'Renewing…') : 'Renew Token (60 days)'}
            </button>
          </div>
        )}

        {section === 'tiktok' && (
          <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
            <div style={{ padding: '10px 14px', background: isDark ? '#101010' : '#f8f8f8', borderRadius: 8, border: `1px solid ${isDark ? '#333' : '#e0e0e0'}`, fontSize: 12, color: isDark ? '#aaa' : '#555', fontFamily: "'Afacad', sans-serif", lineHeight: 1.7 }}>
              Apply for <a href="https://developers.tiktok.com/products/research-api/" target="_blank" style={{ color: '#010101', fontWeight: 600 }}>TikTok Research API</a> access, then paste your client token below. All other platforms are pre-connected without a token.
            </div>
            <div>
              <label style={s.lbl}>TIKTOK RESEARCH API TOKEN</label>
              <input style={s.inp} type="password" placeholder="act.…" value={ttToken} onChange={e => setTtToken(e.target.value)} />
            </div>
            <StatusBox status={ttStatus} isDark={isDark} />
            <button onClick={saveTikTok} disabled={ttLoading || !ttToken} style={{ padding: '11px 0', background: '#010101', border: 'none', borderRadius: 8, cursor: ttLoading || !ttToken ? 'not-allowed' : 'pointer', fontFamily: "'Afacad', sans-serif", fontWeight: 600, fontSize: 13, color: '#fff', opacity: ttLoading || !ttToken ? 0.6 : 1 }}>
              {ttLoading ? 'Testing…' : 'Test & Save'}
            </button>
          </div>
        )}

        {section === 'adsanity' && (
          <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
            <div style={{ padding: '10px 14px', background: isDark ? '#1a0e08' : '#fff5f1', borderRadius: 8, border: '1px solid #E55A2B33', fontSize: 12, color: isDark ? '#e07a50' : '#8B3A1A', fontFamily: "'Afacad', sans-serif", lineHeight: 1.7 }}>
              The <strong>X-Locale-Key</strong> protects your WordPress ad-stats endpoint. It must match the <code>LOCALE_AD_STATS_KEY</code> constant in the Snippets plugin. Default: <code>locale_ads_8f14e45fceea167a5a36dedd4bea2543</code>.
            </div>
            <div>
              <label style={s.lbl}>AD STATS API KEY</label>
              <input style={s.inp} type="password" placeholder="locale_ads_…" value={asKey} onChange={e => setAsKey(e.target.value)} />
            </div>
            <div>
              <label style={s.lbl}>ENDPOINT URL</label>
              <input style={s.inp} type="text" placeholder="https://localemagazine.com/wp-json/locale/v1/ad-stats" value={asExisting.endpoint || 'https://localemagazine.com/wp-json/locale/v1/ad-stats'} onChange={e => saveAdStatsConfig({ ...asExisting, endpoint: e.target.value })} />
            </div>
            <StatusBox status={asStatus} isDark={isDark} />
            <button onClick={saveAdStats} disabled={!asKey} style={{ padding: '11px 0', background: '#E55A2B', border: 'none', borderRadius: 8, cursor: !asKey ? 'not-allowed' : 'pointer', fontFamily: "'Afacad', sans-serif", fontWeight: 600, fontSize: 13, color: '#fff', opacity: !asKey ? 0.6 : 1 }}>
              Save & Test Key
            </button>
          </div>
        )}

        {section === 'airtable' && (
          <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
            <div style={{ padding: '10px 14px', background: isDark ? '#1a1a10' : '#fffbf0', borderRadius: 8, border: '1px solid #C8975A33', fontSize: 12, color: isDark ? '#c8a06a' : '#8B6534', fontFamily: "'Afacad', sans-serif", lineHeight: 1.7 }}>
              ✓ Airtable is pre-connected to base <strong>apppfiqMVK5MkTXSW</strong>. Only use this section if the base ID or API key changes.
            </div>
            {[
              ['apiKey',         'PERSONAL ACCESS TOKEN', 'patXXX…', true],
              ['baseId',         'BASE ID',               'appXXX…', false],
              ['campaignsTable', 'CAMPAIGNS TABLE',       'Individual Campaign Bookings', false],
              ['annualTable',    'PARTNERS TABLE',        'Partners', false],
              ['deliverablesTable','DELIVERABLES TABLE',  'Deliverables', false],
            ].map(([key, lbl, ph, secret]) => {
              const existing = getATConfig() || {};
              const [val, setVal] = React.useState(existing[key] || '');
              return (
                <div key={key}>
                  <label style={s.lbl}>{lbl}</label>
                  <input style={s.inp} type={secret ? 'password' : 'text'} placeholder={ph} value={val} onChange={e => {
                    setVal(e.target.value);
                    const cfg = getATConfig() || {};
                    saveATConfig({ ...cfg, [key]: e.target.value });
                  }} />
                </div>
              );
            })}
            <button onClick={() => { if (onRefresh) onRefresh(); onClose(); }} style={{ padding: '11px 0', background: '#C8975A', border: 'none', borderRadius: 8, cursor: 'pointer', fontFamily: "'Afacad', sans-serif", fontWeight: 600, fontSize: 13, color: '#fff' }}>
              Save & Reload Data
            </button>
          </div>
        )}
      </ModalShell>
    );
  }

  // ─── Campaign Report ──────────────────────────────────────────────────────
  function CampaignReport({ campaign, allCampaigns, theme, isPartnerView, onBack }) {
    const isDark = theme === 'dark';
    const [activeSection, setActiveSection] = useState('overview');
    const [compareId, setCompareId] = useState('');
    const compareCampaign = allCampaigns.find(c => c.id === compareId);
    const totals  = calcTotals(campaign.metrics);
    const bg      = isDark ? '#111' : '#fafaf8';
    const cardBg  = isDark ? '#161616' : '#fff';
    const border  = isDark ? '#2a2a2a' : '#ebebeb';
    const text    = isDark ? '#e0e0e0' : '#1a1a18';
    const sub     = isDark ? '#777' : '#aaa';

    // metricsLoading = no metrics yet AND campaign was just loaded (metrics = empty object)
    const metricsLoading = Object.keys(campaign.metrics || {}).length === 0;

    const navItems = [
      { id: 'overview',     label: 'Overview' },
      { id: 'platforms',    label: 'Platforms' },
      { id: 'timeline',     label: 'Timeline' },
      { id: 'deliverables', label: 'Deliverables' },
      { id: 'gallery',      label: 'Content' },
      { id: 'addedvalue',   label: 'Added Value' },
      { id: 'compare',      label: 'Compare' },
    ];
    const addedTotal = campaign.addedValue.reduce((s, i) => s + (i.estimatedValue || 0), 0);

    return (
      <div style={{ minHeight: '100vh', background: bg }}>
        <div style={{ background: isDark ? '#0d0d0d' : '#fff', borderBottom: `1px solid ${border}`, position: 'sticky', top: 0, zIndex: 10 }}>
          <div style={{ maxWidth: 1100, margin: '0 auto', padding: '0 24px' }}>
            <div style={{ display: 'flex', alignItems: 'center', gap: 16, paddingTop: 18, paddingBottom: 14 }}>
              {!isPartnerView && (
                <button onClick={onBack} style={{ background: 'none', border: `1px solid ${border}`, borderRadius: 8, padding: '6px 12px', cursor: 'pointer', fontSize: 12, color: sub, fontFamily: "'Afacad', sans-serif", display: 'flex', alignItems: 'center', gap: 5 }}>
                  ← Back
                </button>
              )}
              {isPartnerView && (
                <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
                  <img src="https://media.localemagazine.com/wp-content/uploads/2019/01/LocaleLogo_MagHub_178x48_300di.png" alt="Locale Magazine" style={{ height: 28, objectFit: 'contain', display: 'block' }} />
                  <span style={{ color: border, fontSize: 16 }}>|</span>
                  <span style={{ fontSize: 12, color: sub, fontFamily: "'Afacad', sans-serif" }}>Partner Report</span>
                </div>
              )}
              <div style={{ flex: 1 }}>
                <h1 style={{ margin: 0, fontFamily: "'Cormorant Garamond', serif", fontSize: 22, fontWeight: 500, color: text, letterSpacing: '-0.01em' }}>{campaign.partner}</h1>
                <div style={{ display: 'flex', alignItems: 'center', gap: 10, marginTop: 3, flexWrap: 'wrap' }}>
                  <span style={{ fontSize: 12, color: sub, fontFamily: "'Afacad', sans-serif" }}>{campaign.campaignName}</span>
                  <span style={{ color: border }}>·</span>
                  <span style={{ fontSize: 12, color: sub, fontFamily: "'Afacad', sans-serif" }}>{campaign.startDate}{campaign.endDate ? ' – ' + campaign.endDate : ''}</span>
                  <StatusBadge status={campaign.status} />
                </div>
              </div>
              <div style={{ display: 'flex', gap: 8 }}>
                <button onClick={() => window.print()} style={{ padding: '7px 14px', background: 'none', border: `1px solid ${border}`, borderRadius: 8, cursor: 'pointer', fontSize: 12, color: sub, fontFamily: "'Afacad', sans-serif" }}>Export PDF</button>
                {!isPartnerView && (
                  <button onClick={() => {
                    // Use the Airtable Partner record ID (partnerLinkId) so the partner link
                    // filters to only their campaigns via ?view=partner&partnerId=recXXXX
                    const pid = campaign.partnerLinkId || campaign.slug;
                    const url = `${location.origin}${location.pathname}?view=partner&partnerId=${pid}`;
                    navigator.clipboard.writeText(url).then(() => {
                      const btn = document.activeElement;
                      if (btn) { const orig = btn.textContent; btn.textContent = '✓ Copied!'; setTimeout(() => { btn.textContent = orig; }, 2000); }
                    });
                  }} style={{ padding: '7px 14px', background: '#C8975A', border: 'none', borderRadius: 8, cursor: 'pointer', fontSize: 12, color: '#fff', fontFamily: "'Afacad', sans-serif", fontWeight: 600 }}>
                    Copy Partner Link
                  </button>
                )}
              </div>
            </div>
            {/* Summary stats bar */}
            <div style={{ display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', borderTop: `1px solid ${border}` }}>
              {[
                { label: 'Total Impressions',  value: fmtNum(totals.impressions), sub: 'All channels',         accent: '#C8975A' },
                { label: 'Total Reach Social', value: fmtNum(totals.reach),       sub: 'Instagram + Facebook', accent: '#A8C5A0' },
                { label: 'Total Clicks',       value: fmtNum(totals.clicks),      sub: 'Clicks & pageviews',   accent: '#6BAED6' },
                { label: 'Total Engagement',   value: fmtNum(totals.engagement),  sub: 'Likes, saves, shares', accent: '#C9A0DC' },
              ].map((stat, i) => (
                <div key={stat.label} style={{ padding: '12px 20px', borderLeft: i > 0 ? `1px solid ${border}` : 'none', borderTop: `3px solid ${stat.accent}` }}>
                  <div style={{ fontSize: 10, letterSpacing: '0.07em', color: sub, fontFamily: "'Afacad', sans-serif", marginBottom: 4 }}>{stat.label.toUpperCase()}</div>
                  <div style={{ fontSize: 22, fontWeight: 700, letterSpacing: '-0.03em', color: text, fontFamily: "'Afacad', sans-serif" }}>{stat.value}</div>
                  <div style={{ fontSize: 11, color: sub, fontFamily: "'Afacad', sans-serif", marginTop: 2 }}>{stat.sub}</div>
                </div>
              ))}
            </div>
            {/* Section nav */}
            <div style={{ display: 'flex', gap: 2, overflowX: 'auto' }}>
              {navItems.map(n => (
                <button key={n.id} onClick={() => setActiveSection(n.id)} style={{ padding: '8px 14px', background: 'none', border: 'none', cursor: 'pointer', fontFamily: "'Afacad', sans-serif", fontSize: 13, fontWeight: activeSection === n.id ? 600 : 400, color: activeSection === n.id ? '#C8975A' : sub, borderBottom: `2px solid ${activeSection === n.id ? '#C8975A' : 'transparent'}`, whiteSpace: 'nowrap', transition: 'all 0.15s' }}>
                  {n.label}{n.id === 'addedvalue' && addedTotal > 0 ? ` +$${fmtNum(addedTotal)}` : ''}
                </button>
              ))}
            </div>
          </div>
        </div>

        <div style={{ maxWidth: 1100, margin: '0 auto', padding: '32px 24px' }}>
          {activeSection === 'overview' && (
            <div>
              <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(200px, 1fr))', gap: 14, marginBottom: 32 }}>
                <StatCard label="Total Impressions"  value={fmtNum(totals.impressions)} sub="Across all channels"   accent="#C8975A" theme={theme} />
                <StatCard label="Total Reach Social" value={fmtNum(totals.reach)}       sub="Instagram + Facebook"  accent="#A8C5A0" theme={theme} />
                <StatCard label="Total Clicks"       value={fmtNum(totals.clicks)}      sub="Clicks & pageviews"    accent="#6BAED6" theme={theme} />
                <StatCard label="Total Engagement"   value={fmtNum(totals.engagement)}  sub="Likes, saves, shares"  accent="#C9A0DC" theme={theme} />
              </div>
              <Section title="Performance Timeline" theme={theme}>
                <TimelineChart data={campaign.timelineData} theme={theme} loading={metricsLoading} />
              </Section>
              <Section title={`Deliverables — ${campaign.deliverables.filter(d => d.delivered).length}/${campaign.deliverables.length} Delivered`} theme={theme}>
                <DeliverablesList deliverables={campaign.deliverables} theme={theme} />
              </Section>
            </div>
          )}
          {activeSection === 'platforms' && (
            <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(240px, 1fr))', gap: 14 }}>
              {Object.keys(PLATFORMS).map(p => <PlatformCard key={p} platform={p} data={campaign.metrics[p] || {}} theme={theme} />)}
            </div>
          )}
          {activeSection === 'timeline' && (
            <div style={{ background: cardBg, border: `1px solid ${border}`, borderRadius: 12, padding: 28 }}>
              <Section title="Performance Over Time" theme={theme}>
                <TimelineChart data={campaign.timelineData} theme={theme} loading={metricsLoading} />
              </Section>
            </div>
          )}
          {activeSection === 'deliverables' && (
            <div style={{ background: cardBg, border: `1px solid ${border}`, borderRadius: 12, padding: 28 }}>
              <Section title="Campaign Deliverables" theme={theme}>
                <DeliverablesList deliverables={campaign.deliverables} theme={theme} />
              </Section>
            </div>
          )}
          {activeSection === 'gallery' && (
            <Section title="Content Gallery" theme={theme}>
              <ContentGallery items={campaign.gallery} theme={theme} />
            </Section>
          )}
          {activeSection === 'addedvalue' && (
            <div style={{ background: cardBg, border: `1px solid ${border}`, borderRadius: 12, padding: 28 }}>
              <Section title="Added Value" theme={theme} action={<span style={{ fontSize: 12, color: sub, fontFamily: "'Afacad', sans-serif" }}>Items posted outside contracted scope</span>}>
                <AddedValueSection items={campaign.addedValue} theme={theme} />
              </Section>
            </div>
          )}
          {activeSection === 'compare' && (
            <div>
              <div style={{ marginBottom: 24 }}>
                <label style={{ fontSize: 11, color: sub, fontFamily: "'Afacad', sans-serif", letterSpacing: '0.05em', display: 'block', marginBottom: 8 }}>COMPARE WITH CAMPAIGN</label>
                <select value={compareId} onChange={e => setCompareId(e.target.value)} style={{ padding: '9px 14px', border: `1px solid ${border}`, borderRadius: 8, background: cardBg, color: text, fontFamily: "'Afacad', sans-serif", fontSize: 13, minWidth: 280 }}>
                  <option value="">Select a campaign to compare…</option>
                  {allCampaigns.filter(c => c.id !== campaign.id).map(c => (
                    <option key={c.id} value={c.id}>{c.partner} — {c.campaignName}</option>
                  ))}
                </select>
              </div>
              {compareCampaign ? (
                <div>
                  <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12, marginBottom: 24 }}>
                    {[campaign, compareCampaign].map((c, i) => {
                      const t = calcTotals(c.metrics);
                      return (
                        <div key={c.id} style={{ background: cardBg, border: `1px solid ${border}`, borderRadius: 12, padding: '18px 20px' }}>
                          <div style={{ fontSize: 11, color: sub, fontFamily: "'Afacad', sans-serif", letterSpacing: '0.05em', marginBottom: 6 }}>{i === 0 ? 'CURRENT' : 'COMPARED'}</div>
                          <div style={{ fontFamily: "'Cormorant Garamond', serif", fontSize: 18, color: text, marginBottom: 4 }}>{c.partner}</div>
                          <div style={{ fontSize: 12, color: sub, fontFamily: "'Afacad', sans-serif" }}>{c.campaignName}</div>
                          <div style={{ marginTop: 12, display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 8 }}>
                            {[['Impressions', fmtNum(t.impressions)], ['Clicks', fmtNum(t.clicks)], ['Reach', fmtNum(t.reach)], ['Engagement', fmtNum(t.engagement)]].map(([l, v]) => (
                              <div key={l}><div style={{ fontSize: 10, color: sub, fontFamily: "'Afacad', sans-serif" }}>{l}</div><div style={{ fontSize: 16, fontWeight: 600, color: text, fontFamily: "'Afacad', sans-serif" }}>{v}</div></div>
                            ))}
                          </div>
                        </div>
                      );
                    })}
                  </div>
                  <div style={{ background: cardBg, border: `1px solid ${border}`, borderRadius: 12, padding: '20px 24px' }}>
                    <h3 style={{ margin: '0 0 20px', fontFamily: "'Cormorant Garamond', serif", fontSize: 20, fontWeight: 500, color: text }}>Side-by-Side Comparison</h3>
                    {[
                      ['Instagram Impressions', campaign.metrics.instagram?.impressions || 0, compareCampaign.metrics.instagram?.impressions || 0],
                      ['TikTok Views',          campaign.metrics.tiktok?.views || 0,           compareCampaign.metrics.tiktok?.views || 0],
                      ['Facebook Reach',        campaign.metrics.facebook?.reach || 0,         compareCampaign.metrics.facebook?.reach || 0],
                      ['Email Opens',           campaign.metrics.email?.opens || 0,            compareCampaign.metrics.email?.opens || 0],
                      ['YouTube Views',         campaign.metrics.youtube?.views || 0,          compareCampaign.metrics.youtube?.views || 0],
                      ['Pinterest Impressions', campaign.metrics.pinterest?.impressions || 0,  compareCampaign.metrics.pinterest?.impressions || 0],
                    ].map(([label, v1, v2]) => (
                      <CompareBar key={label} label={label} v1={v1} v2={v2} color1="#C8975A" color2="#6BAED6" />
                    ))}
                    <div style={{ display: 'flex', gap: 16, marginTop: 16, paddingTop: 12, borderTop: `1px solid ${border}` }}>
                      <span style={{ display: 'flex', alignItems: 'center', gap: 6, fontSize: 12, color: sub, fontFamily: "'Afacad', sans-serif" }}><span style={{ width: 12, height: 12, borderRadius: 2, background: '#C8975A', display: 'inline-block' }}></span>{campaign.campaignName}</span>
                      <span style={{ display: 'flex', alignItems: 'center', gap: 6, fontSize: 12, color: sub, fontFamily: "'Afacad', sans-serif" }}><span style={{ width: 12, height: 12, borderRadius: 2, background: '#6BAED6', display: 'inline-block' }}></span>{compareCampaign.campaignName}</span>
                    </div>
                  </div>
                </div>
              ) : (
                <div style={{ textAlign: 'center', padding: '48px 0', color: sub, fontFamily: "'Afacad', sans-serif", fontSize: 13 }}>Select a campaign above to compare performance side by side</div>
              )}
            </div>
          )}
        </div>
      </div>
    );
  }

  // ─── Campaigns Tab ────────────────────────────────────────────────────────
  function CampaignsTab({ campaigns, onSelect, theme }) {
    const isDark  = theme === 'dark';
    const border  = isDark ? '#2a2a2a' : '#ebebeb';
    const text    = isDark ? '#e0e0e0' : '#1a1a18';
    const sub     = isDark ? '#777' : '#aaa';
    const cardBg  = isDark ? '#161616' : '#fff';

    if (campaigns.length === 0) {
      return (
        <div style={{ textAlign: 'center', padding: '80px 24px', color: sub, fontFamily: "'Afacad', sans-serif" }}>
          <div style={{ fontFamily: "'Cormorant Garamond', serif", fontSize: 28, color: isDark ? '#333' : '#ccc', marginBottom: 10 }}>Loading campaigns…</div>
          <div style={{ fontSize: 13 }}>Connecting to Airtable and pulling live data.</div>
        </div>
      );
    }

    // Sort: Active first, then Upcoming, then Completed — within each group A→Z then by date
    const statusOrder = { Active: 0, Upcoming: 1, Completed: 2 };
    const toTs = (d) => {
      if (!d) return 0;
      const parts = d.split('/');
      if (parts.length === 3) return new Date(+parts[2], +parts[0]-1, +parts[1]).getTime();
      return new Date(d).getTime() || 0;
    };
    const sorted = [...campaigns].sort((a, b) => {
      const sA = statusOrder[a.status] ?? 1;
      const sB = statusOrder[b.status] ?? 1;
      if (sA !== sB) return sA - sB;
      const nameA = (a.partner || '').toLowerCase();
      const nameB = (b.partner || '').toLowerCase();
      if (nameA < nameB) return -1;
      if (nameA > nameB) return  1;
      return toTs(a.startDate) - toTs(b.startDate);
    });

    // Group by status so we can render section headers
    const groups = [
      { key: 'Active',    label: 'Active',    items: sorted.filter(c => c.status === 'Active') },
      { key: 'Upcoming',  label: 'Upcoming',  items: sorted.filter(c => c.status === 'Upcoming') },
      { key: 'Completed', label: 'Completed', items: sorted.filter(c => c.status === 'Completed') },
    ].filter(g => g.items.length > 0);

    // Visual config per status
    const statusStyle = {
      Active: {
        cardBorder:  isDark ? '#2a3a2e' : '#d4edda',
        cardBg:      isDark ? '#161c18' : '#fff',
        leftAccent:  '#2ecc71',
        nameColor:   isDark ? '#e0e0e0' : '#1a1a18',
        metricColor: isDark ? '#e0e0e0' : '#1a1a18',
        pctColor:    '#C8975A',
        opacity:     1,
      },
      Upcoming: {
        cardBorder:  isDark ? '#3a3520' : '#fff3cd',
        cardBg:      isDark ? '#1c1a10' : '#fffdf5',
        leftAccent:  '#f0ad00',
        nameColor:   isDark ? '#e0e0e0' : '#1a1a18',
        metricColor: isDark ? '#e0e0e0' : '#1a1a18',
        pctColor:    '#f0ad00',
        opacity:     1,
      },
      Completed: {
        cardBorder:  isDark ? '#222' : '#ebebeb',
        cardBg:      isDark ? '#111' : '#fafaf8',
        leftAccent:  isDark ? '#333' : '#ddd',
        nameColor:   isDark ? '#666' : '#999',
        metricColor: isDark ? '#555' : '#aaa',
        pctColor:    isDark ? '#444' : '#ccc',
        opacity:     0.75,
      },
    };

    return (
      <div style={{ display: 'flex', flexDirection: 'column', gap: 28 }}>
        {groups.map(group => {
          const ss = statusStyle[group.key] || statusStyle.Active;
          return (
            <div key={group.key}>
              {/* Section header */}
              <div style={{ display: 'flex', alignItems: 'center', gap: 10, marginBottom: 12 }}>
                <span style={{ width: 8, height: 8, borderRadius: '50%', background: ss.leftAccent, display: 'inline-block', flexShrink: 0 }} />
                <span style={{ fontSize: 11, fontWeight: 700, letterSpacing: '0.1em', color: isDark ? '#666' : '#aaa', fontFamily: "'Afacad', sans-serif" }}>
                  {group.key.toUpperCase()} — {group.items.length}
                </span>
                <div style={{ flex: 1, height: 1, background: isDark ? '#222' : '#ebebeb' }} />
              </div>

              {/* Cards */}
              <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
                {group.items.map(c => {
                  const totals = calcTotals(c.metrics);
                  const deliveredPct = c.deliverables.length
                    ? Math.round(c.deliverables.filter(d => d.delivered).length / c.deliverables.length * 100)
                    : 0;
                  return (
                    <div key={c.id} onClick={() => onSelect(c)}
                      style={{
                        background: ss.cardBg,
                        border: `1px solid ${ss.cardBorder}`,
                        borderLeft: `3px solid ${ss.leftAccent}`,
                        borderRadius: 10,
                        padding: '15px 20px',
                        cursor: 'pointer',
                        transition: 'box-shadow 0.15s, opacity 0.15s',
                        display: 'grid',
                        gridTemplateColumns: '1fr auto',
                        gap: 16,
                        alignItems: 'center',
                        opacity: ss.opacity,
                      }}
                      onMouseEnter={e => { e.currentTarget.style.boxShadow = '0 3px 16px #00000010'; e.currentTarget.style.opacity = '1'; }}
                      onMouseLeave={e => { e.currentTarget.style.boxShadow = 'none'; e.currentTarget.style.opacity = String(ss.opacity); }}>
                      <div>
                        <div style={{ display: 'flex', alignItems: 'center', gap: 10, marginBottom: 5, flexWrap: 'wrap' }}>
                          <span style={{ fontFamily: "'Cormorant Garamond', serif", fontSize: 18, fontWeight: 500, color: ss.nameColor }}>{c.partner}</span>
                          {c.type === 'Annual Partner' && <span style={{ fontSize: 10, fontWeight: 600, letterSpacing: '0.06em', color: '#C8975A', background: '#fdf3e7', padding: '2px 8px', borderRadius: 20 }}>ANNUAL</span>}
                        </div>
                        <div style={{ fontSize: 12, color: sub, fontFamily: "'Afacad', sans-serif", marginBottom: 8 }}>
                          {c.campaignName} · {c.startDate}{c.endDate ? ' – ' + c.endDate : ''}
                        </div>
                        {/* Metrics row — dimmed for completed */}
                        <div style={{ display: 'flex', gap: 18, flexWrap: 'wrap' }}>
                          {[['Impressions', fmtNum(totals.impressions)], ['Clicks', fmtNum(totals.clicks)], ['Reach', fmtNum(totals.reach)]].map(([l, v]) => (
                            <div key={l}>
                              <span style={{ fontSize: 11, color: sub, fontFamily: "'Afacad', sans-serif" }}>{l}: </span>
                              <span style={{ fontSize: 13, fontWeight: 600, color: ss.metricColor, fontFamily: "'Afacad', sans-serif" }}>{v}</span>
                            </div>
                          ))}
                        </div>
                      </div>
                      {/* Delivery % — right side */}
                      <div style={{ textAlign: 'right', minWidth: 64 }}>
                        <div style={{ fontSize: 20, fontWeight: 700, color: ss.pctColor, fontFamily: "'Afacad', sans-serif", letterSpacing: '-0.02em' }}>{deliveredPct}%</div>
                        <div style={{ fontSize: 10, color: sub, fontFamily: "'Afacad', sans-serif", marginBottom: 6 }}>delivered</div>
                        <div style={{ width: 56, height: 3, background: isDark ? '#2a2a2a' : '#ebebeb', borderRadius: 2, overflow: 'hidden', marginLeft: 'auto' }}>
                          <div style={{ width: `${deliveredPct}%`, height: '100%', background: ss.pctColor, borderRadius: 2 }} />
                        </div>
                      </div>
                    </div>
                  );
                })}
              </div>
            </div>
          );
        })}
      </div>
    );
  }

  // ─── Annual Partners Tab ──────────────────────────────────────────────────
  function AnnualPartnersTab({ partners, campaigns, onSelectCampaign, theme }) {
    const isDark = theme === 'dark';
    const border = isDark ? '#2a2a2a' : '#ebebeb';
    const text   = isDark ? '#e0e0e0' : '#1a1a18';
    const sub    = isDark ? '#777' : '#aaa';
    const cardBg = isDark ? '#161616' : '#fff';

    if (partners.length === 0) {
      return (
        <div style={{ textAlign: 'center', padding: '80px 24px', color: sub, fontFamily: "'Afacad', sans-serif" }}>
          <div style={{ fontFamily: "'Cormorant Garamond', serif", fontSize: 28, color: isDark ? '#333' : '#ccc', marginBottom: 10 }}>Loading partners…</div>
          <div style={{ fontSize: 13 }}>Connecting to Airtable Partners table.</div>
        </div>
      );
    }
    return (
      <div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
        {partners.map(ap => {
          const apCampaigns = campaigns.filter(c => ap.campaignIds.includes(c.id));
          const allTotals   = apCampaigns.reduce((acc, c) => {
            const t = calcTotals(c.metrics);
            return { impressions: acc.impressions + t.impressions, clicks: acc.clicks + t.clicks, reach: acc.reach + t.reach, engagement: acc.engagement + t.engagement };
          }, { impressions: 0, clicks: 0, reach: 0, engagement: 0 });
          return (
            <div key={ap.id} style={{ background: cardBg, border: `1px solid ${border}`, borderRadius: 14, overflow: 'hidden' }}>
              <div style={{ padding: '20px 24px', borderBottom: `1px solid ${border}`, background: isDark ? '#161616' : '#fdfaf6' }}>
                <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start' }}>
                  <div>
                    <h2 style={{ margin: 0, fontFamily: "'Cormorant Garamond', serif", fontSize: 22, fontWeight: 500, color: text }}>{ap.partner}</h2>
                    <div style={{ fontSize: 12, color: sub, fontFamily: "'Afacad', sans-serif", marginTop: 4 }}>Annual Contract · {ap.contractStart} – {ap.contractEnd}{ap.contactName ? ' · ' + ap.contactName : ''}</div>
                  </div>
                  <div style={{ textAlign: 'right' }}>
                    <div style={{ fontSize: 11, color: sub, fontFamily: "'Afacad', sans-serif" }}>Contract Value</div>
                    <div style={{ fontSize: 20, fontWeight: 700, color: '#C8975A', fontFamily: "'Afacad', sans-serif" }}>${ap.totalValue.toLocaleString()}</div>
                  </div>
                </div>
                <div style={{ display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', gap: 12, marginTop: 16 }}>
                  {[['Total Impressions', fmtNum(allTotals.impressions)], ['Total Clicks', fmtNum(allTotals.clicks)], ['Total Reach', fmtNum(allTotals.reach)], ['Engagement', fmtNum(allTotals.engagement)]].map(([l, v]) => (
                    <div key={l} style={{ background: isDark ? '#1e1e1e' : '#fff', border: `1px solid ${border}`, borderRadius: 8, padding: '10px 14px' }}>
                      <div style={{ fontSize: 10, color: sub, fontFamily: "'Afacad', sans-serif", letterSpacing: '0.04em' }}>{l.toUpperCase()}</div>
                      <div style={{ fontSize: 18, fontWeight: 700, color: text, fontFamily: "'Afacad', sans-serif", letterSpacing: '-0.02em', marginTop: 3 }}>{v}</div>
                    </div>
                  ))}
                </div>
              </div>
              <div style={{ padding: '14px 24px' }}>
                <div style={{ fontSize: 11, color: sub, fontFamily: "'Afacad', sans-serif", letterSpacing: '0.05em', marginBottom: 10 }}>CAMPAIGNS</div>
                {apCampaigns.length === 0 ? (
                  <div style={{ fontSize: 13, color: sub, fontFamily: "'Afacad', sans-serif" }}>No active campaigns linked</div>
                ) : apCampaigns.map(c => (
                  <div key={c.id} onClick={() => onSelectCampaign(c)}
                    style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', padding: '10px 14px', borderRadius: 8, cursor: 'pointer', transition: 'background 0.12s', marginBottom: 6 }}
                    onMouseEnter={e => e.currentTarget.style.background = isDark ? '#1e1e1e' : '#fafaf8'}
                    onMouseLeave={e => e.currentTarget.style.background = 'transparent'}>
                    <div>
                      <span style={{ fontSize: 14, fontFamily: "'Afacad', sans-serif", color: text, fontWeight: 500 }}>{c.campaignName}</span>
                      <span style={{ fontSize: 12, color: sub, fontFamily: "'Afacad', sans-serif", marginLeft: 10 }}>{c.startDate}{c.endDate ? ' – ' + c.endDate : ''}</span>
                    </div>
                    <StatusBadge status={c.status} />
                  </div>
                ))}
              </div>
            </div>
          );
        })}
      </div>
    );
  }

  // ─── Password Gate (admin only) ──────────────────────────────────────────
  const ADMIN_PASSWORD = 'locale2026';
  const ADMIN_KEY      = 'locale_admin_auth';

  function PasswordGate({ onAuth }) {
    const [pw, setPw]     = useState('');
    const [err, setErr]   = useState(false);
    function attempt() {
      if (pw === ADMIN_PASSWORD) {
        sessionStorage.setItem(ADMIN_KEY, '1');
        onAuth();
      } else {
        setErr(true);
        setPw('');
        setTimeout(() => setErr(false), 2000);
      }
    }
    return (
      <div style={{ minHeight: '100vh', background: '#fafaf8', display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', fontFamily: "'Afacad', sans-serif" }}>
        <img src="https://media.localemagazine.com/wp-content/uploads/2019/01/LocaleLogo_MagHub_178x48_300di.png" alt="Locale" style={{ height: 36, marginBottom: 36 }} />
        <div style={{ background: '#fff', border: '1px solid #ebebeb', borderRadius: 14, padding: '36px 40px', width: 320, boxShadow: '0 4px 24px #0000000a' }}>
          <div style={{ fontSize: 13, fontWeight: 600, color: '#1a1a18', marginBottom: 4 }}>Partner Dashboard</div>
          <div style={{ fontSize: 12, color: '#aaa', marginBottom: 24 }}>Enter your password to continue</div>
          <input
            type="password"
            placeholder="Password"
            value={pw}
            onChange={e => setPw(e.target.value)}
            onKeyDown={e => e.key === 'Enter' && attempt()}
            autoFocus
            style={{ width: '100%', padding: '10px 12px', border: `1px solid ${err ? '#e53e3e' : '#e0e0e0'}`, borderRadius: 8, fontSize: 13, fontFamily: "'Afacad', sans-serif", boxSizing: 'border-box', outline: 'none', marginBottom: 12, background: err ? '#fff5f5' : '#fff', transition: 'border 0.2s' }}
          />
          {err && <div style={{ fontSize: 11, color: '#e53e3e', marginBottom: 10 }}>Incorrect password — try again.</div>}
          <button onClick={attempt} style={{ width: '100%', padding: '11px 0', background: '#C8975A', border: 'none', borderRadius: 8, cursor: 'pointer', fontSize: 13, fontWeight: 600, color: '#fff', fontFamily: "'Afacad', sans-serif" }}>Enter</button>
        </div>
      </div>
    );
  }

  // ─── Main App ─────────────────────────────────────────────────────────────
  function App() {
    const urlParams      = new URLSearchParams(location.search);
    const isPartnerUrl   = urlParams.get('view') === 'partner';
    const partnerIdParam = urlParams.get('partnerId');

    // Admin auth — only required when NOT in partner view
    const [authed, setAuthed] = useState(
      isPartnerUrl || sessionStorage.getItem(ADMIN_KEY) === '1'
    );

    const [theme, setTheme]                       = useState('light');
    const [tab, setTab]                           = useState('campaigns');
    const [selectedCampaign, setSelectedCampaign] = useState(null);
    const [showSettings, setShowSettings]         = useState(false);
    const [campaigns, setCampaigns]               = useState([]);
    const [loadingLive, setLoadingLive]           = useState(false);
    const [liveError, setLiveError]               = useState(null);
    const [annualPartners, setAnnualPartners]     = useState([]);
    const [partnerName, setPartnerName]           = useState('');
    const [refreshKey, setRefreshKey]             = useState(0);
    const [showTweaks, setShowTweaks]             = useState(false);

    if (!authed) return <PasswordGate onAuth={() => setAuthed(true)} />;

    // ── Load campaigns + metrics automatically on mount ──────────────────
    const loadCampaigns = useCallback(() => {
      setLoadingLive(true);
      setLiveError(null);
      window.DashData.fetchLiveCampaigns(partnerIdParam || null)
        .then(cams => {
          setCampaigns(cams);
          setLoadingLive(false);
          // Resolve partner name from first campaign if in partner view
          if (isPartnerUrl && partnerIdParam && cams.length > 0) {
            setPartnerName(cams[0].partner || '');
          }
          // Fire metrics fetch for each campaign; update in-place as each resolves
          cams.forEach(async (cam, idx) => {
            try {
              const result = await window.DashData.fetchCampaignMetrics(cam);
              const metrics      = result.totals   || result;
              const timelineData = result.timeline || [];
              setCampaigns(prev => {
                const next = [...prev];
                if (next[idx]) next[idx] = { ...next[idx], metrics, timelineData };
                return next;
              });
            } catch(e) { /* silent */ }
          });
        })
        .catch(e => { setLiveError(e.message); setLoadingLive(false); });

      // Only load annual partners on admin view
      if (!isPartnerUrl) {
        window.DashData.fetchLivePartners()
          .then(pts => setAnnualPartners(pts))
          .catch(() => {});
      }
    }, []);

    // Auto-load on mount and whenever refreshKey bumps
    useEffect(() => { loadCampaigns(); }, [refreshKey]);

    // Auto-open single campaign in partner view
    useEffect(() => {
      if (isPartnerUrl && campaigns.length === 1 && !selectedCampaign) {
        setSelectedCampaign({ ...campaigns[0], isPartnerView: true });
      }
    }, [campaigns]);

    // Tweaks panel messaging
    useEffect(() => {
      window.addEventListener('message', e => {
        if (e.data?.type === '__activate_edit_mode')   setShowTweaks(true);
        if (e.data?.type === '__deactivate_edit_mode') setShowTweaks(false);
      });
      window.parent.postMessage({ type: '__edit_mode_available' }, '*');
    }, []);

    const isDark  = theme === 'dark';
    const bg      = isDark ? '#111'    : '#fafaf8';
    const border  = isDark ? '#2a2a2a' : '#ebebeb';
    const text    = isDark ? '#e0e0e0' : '#1a1a18';
    const sub     = isDark ? '#777'    : '#aaa';
    const cardBg  = isDark ? '#161616' : '#fff';

    // Meta token expiry warning (show in nav when ≤ 14 days)
    const daysLeft = metaDaysLeft();
    const showTokenWarning = daysLeft <= 14;

    if (selectedCampaign?.isPartnerView) {
      return <CampaignReport campaign={selectedCampaign} allCampaigns={campaigns} theme={theme} isPartnerView={true} onBack={() => setSelectedCampaign(null)} />;
    }
    if (selectedCampaign) {
      return <CampaignReport campaign={selectedCampaign} allCampaigns={campaigns} theme={theme} isPartnerView={false} onBack={() => setSelectedCampaign(null)} />;
    }

    // ── Partner share view ────────────────────────────────────────────────
    if (isPartnerUrl && partnerIdParam) {
      return (
        <div style={{ minHeight: '100vh', background: bg, fontFamily: "'Afacad', sans-serif" }}>
          {/* Partner nav */}
          <div style={{ background: isDark ? '#0d0d0d' : '#fff', borderBottom: `1px solid ${border}`, padding: '0 24px', height: 58, display: 'flex', alignItems: 'center', gap: 12 }}>
            <img src="https://media.localemagazine.com/wp-content/uploads/2019/01/LocaleLogo_MagHub_178x48_300di.png" alt="Locale Magazine" style={{ height: 32, objectFit: 'contain' }} />
            <span style={{ color: border, fontSize: 16 }}>|</span>
            <span style={{ fontSize: 11, color: sub, letterSpacing: '0.1em', fontWeight: 600 }}>PARTNER REPORT</span>
            <div style={{ flex: 1 }} />
            {loadingLive && <span style={{ fontSize: 12, color: '#C8975A' }}>Loading…</span>}
          </div>

          <div style={{ maxWidth: 900, margin: '0 auto', padding: '40px 24px' }}>
            {/* Partner name header */}
            {(partnerName || loadingLive) && (
              <div style={{ marginBottom: 32 }}>
                <div style={{ fontSize: 11, color: '#C8975A', letterSpacing: '0.1em', fontWeight: 600, marginBottom: 6 }}>YOUR CONTRACT</div>
                <h1 style={{ fontFamily: "'Cormorant Garamond', serif", fontSize: 36, fontWeight: 400, color: text, margin: 0, lineHeight: 1.1 }}>
                  {partnerName || '…'}
                </h1>
                <div style={{ width: 40, height: 2, background: '#C8975A', marginTop: 12 }} />
              </div>
            )}

            {loadingLive && (
              <div style={{ textAlign: 'center', padding: '60px 0', color: sub, fontFamily: "'Cormorant Garamond', serif", fontSize: 22 }}>Loading your campaign data…</div>
            )}

            {!loadingLive && campaigns.length === 0 && (
              <div style={{ textAlign: 'center', padding: '60px 0', color: sub, fontSize: 14 }}>No campaigns found for this contract.</div>
            )}

            {!loadingLive && campaigns.length > 0 && (
              <>
                <div style={{ fontSize: 13, color: sub, marginBottom: 20 }}>Select a campaign below to view your full performance report.</div>
                <CampaignsTab
                  campaigns={campaigns}
                  onSelect={c => setSelectedCampaign({ ...c, isPartnerView: true })}
                  theme={theme}
                />
              </>
            )}
          </div>
        </div>
      );
    }

    return (
      <div style={{ minHeight: '100vh', background: bg, fontFamily: "'Afacad', sans-serif" }}>

        {/* ── Top Nav ── */}
        <div style={{ background: isDark ? '#0d0d0d' : '#fff', borderBottom: `1px solid ${border}`, position: 'sticky', top: 0, zIndex: 10 }}>
          <div style={{ maxWidth: 1100, margin: '0 auto', padding: '0 24px', display: 'flex', alignItems: 'center', gap: 16, height: 58 }}>
            <img src="https://media.localemagazine.com/wp-content/uploads/2019/01/LocaleLogo_MagHub_178x48_300di.png" alt="Locale Magazine" style={{ height: 32, objectFit: 'contain', display: 'block' }} />
            <span style={{ color: border, fontSize: 16 }}>|</span>
            <span style={{ fontSize: 11, color: sub, letterSpacing: '0.1em', fontWeight: 600 }}>PARTNER DASHBOARD</span>
            <div style={{ flex: 1 }} />
            {/* Loading/error state */}
            {loadingLive && <span style={{ fontSize: 12, color: '#C8975A' }}>Loading live data…</span>}
            {liveError   && <span style={{ fontSize: 12, color: '#721c24' }}>Error: {liveError}</span>}
            {/* Token expiry warning — only shown when close to expiry */}
            {showTokenWarning && !loadingLive && (
              <button onClick={() => setShowSettings(true)} style={{ padding: '5px 12px', background: daysLeft <= 7 ? '#f8d7da' : '#fff3cd', border: `1px solid ${daysLeft <= 7 ? '#f5c6cb' : '#ffeaa7'}`, borderRadius: 20, cursor: 'pointer', fontSize: 11, fontWeight: 600, color: daysLeft <= 7 ? '#721c24' : '#856404', fontFamily: "'Afacad', sans-serif" }}>
                ⚠ Meta token expires in {daysLeft}d
              </button>
            )}
            {/* Subtle settings gear */}
            <button onClick={() => setShowSettings(true)} title="Settings" style={{ padding: '7px 10px', background: 'none', border: `1px solid ${border}`, borderRadius: 8, cursor: 'pointer', fontSize: 15, color: sub, lineHeight: 1 }}>⚙</button>
          </div>
        </div>

        {/* ── Settings Modal ── */}
        {showSettings && (
          <SettingsModal
            theme={theme}
            onClose={() => setShowSettings(false)}
            onRefresh={() => { setRefreshKey(k => k + 1); setShowSettings(false); }}
          />
        )}

        {/* ── Tab Bar ── */}
        <div style={{ borderBottom: `1px solid ${border}`, background: isDark ? '#0d0d0d' : '#fff' }}>
          <div style={{ maxWidth: 1100, margin: '0 auto', padding: '0 24px', display: 'flex', gap: 0 }}>
            {[
              ['campaigns', `Campaigns (${campaigns.length})`],
              ['annual',    `Annual Partners (${annualPartners.length})`],
            ].map(([id, label]) => (
              <button key={id} onClick={() => setTab(id)}
                style={{ padding: '12px 18px', background: 'none', border: 'none', cursor: 'pointer', fontSize: 13, fontWeight: tab === id ? 600 : 400, color: tab === id ? '#C8975A' : sub, borderBottom: `2px solid ${tab === id ? '#C8975A' : 'transparent'}`, transition: 'all 0.15s', fontFamily: "'Afacad', sans-serif", letterSpacing: '0.02em' }}>
                {label}
              </button>
            ))}
          </div>
        </div>

        {/* ── Content ── */}
        <div style={{ maxWidth: 1100, margin: '0 auto', padding: '28px 24px' }}>
          {tab === 'campaigns' && <CampaignsTab campaigns={campaigns} onSelect={setSelectedCampaign} theme={theme} />}
          {tab === 'annual'    && <AnnualPartnersTab partners={annualPartners} campaigns={campaigns} onSelectCampaign={setSelectedCampaign} theme={theme} />}
        </div>

        {/* ── Tweaks Panel ── */}
        {showTweaks && (
          <div style={{ position: 'fixed', bottom: 20, right: 20, background: isDark ? '#1e1e1e' : '#fff', border: `1px solid ${border}`, borderRadius: 14, padding: 20, width: 240, boxShadow: '0 8px 40px #0000001a', zIndex: 999 }}>
            <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 16 }}>
              <span style={{ fontFamily: "'Afacad', sans-serif", fontSize: 13, fontWeight: 600, color: text }}>Tweaks</span>
              <button onClick={() => { setShowTweaks(false); window.parent.postMessage({ type: '__edit_mode_dismissed' }, '*'); }} style={{ background: 'none', border: 'none', cursor: 'pointer', color: sub, fontSize: 16, lineHeight: 1 }}>×</button>
            </div>
            <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
              <div>
                <div style={{ fontSize: 11, color: sub, letterSpacing: '0.05em', marginBottom: 8 }}>THEME</div>
                <div style={{ display: 'flex', gap: 6 }}>
                  {[['light', 'Editorial Light'], ['dark', 'Dark Premium']].map(([val, lbl]) => (
                    <button key={val} onClick={() => setTheme(val)} style={{ flex: 1, padding: '8px 0', background: theme === val ? '#C8975A' : isDark ? '#2a2a2a' : '#f5f5f3', border: 'none', borderRadius: 8, cursor: 'pointer', fontSize: 11, fontWeight: 600, color: theme === val ? '#fff' : sub, fontFamily: "'Afacad', sans-serif" }}>{lbl}</button>
                  ))}
                </div>
              </div>
              {campaigns.length > 0 && (
                <div>
                  <div style={{ fontSize: 11, color: sub, letterSpacing: '0.05em', marginBottom: 8 }}>PREVIEW AS</div>
                  <div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
                    {campaigns.slice(0, 5).map(c => (
                      <button key={c.id} onClick={() => setSelectedCampaign(c)} style={{ padding: '8px 12px', background: isDark ? '#2a2a2a' : '#fafaf8', border: `1px solid ${border}`, borderRadius: 8, cursor: 'pointer', fontSize: 12, color: text, fontFamily: "'Afacad', sans-serif", textAlign: 'left' }}>
                        {c.partner}
                      </button>
                    ))}
                  </div>
                </div>
              )}
            </div>
          </div>
        )}
      </div>
    );
  }

  const root = ReactDOM.createRoot(document.getElementById('root'));
  root.render(<App />);
})();
