const TOPICS = ['Rumours & reporting', 'Betting lines & market movement', 'Injuries & availability', 'Numbers & data', 'Fantasy relevance', 'The business of sports', 'Coaching-related insights', 'Front office & contracts', 'Fan sentiment'];
const SOURCES = ['Word of mouth', 'Social media (advertising)', 'Social media (organic)', 'LLM chat response', 'Forwarded email'];
const INTENTS = [
  { id: 'fan', label: 'Fan', sub: 'I follow the team, not the market' },
  { id: 'bettor', label: 'Bettor', sub: 'Lines, edges, and closing value' },
  { id: 'fantasy', label: 'Fantasy player', sub: 'Usage, snaps, and matchups' },
];
const WEEKLIES = [
  { id: 'power', title: 'Team Power Rankings', sub: 'A weekly assessment of how our models feel about every team in the League', day: 'Tuesday' },
  { id: 'cdri', title: 'Coach Decision Ranking Index', sub: '4th-down decisions, clock management strategies, and scheme effectiveness', day: 'Wednesday' },
];
const LEAGUES = [
  { id: 'nba', label: 'NBA', when: 'Spring 2027', on: { bg: '#17408B', ink: '#FFFFFF', sub: 'rgba(255,255,255,0.75)', border: '#C8102E', accent: '#FFFFFF' } },
  { id: 'mlb', label: 'MLB', when: 'Spring 2027', on: { bg: '#FFFFFF', ink: '#000000', sub: 'rgba(0,0,0,0.6)', border: '#002D72', accent: '#D50032' } },
  { id: 'nhl', label: 'NHL', when: 'Winter 2026', on: { bg: '#000000', ink: '#FFFFFF', sub: 'rgba(255,255,255,0.72)', border: '#F26A21', accent: '#F26A21' } },
];
const teamKey = (t) => t.city + ' ' + t.name;

function StepTeams({ v, set, update }) {
  const teams = window.NFL_TEAMS;
  const max = 3;
  const toggle = (k) => update(prev => {
    const has = prev.teams.includes(k);
    if (!has && prev.teams.length >= max) return prev;
    const next = has ? prev.teams.filter(x => x !== k) : prev.teams.concat(k);
    const cad = Object.assign({}, prev.teamCadence); const on = Object.assign({}, prev.teamOn);
    if (!has) { cad[k] = cad[k] || 'daily'; on[k] = true; }
    return Object.assign({}, prev, { teams: next, teamCadence: cad, teamOn: on });
  });
  const [q, setQ] = React.useState('');
  const query = q.trim().toLowerCase();
  const matches = query ? teams.filter(t => (t.city + ' ' + t.name + ' ' + t.conf + ' ' + t.div).toLowerCase().includes(query)) : null;
  return (
    <React.Fragment>
      <StepHead eyebrow="Step 1 of 5" title="Pick your NFL teams." lead="Each team you pick gets its own newsletter. You set the cadence on the next step." />
      <div style={{ display: 'flex', alignItems: 'center', gap: 16, marginBottom: 26, flexWrap: 'wrap' }}>
        <div style={{ position: 'relative', width: '100%', maxWidth: 300 }}>
          <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" style={{ position: 'absolute', left: 13, top: 12, color: 'var(--syn-fg-subtle)', pointerEvents: 'none' }}><circle cx="11" cy="11" r="7"></circle><line x1="16.5" y1="16.5" x2="21" y2="21"></line></svg>
          <input type="text" value={q} onChange={e => setQ(e.target.value)} placeholder="Search teams or cities" style={{
            width: '100%', boxSizing: 'border-box', padding: '10px 34px 10px 38px',
            fontFamily: 'var(--syn-font-body)', fontSize: 14.5,
            border: '1px solid var(--syn-rule-strong)', borderRadius: 'var(--syn-radius-md)',
            background: 'var(--syn-bg-elev)', color: 'var(--syn-fg)', outline: 'none',
          }} />
          {q ? <button type="button" onClick={() => setQ('')} aria-label="Clear search" style={{ position: 'absolute', right: 8, top: 8, width: 24, height: 24, display: 'flex', alignItems: 'center', justifyContent: 'center', background: 'none', border: 0, padding: 0, cursor: 'pointer', color: 'var(--syn-fg-subtle)', fontFamily: 'var(--syn-font-body)', fontSize: 16, lineHeight: 1 }}>×</button> : null}
        </div>
        <div style={{ fontFamily: 'var(--syn-font-mono)', fontSize: 12, letterSpacing: '0.08em', color: v.teams.length === max ? 'var(--syn-orange-700)' : 'var(--syn-fg-subtle)' }}>{v.teams.length} / {max} SELECTED</div>
        {v.teams.length ? <button type="button" onClick={() => set({ teams: [] })} style={{ background: 'none', border: 0, padding: 0, fontFamily: 'var(--syn-font-body)', fontSize: 13, color: 'var(--syn-fg-subtle)', textDecoration: 'underline', cursor: 'pointer' }}>Clear</button> : null}
      </div>
      {matches ? (
        matches.length ? (
          <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill,minmax(200px,1fr))', gap: 10, maxWidth: 660 }}>
            {matches.map(t => {
              const k = teamKey(t); const sel = v.teams.includes(k);
              return <TeamChip key={k} team={t} selected={sel} disabled={!sel && v.teams.length >= max} onClick={() => toggle(k)} />;
            })}
          </div>
        ) : (
          <div style={{ fontFamily: 'var(--syn-font-body)', fontSize: 14.5, color: 'var(--syn-fg-subtle)' }}>No teams match "{q.trim()}".</div>
        )
      ) : (
      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit,minmax(300px,1fr))', gap: 34 }}>
        {['AFC', 'NFC'].map(conf => (
          <div key={conf}>
            <div style={{ fontFamily: 'var(--syn-font-display)', fontSize: 15, fontWeight: 600, letterSpacing: '0.02em', color: 'var(--syn-fg)', paddingBottom: 10, borderBottom: '1px solid var(--syn-rule)', marginBottom: 18 }}>{conf}</div>
            {['East', 'North', 'South', 'West'].map(div => (
              <div key={div} style={{ marginBottom: 18 }}>
                <div style={{ fontFamily: 'var(--syn-font-mono)', fontSize: 10.5, letterSpacing: '0.16em', textTransform: 'uppercase', color: 'var(--syn-fg-subtle)', marginBottom: 9 }}>{conf} {div}</div>
                <div style={{ display: 'grid', gridTemplateColumns: 'repeat(2,minmax(0,1fr))', gap: 10 }}>
                  {teams.filter(t => t.conf === conf && t.div === div).map(t => {
                    const k = teamKey(t); const sel = v.teams.includes(k);
                    return <TeamChip key={k} team={t} selected={sel} disabled={!sel && v.teams.length >= max} onClick={() => toggle(k)} />;
                  })}
                </div>
              </div>
            ))}
          </div>
        ))}
      </div>
      )}
    </React.Fragment>
  );
}

function StepNewsletters({ v, set }) {
  const { isPhone } = window.useIsMobile();
  // On phone, "label on the left, controls on the right" rows crush the label to
  // one-word-per-line. Stack them: label on top, controls below, both full width.
  const rowStack = isPhone
    ? { flexDirection: 'column', alignItems: 'stretch', gap: 14 }
    : {};
  React.useEffect(() => {
    if (document.getElementById('syn-pulse-rule-css')) return;
    const el = document.createElement('style'); el.id = 'syn-pulse-rule-css';
    el.textContent = '@keyframes synPulseRule{0%,100%{border-color:var(--syn-red);box-shadow:0 0 0 0 rgba(235,108,95,0.30)}50%{border-color:var(--syn-red-700);box-shadow:0 0 0 5px rgba(235,108,95,0)}}.syn-pulse-rule{animation:synPulseRule 2.4s cubic-bezier(0.2,0.7,0.2,1) infinite}@media (prefers-reduced-motion:reduce){.syn-pulse-rule{animation:none}}';
    document.head.appendChild(el);
  }, []);
  const teams = window.NFL_TEAMS;
  const byKey = (k) => teams.find(t => teamKey(t) === k) || {};
  const solo = v.teams.length === 1 ? byKey(v.teams[0]) : null;
  const soloColor = solo && solo.color ? solo.color : null;
  const soloLight = soloColor ? lum(soloColor) > 0.42 : false;
  const soloInk = soloColor ? (soloLight ? 'var(--syn-navy)' : '#FFFFFF') : null;
  const soloSubInk = soloColor ? (soloLight ? 'rgba(20,43,77,0.72)' : 'rgba(255,255,255,0.78)') : null;
  const soloRule = soloColor ? (soloLight ? 'rgba(20,43,77,0.18)' : 'rgba(255,255,255,0.24)') : null;
  return (
    <React.Fragment>
      <StepHead eyebrow="Step 2 of 5" title="Set the cadence." lead="Every subscription is independent. Choose between daily, or thrice weekly delivery." />
      <div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
        <Panel style={soloColor ? { background: soloColor, borderColor: soloColor, transition: `background-color 200ms ${EASE}` } : { transition: `background-color 200ms ${EASE}` }}>
          <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between', gap: 16, marginBottom: 18 }}>
            <div style={{ fontFamily: 'var(--syn-font-display)', fontSize: 20, fontWeight: 600, letterSpacing: '-0.02em', color: soloInk || 'var(--syn-navy)' }}>Team newsletters</div>
            <div style={{ fontFamily: 'var(--syn-font-mono)', fontSize: 11, letterSpacing: '0.16em', textTransform: 'uppercase', fontWeight: 500, color: soloSubInk || 'var(--syn-fg-subtle)' }}>{v.teams.length} team{v.teams.length === 1 ? '' : 's'}</div>
          </div>
          {v.teams.length === 0 ? (
            <div style={{ fontFamily: 'var(--syn-font-body)', fontSize: 14, color: soloSubInk || 'var(--syn-fg-subtle)' }}>No teams selected — go back a step to add up to three.</div>
          ) : (
            <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
              {v.teams.map((k, i) => {
                const t = byKey(k); const on = v.teamOn[k] !== false;
                return (
                  <div key={k} style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 16, flexWrap: 'wrap', paddingTop: i ? 14 : 0, borderTop: i ? `1px solid ${soloRule || 'var(--syn-rule)'}` : 'none', ...rowStack }}>
                    <RowLabel dot={soloColor ? null : t.color} title={k} sub={on ? 'Reporting, rumours, performance data, fan sentiment' : 'Paused'} ink={soloInk} subInk={soloSubInk} />
                    <div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
                      <CadencePicker value={v.teamCadence[k] || 'daily'} disabled={!on} onChange={c => set({ teamCadence: Object.assign({}, v.teamCadence, { [k]: c }) })} />
                      <Toggle on={on} onChange={val => set({ teamOn: Object.assign({}, v.teamOn, { [k]: val }) })} invert={!!soloColor && !soloLight && on} />
                    </div>
                  </div>
                );
              })}
            </div>
          )}
        </Panel>
        <Panel>
          <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 16, flexWrap: 'wrap', ...rowStack }}>
            <RowLabel title="NFL league-wide" sub="The most important factors influencing outcomes across all 32 teams" />
            <div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
              <CadencePicker value={v.league.cadence} disabled={!v.league.on} onChange={c => set({ league: Object.assign({}, v.league, { cadence: c }) })} />
              <Toggle on={v.league.on} onChange={val => set({ league: Object.assign({}, v.league, { on: val }) })} />
            </div>
          </div>
        </Panel>
        {WEEKLIES.map(w => (
          <Panel key={w.id} className="syn-pulse-rule" style={{ borderColor: 'var(--syn-red)' }}>
            <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 16, flexWrap: 'wrap', ...rowStack }}>
              <div style={{ flex: 1, minWidth: 0 }}>
                <div style={{ display: 'flex', alignItems: 'center', gap: 10, marginBottom: 3, flexWrap: 'wrap' }}>
                  <div style={{ fontFamily: 'var(--syn-font-body)', fontSize: 15, fontWeight: 600, color: 'var(--syn-fg)' }}>{w.title}</div>
                  <span style={{ fontFamily: 'var(--syn-font-mono)', fontSize: 10, letterSpacing: '0.14em', textTransform: 'uppercase', color: 'var(--syn-red-700)', border: '1px solid var(--syn-red)', borderRadius: 'var(--syn-radius-pill)', padding: '3px 9px' }}>New</span>
                </div>
                <div style={{ fontFamily: 'var(--syn-font-body)', fontSize: 13, color: 'var(--syn-fg-subtle)' }}>{w.sub}</div>
              </div>
              <div style={{ display: 'flex', alignItems: 'center', gap: 12, flexShrink: 0 }}>
                <span style={{ fontFamily: 'var(--syn-font-mono)', fontSize: 11, letterSpacing: '0.1em', textTransform: 'uppercase', color: 'var(--syn-fg-subtle)', border: '1px solid var(--syn-rule)', borderRadius: 'var(--syn-radius-pill)', padding: '6px 12px', whiteSpace: 'nowrap' }}>{w.day}s · weekly</span>
                <Toggle on={!!v.weeklies[w.id]} onChange={val => set({ weeklies: Object.assign({}, v.weeklies, { [w.id]: val }) })} />
              </div>
            </div>
          </Panel>
        ))}
        <Panel muted style={{ borderStyle: 'solid', borderColor: v.topPicks ? 'var(--syn-navy)' : 'var(--syn-rule)', background: v.topPicks ? 'var(--syn-navy)' : 'var(--syn-paper-2)', transition: `background-color 200ms ${EASE}, border-color 200ms ${EASE}` }}>
          <div style={{ display: 'flex', alignItems: 'flex-start', justifyContent: 'space-between', gap: 16, flexWrap: 'wrap', ...rowStack }}>
            <div style={{ maxWidth: 520 }}>
              <div style={{ display: 'flex', alignItems: 'center', gap: 10, marginBottom: 6 }}>
                <div style={{ fontFamily: 'var(--syn-font-body)', fontSize: 15, fontWeight: 600, color: v.topPicks ? '#FFFFFF' : 'var(--syn-fg-muted)' }}>Top Picks</div>
                <span style={{ fontFamily: 'var(--syn-font-mono)', fontSize: 10, letterSpacing: '0.14em', textTransform: 'uppercase', color: v.topPicks ? 'var(--syn-amber)' : 'var(--syn-orange-700)', border: `1px solid ${v.topPicks ? 'var(--syn-amber)' : 'var(--syn-orange)'}`, borderRadius: 'var(--syn-radius-pill)', padding: '3px 9px' }}>Coming soon</span>
              </div>
              <div style={{ fontFamily: 'var(--syn-font-body)', fontSize: 13.5, lineHeight: 1.55, color: v.topPicks ? 'rgba(255,255,255,0.78)' : 'var(--syn-fg-subtle)' }}>Our highest-conviction reads of the week, sourced and ranked. Coming soon with Synth Sidecar premium subscription — Winter 2026</div>
            </div>
            <label style={{ display: 'flex', alignItems: 'center', gap: 10, cursor: 'pointer' }}>
              <span style={{ fontFamily: 'var(--syn-font-body)', fontSize: 13, color: v.topPicks ? '#FFFFFF' : 'var(--syn-fg-muted)' }}>Notify me</span>
              <Toggle on={v.topPicks} onChange={val => set({ topPicks: val })} invert={v.topPicks} />
            </label>
          </div>
        </Panel>
      </div>
    </React.Fragment>
  );
}

function StepSignals({ v, set }) {
  const toggleTopic = (t) => set({ topics: v.topics.includes(t) ? v.topics.filter(x => x !== t) : v.topics.concat(t) });
  return (
    <React.Fragment>
      <StepHead eyebrow="Step 4 of 5" title="What information earns your morning read?" lead="Pick any number of signals that apply to you." />
      <div style={{ display: 'flex', flexWrap: 'wrap', gap: 10, marginBottom: 44 }}>
        {TOPICS.map(t => <OptionChip key={t} label={t} selected={v.topics.includes(t)} onClick={() => toggleTopic(t)} />)}
      </div>
      <div style={{ fontFamily: 'var(--syn-font-display)', fontSize: 22, fontWeight: 600, letterSpacing: '-0.025em', color: 'var(--syn-navy)', marginBottom: 6 }}>What type of reader are you?</div>
      <p style={{ fontFamily: 'var(--syn-font-body)', fontSize: 14, color: 'var(--syn-fg-subtle)', margin: '0 0 18px' }}>Your priorities when consuming sports content.</p>
      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit,minmax(200px,1fr))', gap: 12 }}>
        {INTENTS.map(o => {
          const sel = v.intent === o.id;
          return (
            <button key={o.id} type="button" onClick={() => set({ intent: o.id })} style={{
              textAlign: 'left', padding: '18px 20px', borderRadius: 'var(--syn-radius-lg)', cursor: 'pointer',
              border: `1px solid ${sel ? 'var(--syn-navy)' : 'var(--syn-rule)'}`,
              background: sel ? 'var(--syn-navy)' : 'var(--syn-bg-elev)',
              boxShadow: sel ? 'var(--syn-shadow-sm)' : 'none',
              transition: `background-color 160ms ${EASE}, border-color 160ms ${EASE}`,
            }}>
              <div style={{ fontFamily: 'var(--syn-font-display)', fontSize: 19, fontWeight: 600, letterSpacing: '-0.02em', color: sel ? 'var(--syn-paper)' : 'var(--syn-navy)', marginBottom: 5 }}>{o.label}</div>
              <div style={{ fontFamily: 'var(--syn-font-body)', fontSize: 13, lineHeight: 1.45, color: sel ? 'var(--syn-navy-300)' : 'var(--syn-fg-subtle)' }}>{o.sub}</div>
            </button>
          );
        })}
      </div>
      <div style={{ fontFamily: 'var(--syn-font-display)', fontSize: 22, fontWeight: 600, letterSpacing: '-0.025em', color: 'var(--syn-navy)', margin: '44px 0 6px' }}>How did you hear about Synth?</div>
      <p style={{ fontFamily: 'var(--syn-font-body)', fontSize: 14, color: 'var(--syn-fg-subtle)', margin: '0 0 18px' }}>Helps us know where our readers are coming from.</p>
      <div style={{ display: 'flex', flexWrap: 'wrap', gap: 10 }}>
        {SOURCES.map(o => <OptionChip key={o} label={o} selected={v.source === o} onClick={() => set({ source: v.source === o ? '' : o })} />)}
      </div>
    </React.Fragment>
  );
}

function StepLeagues({ v, set }) {
  return (
    <React.Fragment>
      <StepHead eyebrow="Step 3 of 5" title="What league do you want to see next?" lead="Get first access when the next league lands." />
      <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
        {LEAGUES.map(l => {
          const on = !!v.leagues[l.id]; const c = l.on;
          return (
            <Panel key={l.id} style={{
              padding: '22px 26px',
              background: on ? c.bg : 'var(--syn-bg-elev)',
              borderColor: on ? c.border : 'var(--syn-rule)',
              borderWidth: on ? 2 : 1,
              transition: `background-color 200ms ${EASE}, border-color 200ms ${EASE}`,
            }}>
              <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 16 }}>
                <div style={{ display: 'flex', alignItems: 'center', gap: 16, minWidth: 0 }}>
                  <span style={{ width: 4, height: 34, borderRadius: 2, background: on ? c.accent : 'var(--syn-rule-strong)', flexShrink: 0, transition: `background-color 200ms ${EASE}` }} />
                  <div style={{ minWidth: 0 }}>
                    <div style={{ fontFamily: 'var(--syn-font-display)', fontSize: 21, fontWeight: 600, letterSpacing: '-0.02em', color: on ? c.ink : 'var(--syn-navy)' }}>{l.label}</div>
                    <div style={{ fontFamily: 'var(--syn-font-body)', fontSize: 13, color: on ? c.sub : 'var(--syn-fg-subtle)', marginTop: 3 }}>Launching {l.when}</div>
                  </div>
                </div>
                <Toggle on={on} onChange={val => set({ leagues: Object.assign({}, v.leagues, { [l.id]: val }) })} invert={on && l.id !== 'mlb'} />
              </div>
            </Panel>
          );
        })}
      </div>
    </React.Fragment>
  );
}

function SummaryRow({ label, children }) {
  const { isPhone } = window.useIsMobile();
  return (
    <div style={{ display: 'flex', flexDirection: isPhone ? 'column' : 'row', gap: isPhone ? 6 : 24, padding: '16px 0', borderBottom: '1px solid var(--syn-rule)', alignItems: 'flex-start' }}>
      <div style={{ width: isPhone ? 'auto' : 150, flexShrink: 0, fontFamily: 'var(--syn-font-mono)', fontSize: 11, letterSpacing: '0.14em', textTransform: 'uppercase', color: 'var(--syn-fg-subtle)', paddingTop: 3 }}>{label}</div>
      <div style={{ fontFamily: 'var(--syn-font-body)', fontSize: 15, lineHeight: 1.6, color: 'var(--syn-fg)', minWidth: 0 }}>{children}</div>
    </div>
  );
}

function StepConfirm({ v, set, onEdit }) {
  const teams = window.NFL_TEAMS;
  const byKey = (k) => teams.find(t => teamKey(t) === k) || {};
  const active = v.teams.filter(k => v.teamOn[k] !== false);
  const leagues = LEAGUES.filter(l => v.leagues[l.id]);
  const intent = (INTENTS.find(i => i.id === v.intent) || {}).label;
  return (
    <React.Fragment>
      <StepHead eyebrow="Step 5 of 5" title="Here's what will land in your inbox." lead="Confirm the address it lands at. Everything below is editable later from any issue footer." />
      <div>
        <SummaryRow label="Email">
          <input type="email" value={v.email} onChange={e => set({ email: e.target.value })} placeholder="you@domain.com" style={{
            width: 320, maxWidth: '100%', boxSizing: 'border-box', padding: '10px 13px',
            fontFamily: 'var(--syn-font-body)', fontSize: 15,
            border: '1px solid var(--syn-rule-strong)', borderRadius: 'var(--syn-radius-md)',
            background: 'var(--syn-bg-elev)', color: 'var(--syn-fg)', outline: 'none',
          }} />
        </SummaryRow>
        <SummaryRow label="Team newsletters">
          {active.length ? (
            <div style={{ display: 'flex', flexDirection: 'column', gap: 7 }}>
              {active.map(k => (
                <div key={k} style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
                  <span style={{ width: 9, height: 9, borderRadius: 999, background: byKey(k).color }} />
                  <span>{k}</span>
                  <span style={{ fontFamily: 'var(--syn-font-mono)', fontSize: 12, color: 'var(--syn-fg-subtle)' }}>{cadenceLabel(v.teamCadence[k] || 'daily')}</span>
                </div>
              ))}
            </div>
          ) : <span style={{ color: 'var(--syn-fg-subtle)' }}>None</span>}
        </SummaryRow>
        <SummaryRow label="NFL league-wide">{v.league.on ? <span>Subscribed <span style={{ fontFamily: 'var(--syn-font-mono)', fontSize: 12, color: 'var(--syn-fg-subtle)' }}>{cadenceLabel(v.league.cadence)}</span></span> : <span style={{ color: 'var(--syn-fg-subtle)' }}>Not subscribed</span>}</SummaryRow>
        <SummaryRow label="Weekly indexes">{WEEKLIES.filter(w => v.weeklies[w.id]).length ? WEEKLIES.filter(w => v.weeklies[w.id]).map(w => w.title + ' · ' + w.day + 's').join('  ·  ') : <span style={{ color: 'var(--syn-fg-subtle)' }}>None</span>}</SummaryRow>
        <SummaryRow label="Top Picks">{v.topPicks ? 'Notify at Sidecar launch — Winter 2026' : <span style={{ color: 'var(--syn-fg-subtle)' }}>Skipped</span>}</SummaryRow>
        <SummaryRow label="Signals">{v.topics.length ? v.topics.join(' · ') : <span style={{ color: 'var(--syn-fg-subtle)' }}>No preference</span>}</SummaryRow>
        <SummaryRow label="Heard about us">{v.source || <span style={{ color: 'var(--syn-fg-subtle)' }}>Not shared</span>}</SummaryRow>
        <SummaryRow label="Reading as">{intent || <span style={{ color: 'var(--syn-fg-subtle)' }}>No preference</span>}</SummaryRow>
        <SummaryRow label="Next leagues">{leagues.length ? leagues.map(l => l.label + ' · ' + l.when).join('  ·  ') : <span style={{ color: 'var(--syn-fg-subtle)' }}>None</span>}</SummaryRow>
        <button type="button" onClick={() => onEdit(0)} style={{ marginTop: 20, background: 'none', border: 0, padding: 0, fontFamily: 'var(--syn-font-body)', fontSize: 14, color: 'var(--syn-fg-muted)', textDecoration: 'underline', cursor: 'pointer' }}>Change my teams</button>
      </div>
    </React.Fragment>
  );
}

function StepDone({ v, onNav }) {
  const count = v.teams.filter(k => v.teamOn[k] !== false).length + (v.league.on ? 1 : 0);
  return (
    <div style={{ maxWidth: 560 }}>
      <Eyebrow>You're in</Eyebrow>
      <h1 style={{ fontFamily: 'var(--syn-font-display)', fontSize: 52, fontWeight: 600, letterSpacing: '-0.035em', lineHeight: 1.05, color: 'var(--syn-navy)', margin: '16px 0 16px' }}>{count} subscription{count === 1 ? '' : 's'} confirmed.</h1>
      <p style={{ fontFamily: 'var(--syn-font-display)', fontSize: 19, lineHeight: 1.5, color: 'var(--syn-fg-muted)', margin: '0 0 32px', fontWeight: 400 }}>First issue lands with Week 1 of the 2026 NFL season. Confirmation sent to {v.email || 'your inbox'}.</p>
      <button type="button" onClick={() => onNav('home')} style={{ background: 'var(--syn-navy)', color: 'var(--syn-paper)', border: 0, borderRadius: 'var(--syn-radius-md)', padding: '14px 24px', fontFamily: 'var(--syn-font-body)', fontSize: 15, fontWeight: 500, cursor: 'pointer' }}>Back to Synth</button>
    </div>
  );
}

Object.assign(window, { TOPICS, SOURCES, INTENTS, WEEKLIES, LEAGUES, teamKey, StepTeams, StepNewsletters, StepSignals, StepLeagues, StepConfirm, StepDone, SummaryRow });
