// Reveals children when scrolled into view (respects reduced motion).
function Reveal({ children, delay = 0, y = 28, style = {} }) {
  const ref = React.useRef(null);
  const [shown, setShown] = React.useState(false);
  React.useEffect(() => {
    const reduce = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
    if (reduce) { setShown(true); return; }
    const el = ref.current;
    if (!el) return;
    const io = new IntersectionObserver((entries) => {
      entries.forEach(e => { if (e.isIntersecting) { setShown(true); io.unobserve(e.target); } });
    }, { threshold: 0.25 });
    io.observe(el);
    return () => io.disconnect();
  }, []);
  return (
    <div ref={ref} style={{
      ...style,
      opacity: shown ? 1 : 0,
      transform: shown ? 'none' : `translateY(${y}px)`,
      transition: `opacity 640ms cubic-bezier(0.16,1,0.3,1) ${delay}ms, transform 640ms cubic-bezier(0.16,1,0.3,1) ${delay}ms`,
    }}>{children}</div>
  );
}

// The defining brand element: a 0–100 fan-sentiment ring.
function SentimentRing({ value = 62, size = 92, label = 'Fan sentiment', mood = 'Cautiously up' }) {
  const stroke = 8, r = (size - stroke) / 2, c = 2 * Math.PI * r;
  const arc = (value / 100) * c;
  const hue = value >= 60 ? 'var(--syn-up)' : value >= 45 ? 'var(--syn-orange)' : 'var(--syn-red-700)';
  return (
    <div style={{ display: 'flex', alignItems: 'center', gap: 16 }}>
      <div style={{ position: 'relative', width: size, height: size, flexShrink: 0 }}>
        <svg width={size} height={size} style={{ transform: 'rotate(-90deg)' }}>
          <circle cx={size/2} cy={size/2} r={r} fill="none" stroke="var(--syn-paper-3)" strokeWidth={stroke} />
          <circle cx={size/2} cy={size/2} r={r} fill="none" stroke={hue} strokeWidth={stroke}
            strokeDasharray={`${arc} ${c}`} strokeLinecap="round" />
        </svg>
        <div style={{
          position: 'absolute', inset: 0, display: 'flex', flexDirection: 'column',
          alignItems: 'center', justifyContent: 'center',
        }}>
          <span style={{
            fontFamily: 'var(--syn-font-display)', fontWeight: 700,
            fontVariantNumeric: 'tabular-nums', fontSize: 28,
            letterSpacing: '-0.03em', color: 'var(--syn-navy)', lineHeight: 1,
          }}>{value}</span>
        </div>
      </div>
      <div>
        <div style={{
          fontFamily: 'var(--syn-font-mono)', fontSize: 10,
          letterSpacing: '0.14em', textTransform: 'uppercase',
          color: 'var(--syn-fg-subtle)', fontWeight: 600, marginBottom: 5,
        }}>{label}</div>
        <div style={{
          fontFamily: 'var(--syn-font-body)', fontSize: 14,
          color: 'var(--syn-fg-muted)', lineHeight: 1.4, maxWidth: 150,
        }}>{mood}</div>
      </div>
    </div>
  );
}

// Content card whose outline draws itself on as the user scrolls.
// Peripheral meta stays; the only body content is the section copy.
function SignalsCard() {
  const cardRef = React.useRef(null);
  const [dim, setDim] = React.useState({ w: 860, h: 480 });
  const [prog, setProg] = React.useState(0);
  const { isPhone } = window.useIsMobile();

  React.useEffect(() => {
    const measure = () => { const el = cardRef.current; if (el) setDim({ w: el.offsetWidth, h: el.offsetHeight }); };
    measure();
    window.addEventListener('resize', measure);
    return () => window.removeEventListener('resize', measure);
  }, []);

  React.useEffect(() => {
    const reduce = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
    if (reduce) { setProg(1); return; }
    let raf = 0;
    const onScroll = () => {
      cancelAnimationFrame(raf);
      raf = requestAnimationFrame(() => {
        const el = cardRef.current; if (!el) return;
        const rect = el.getBoundingClientRect();
        const vh = window.innerHeight || 800;
        const start = vh * 0.94, end = vh * 0.4;
        const p = (start - rect.top) / (start - end);
        setProg(Math.max(0, Math.min(1, p)));
      });
    };
    onScroll();
    window.addEventListener('scroll', onScroll, { passive: true });
    return () => { window.removeEventListener('scroll', onScroll); cancelAnimationFrame(raf); };
  }, []);

  const r = 24, sw = 1.75, inset = sw / 2;
  const { w, h } = dim;
  const rw = w - inset * 2, rh = h - inset * 2;
  const path = `M ${inset + r},${inset} H ${inset + rw - r} A ${r},${r} 0 0 1 ${inset + rw},${inset + r} V ${inset + rh - r} A ${r},${r} 0 0 1 ${inset + rw - r},${inset + rh} H ${inset + r} A ${r},${r} 0 0 1 ${inset},${inset + rh - r} V ${inset + r} A ${r},${r} 0 0 1 ${inset + r},${inset} Z`;
  const perim = 2 * (rw - 2 * r) + 2 * (rh - 2 * r) + 2 * Math.PI * r;
  const contentP = Math.max(0, Math.min(1, (prog - 0.5) / 0.42));

  return (
    <div ref={cardRef} style={{
      position: 'relative', width: 860, maxWidth: '100%', padding: isPhone ? 24 : 60, boxSizing: 'border-box',
      borderRadius: r,
      boxShadow: `0 24px 60px -34px rgba(0,0,0,${0.55 * contentP})`,
    }}>
      <svg width={w} height={h} viewBox={`0 0 ${w} ${h}`} style={{ position: 'absolute', inset: 0, overflow: 'visible', pointerEvents: 'none' }}>
        <path d={path} fill="none" stroke="#FBF7F1" strokeWidth={sw} strokeLinecap="round"
          strokeDasharray={perim} strokeDashoffset={perim * (1 - prog)} />
      </svg>
      <div style={{
        display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 40,
        opacity: contentP, transition: 'opacity 240ms linear',
      }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
          <span style={{
            fontFamily: 'var(--syn-font-mono)', fontSize: 14, fontWeight: 600,
            letterSpacing: '0.08em', color: 'var(--syn-navy)',
            background: 'var(--syn-cream)', padding: '5px 12px', borderRadius: 999,
          }}>DAL</span>
          <span style={{
            fontFamily: 'var(--syn-font-mono)', fontSize: 14,
            letterSpacing: '0.1em', textTransform: 'uppercase',
            color: 'var(--syn-navy-300)',
          }}>NFL · Week 9</span>
        </div>
        <span style={{ fontFamily: 'var(--syn-font-mono)', fontSize: 14, color: 'var(--syn-navy-300)' }}>11/02/26</span>
      </div>
      <div style={{
        opacity: contentP, transform: `translateY(${(1 - contentP) * 14}px)`,
        transition: 'opacity 240ms linear, transform 240ms linear',
      }}>
        <h2 style={{
          fontFamily: 'var(--syn-font-display)', fontSize: isPhone ? 34 : 62, fontWeight: 600,
          letterSpacing: '-0.03em', lineHeight: 1.06, color: '#FBF7F1', margin: '0 0 30px',
        }}>Your team's day, at a glance</h2>
        <p style={{
          fontFamily: 'var(--syn-font-body)', fontSize: isPhone ? 17 : 23, lineHeight: 1.6,
          color: '#C8CFDC', margin: 0,
        }}>The stats, the trade talk, the injury report, and the fan mood, written into content cards that capture where your team stands today. <b><br />Built to be read in ten seconds and remembered all season.</b></p>
      </div>
    </div>
  );
}

// ---- Interactive fan-sentiment season chart -----------------------------
const SEASON = [
  { wk: 1,  s: 53, r: 'L', opp: '@PHI', score: '20–24', aspect: 'Cowboys defensive potential without Micah Parsons', event: true, kind: 'trade' },
  { wk: 2,  s: 55, r: 'W', opp: 'NYG',  score: '40–37', aspect: 'Defensive collapse against Russell Wilson' },
  { wk: 3,  s: 28, r: 'L', opp: '@CHI', score: '14–31', aspect: 'Underestimated the Bears as a trap game', event: true, kind: 'low' },
  { wk: 4,  s: 48, r: 'T', opp: 'GB',   score: '40–40', aspect: 'An overtime tie feels like an unsatisfying ending to the Micah Bowl' },
  { wk: 5,  s: 69, r: 'W', opp: '@NYJ', score: '37–22', aspect: "Cowboys playoff hopes and Dak Prescott's performance" },
  { wk: 6,  s: 31, r: 'L', opp: '@CAR', score: '27–30', aspect: 'Run defense collapses vs Rico Dowdle' },
  { wk: 7,  s: 54, r: 'W', opp: 'WAS',  score: '44–22', aspect: "Dak Prescott's excellence carries the offense" },
  { wk: 8,  s: 26, r: 'L', opp: '@DEN', score: '24–44', aspect: 'Defensive collapse against the Broncos', event: true, kind: 'low' },
  { wk: 9,  s: 36, r: 'L', opp: 'ARI',  score: '17–27', aspect: "Dallas secondary gashed by the Cardinals' passing game" },
  { wk: 10, s: 60, opp: 'Bye Week', aspect: 'Quinnen Williams defensive addition', event: true, kind: 'trade' },
  { wk: 11, s: 57, r: 'W', opp: '@LV',  score: '33–16', aspect: "Marshawn Kneeland's passing, and its impact on the team" },
  { wk: 12, s: 59, r: 'W', opp: 'PHI',  score: '24–21', aspect: 'Inconsistency against quality vs weak opponents' },
  { wk: 13, s: 62, r: 'W', opp: 'KC',   score: '31–28', aspect: 'Thanksgiving upset of the defending champs', event: true, kind: 'high' },
  { wk: 14, s: 60, r: 'L', opp: '@DET', score: '30–44', aspect: 'Playoff hopes fading vs the Lions' },
  { wk: 15, s: 51, r: 'L', opp: 'MIN',  score: '26–34', aspect: "Offensive line protection issues impacting Dak's performance" },
  { wk: 16, s: 27, r: 'L', opp: 'LAC',  score: '17–34', aspect: 'Defensive collapse vs the Chargers', event: true, kind: 'low' },
  { wk: 17, s: 38, r: 'W', opp: '@WAS', score: '30–23', aspect: "Dak Prescott's performances in meaningless games" },
  { wk: 18, s: 30, r: 'L', opp: '@NYG', score: '17–34', aspect: "Jaxson Dart's performance and the Giants' upset win" },
];

function SentimentChart() {
  const [hover, setHover] = React.useState(null);
  const wrapRef = React.useRef(null);
  const [prog, setProg] = React.useState(0);
  React.useEffect(() => {
    if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) { setProg(1); return; }
    let raf = 0;
    const onScroll = () => {
      cancelAnimationFrame(raf);
      raf = requestAnimationFrame(() => {
        const anchor = document.getElementById('synFanHeadline') || wrapRef.current;
        if (!anchor) return;
        const rect = anchor.getBoundingClientRect();
        const vh = window.innerHeight || 800;
        const start = vh * 0.62, end = vh * 0.12;
        const p = (start - rect.top) / (start - end);
        setProg(Math.max(0, Math.min(1, p)));
      });
    };
    onScroll();
    window.addEventListener('scroll', onScroll, { passive: true });
    return () => { window.removeEventListener('scroll', onScroll); cancelAnimationFrame(raf); };
  }, []);
  const W = 900, H = 340, padL = 44, padR = 24, padT = 28, padB = 44;
  const iw = W - padL - padR, ih = H - padT - padB;
  const x = i => padL + (i / (SEASON.length - 1)) * iw;
  const y = v => padT + (1 - v / 100) * ih;
  const linePts = SEASON.map((d, i) => `${x(i)},${y(d.s)}`).join(' ');
  const areaPts = `${x(0)},${y(0)} ${linePts} ${x(SEASON.length-1)},${y(0)}`;
  const eventColor = { injury: 'var(--syn-red-700)', low: 'var(--syn-red)', trade: 'var(--syn-orange)', high: 'var(--syn-up)' };
  const clipW = padL + iw * prog + 2;
  const active = hover != null ? SEASON[hover] : null;
  return (
    <div ref={wrapRef} style={{ position: 'relative', width: '100%' }}>
      <svg viewBox={`0 0 ${W} ${H}`} style={{ width: '100%', height: 'auto', display: 'block', overflow: 'visible' }}
        onMouseLeave={() => setHover(null)}>
        <defs>
          <linearGradient id="synFill" x1="0" y1="0" x2="0" y2="1">
            <stop offset="0%" stopColor="#EB954A" stopOpacity="0.20" />
            <stop offset="100%" stopColor="#EB954A" stopOpacity="0.02" />
          </linearGradient>
          <clipPath id="synReveal">
            <rect x="0" y={-40} width={clipW} height={H + 80} />
          </clipPath>
        </defs>
        {[0, 25, 50, 75, 100].map(g => (
          <g key={g}>
            <line x1={padL} x2={W - padR} y1={y(g)} y2={y(g)} stroke="rgba(251,247,241,0.18)" strokeWidth="1" strokeDasharray={g === 50 ? '0' : '2 4'} opacity={g === 50 ? 0.9 : 0.6} />
            <text x={padL - 12} y={y(g) + 4} textAnchor="end" style={{ fontFamily: 'var(--syn-font-mono)', fontSize: 11, fill: 'var(--syn-navy-300)' }}>{g}</text>
          </g>
        ))}
        <g clipPath="url(#synReveal)">
          <polygon points={areaPts} fill="url(#synFill)" />
          <polyline points={linePts} fill="none" stroke="var(--syn-orange)" strokeWidth="2.5" strokeLinejoin="round" strokeLinecap="round" />
        </g>
        {active && (
          <line x1={x(hover)} x2={x(hover)} y1={padT} y2={padT + ih} stroke="var(--syn-navy-300)" strokeWidth="1" />
        )}
        {SEASON.map((d, i) => {
          const rp = SEASON.length > 1 ? i / (SEASON.length - 1) : 0;
          const vis = prog >= rp - 0.02 ? 1 : 0;
          return (
          <g key={d.wk} style={{ opacity: vis, transition: 'opacity 220ms linear' }}>
            <text x={x(i)} y={H - padB + 22} textAnchor="middle" style={{ fontFamily: 'var(--syn-font-mono)', fontSize: 10.5, fill: hover === i ? '#FBF7F1' : 'var(--syn-navy-300)', fontWeight: hover === i ? 600 : 400 }}>{d.wk}</text>
            {d.event && <circle cx={x(i)} cy={y(d.s)} r="9" fill="none" stroke={eventColor[d.kind]} strokeWidth="1.5" opacity="0.55" />}
            <circle cx={x(i)} cy={y(d.s)} r={hover === i ? 6 : 4} fill={d.event ? eventColor[d.kind] : '#FBF7F1'} stroke="var(--syn-navy)" strokeWidth="1.5" />
            <rect x={x(i) - (iw / (SEASON.length - 1)) / 2} y={padT} width={iw / (SEASON.length - 1)} height={ih} fill="transparent" onMouseEnter={() => vis && setHover(i)} />
          </g>
          );
        })}
        <text x={padL} y={H - 6} style={{ fontFamily: 'var(--syn-font-mono)', fontSize: 10, letterSpacing: '0.1em', fill: 'var(--syn-navy-300)', textTransform: 'uppercase' }}>NFL week →</text>
      </svg>
      {active && (
        <div style={{
          position: 'absolute', top: 0, left: `${(hover / (SEASON.length - 1)) * 100}%`,
          transform: `translateX(${hover > SEASON.length / 2 ? '-108%' : '8%'})`,
          background: '#FFFFFF', border: '1px solid var(--syn-border-strong)', borderRadius: 12,
          padding: '12px 14px', boxShadow: 'var(--syn-shadow-md, 0 6px 20px rgba(20,43,77,0.12))',
          pointerEvents: 'none', minWidth: 176, maxWidth: 240,
        }}>
          <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', marginBottom: 6 }}>
            <span style={{ fontFamily: 'var(--syn-font-mono)', fontSize: 11, letterSpacing: '0.08em', color: 'var(--syn-fg-subtle)' }}>WK {active.wk} · {active.opp}</span>
            {active.score && (
              <span style={{ fontFamily: 'var(--syn-font-mono)', fontSize: 11, fontWeight: 600, color: active.r === 'W' ? 'var(--syn-up)' : active.r === 'T' ? 'var(--syn-tie)' : 'var(--syn-red-700)' }}>{active.r} {active.score}</span>
            )}
          </div>
          <div style={{ display: 'flex', alignItems: 'baseline', gap: 6 }}>
            <span style={{ fontFamily: 'var(--syn-font-display)', fontWeight: 700, fontSize: 28, letterSpacing: '-0.03em', color: 'var(--syn-navy)', lineHeight: 1 }}>{active.s}</span>
            <span style={{ fontFamily: 'var(--syn-font-mono)', fontSize: 10, letterSpacing: '0.1em', textTransform: 'uppercase', color: 'var(--syn-fg-subtle)' }}>mood</span>
          </div>
          {active.aspect && (
            <div style={{ fontFamily: 'var(--syn-font-body)', fontSize: 12.5, lineHeight: 1.4, color: 'var(--syn-fg-muted)', marginTop: 8, paddingTop: 8, borderTop: '1px solid var(--syn-rule)' }}>{active.aspect}</div>
          )}
        </div>
      )}
    </div>
  );
}

// Two live leaderboards whose rows reorder on a timer.
function RankRow({ item, index, rowH, accent }) {
  const dir = item.dir;
  return (
    <div style={{
      position: 'absolute', left: 0, right: 0, top: index * rowH, height: rowH - 8,
      display: 'flex', alignItems: 'center', gap: 14, padding: '0 16px',
      background: dir ? 'rgba(251,247,241,0.07)' : 'rgba(251,247,241,0.03)',
      border: '1px solid ' + (dir ? (dir === 'up' ? 'var(--syn-up)' : 'var(--syn-red-700)') : 'rgba(251,247,241,0.13)'),
      borderRadius: 14,
      transition: 'top 620ms cubic-bezier(0.16,1,0.3,1), background 620ms ease, border-color 620ms ease',
    }}>
      <span style={{
        fontFamily: 'var(--syn-font-mono)', fontSize: 13, fontWeight: 600, width: 18,
        color: index === 0 ? accent : 'var(--syn-navy-300)', fontVariantNumeric: 'tabular-nums',
      }}>{index + 1}</span>
      <span style={{
        fontFamily: 'var(--syn-font-mono)', fontSize: 11, letterSpacing: '0.08em', fontWeight: 600,
        color: '#FBF7F1', background: 'rgba(251,247,241,0.09)', border: '1px solid rgba(251,247,241,0.16)',
        borderRadius: 999, padding: '4px 9px',
      }}>{item.code}</span>
      <span style={{
        fontFamily: 'var(--syn-font-body)', fontSize: 15, color: '#FBF7F1', flex: 1,
        whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis',
      }}>{item.name}</span>
      <span style={{
        fontFamily: 'var(--syn-font-mono)', fontSize: 11, width: 26, textAlign: 'right',
        color: dir === 'up' ? 'var(--syn-up)' : dir === 'down' ? 'var(--syn-red-700)' : 'rgba(251,247,241,0.28)',
        transition: 'color 400ms ease',
      }}>{dir === 'up' ? '▲1' : dir === 'down' ? '▼1' : '—'}</span>
      <span style={{
        fontFamily: 'var(--syn-font-display)', fontSize: 19, fontWeight: 600, letterSpacing: '-0.02em',
        color: '#FBF7F1', fontVariantNumeric: 'tabular-nums', width: 54, textAlign: 'right',
      }}>{item.score.toFixed(1)}</span>
    </div>
  );
}

function RankBoard({ eyebrow, note, seed, accent, delay = 0 }) {
  const rowH = 56;
  const { isPhone } = window.useIsMobile();
  const [items, setItems] = React.useState(seed);
  const seedMean = React.useMemo(() => seed.reduce((s, it) => s + it.score, 0) / seed.length, [seed]);
  React.useEffect(() => {
    if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) return;
    let t;
    const tick = () => {
      setItems(prev => {
        const i = Math.floor(Math.random() * (prev.length - 1));
        const gap = prev[i].score - prev[i + 1].score;
        const swing = (gap + 0.1 + Math.random() * 0.8) / 2;
        const bumped = prev.map((it, k) => k === i + 1
          ? { ...it, score: it.score + swing }
          : k === i ? { ...it, score: it.score - swing } : it);
        const mean = bumped.reduce((s, it) => s + it.score, 0) / bumped.length;
        const drift = seedMean - mean;
        const norm = bumped.map(it => ({ ...it, score: Math.min(99.9, Math.max(60, it.score + drift)) }));
        const sorted = [...norm].sort((a, b) => b.score - a.score);
        return sorted.map(it => {
          const was = prev.findIndex(p => p.id === it.id);
          const now = sorted.findIndex(p => p.id === it.id);
          return { ...it, dir: now < was ? 'up' : now > was ? 'down' : null };
        });
      });
      t = setTimeout(tick, 1900 + Math.random() * 1200);
    };
    t = setTimeout(tick, 1200 + delay);
    return () => clearTimeout(t);
  }, []);
  const byId = items.map((it, i) => ({ it, i })).sort((a, b) => a.it.id < b.it.id ? -1 : 1);
  return (
    <div style={{
      background: 'rgba(251,247,241,0.04)', border: '1px solid rgba(251,247,241,0.13)',
      borderRadius: 24, padding: isPhone ? '24px 16px 20px' : '28px 24px 24px',
      flex: 1, minWidth: isPhone ? 0 : 340, width: isPhone ? '100%' : 'auto',
      boxSizing: 'border-box',
    }}>
      <div style={{
        fontFamily: 'var(--syn-font-mono)', fontSize: isPhone ? 12 : 15,
        letterSpacing: isPhone ? '0.08em' : '0.16em',
        textTransform: 'uppercase', color: accent, fontWeight: 800, marginBottom: 8,
      }}>{eyebrow}</div>
      <p style={{
        fontFamily: 'var(--syn-font-body)', fontSize: 14, lineHeight: 1.5,
        color: 'var(--syn-navy-300)', margin: '0 0 22px',
      }}>{note}</p>
      <div style={{ position: 'relative', height: rowH * items.length - 8 }}>
        {byId.map(({ it, i }) => <RankRow key={it.id} item={it} index={i} rowH={rowH} accent={accent} />)}
      </div>
    </div>
  );
}

const SYN_TEAM_SEED = [
  { id: 't1', code: 'DET', name: 'Lions', score: 92.4 },
  { id: 't2', code: 'LAR', name: 'Rams', score: 90.8 },
  { id: 't3', code: 'PHI', name: 'Eagles', score: 88.1 },
  { id: 't4', code: 'BUF', name: 'Bills', score: 86.5 },
  { id: 't5', code: 'KC', name: 'Chiefs', score: 84.9 },
];
const SYN_COACH_SEED = [
  { id: 'c1', code: 'LAR', name: 'Sean McVay', score: 94.2 },
  { id: 'c2', code: 'SF', name: 'Kyle Shanahan', score: 91.6 },
  { id: 'c3', code: 'SEA', name: 'Mike Macdonald', score: 89.3 },
  { id: 'c4', code: 'KC', name: 'Andy Reid', score: 85.7 },
  { id: 'c5', code: 'DEN', name: 'Sean Payton', score: 82.4 },
];

function ProductPage({ onNav = () => {} }) {
  const [ctaEmail, setCtaEmail] = React.useState('');
  const [heroEmail, setHeroEmail] = React.useState('');
  const { isPhone } = window.useIsMobile();
  // phone-aware section padding: keep the desktop vertical rhythm but shrink the
  // 48px sides to 20px so nothing overflows the viewport.
  const sx = (v) => isPhone ? v.replace(/ 48px/g, ' 20px') : v;
  return (
    <main>
      <style>{`
        .syn-ul{background-image:linear-gradient(var(--syn-orange),var(--syn-orange));background-repeat:no-repeat;background-position:0 88%;background-size:0% 3px;padding-bottom:2px}
        .syn-ul-1{animation:synUnderline 620ms cubic-bezier(0.16,1,0.3,1) 900ms both}
        .syn-ul-2{animation:synUnderline 620ms cubic-bezier(0.16,1,0.3,1) 2100ms both}
        @keyframes synUnderline{from{background-size:0% 3px}to{background-size:100% 3px}}
        @media (prefers-reduced-motion:reduce){.syn-ul{background-size:100% 3px}.syn-ul-1,.syn-ul-2{animation:none}}
      `}</style>
      {/* Hero */}
      <section style={{ padding: sx('88px 48px 72px') }}>
        <div style={{ maxWidth: 1120, margin: '0 auto' }}>
          <div style={{
            fontFamily: 'var(--syn-font-mono)', fontSize: isPhone ? 14 : 21, letterSpacing: '0.16em',
            textTransform: 'uppercase', color: 'var(--syn-navy-300)', fontWeight: 500, marginBottom: 22,
          }}>Our product · A daily sports newsletter</div>
          <h1 style={{
            fontFamily: 'var(--syn-font-display)', fontSize: isPhone ? 36 : 62, fontWeight: 600,
            letterSpacing: '-0.035em', lineHeight: 1.04, color: '#FBF7F1',
            margin: '0 0 26px', maxWidth: 940, textWrap: 'balance',
          }}><span style={{ fontWeight: 200, color: 'var(--syn-orange)' }}>We use AI to do what it does best: </span><span className="syn-ul syn-ul-1">Analyze lots of data</span><span style={{ fontWeight: 600 }}> and deliver the insights that </span><span className="syn-ul syn-ul-2">make you smarter</span></h1>
          <p style={{
            fontFamily: 'var(--syn-font-display)', fontSize: isPhone ? 17 : 21, lineHeight: 1.5,
            color: 'var(--syn-navy-300)', maxWidth: 680, margin: '0 0 34px', fontWeight: 400,
          }}>Synth reads everything about your team — what analysts say, what the data says, and what others in the community think — and delivers only what makes you a more informed fan, bettor, and consumer of the game.</p>
          <form onSubmit={e => { e.preventDefault(); onNav('onboarding', heroEmail); }} style={{ display: 'flex', flexDirection: isPhone ? 'column' : 'row', gap: 8, maxWidth: 460 }}>
            <input type="email" value={heroEmail} onChange={e => setHeroEmail(e.target.value)} placeholder="Enter your email" style={{
              flex: 1, padding: '15px 16px', fontFamily: 'var(--syn-font-body)', fontSize: 15,
              border: '1px solid rgba(251,247,241,0.2)', borderRadius: 12, background: '#FFFFFF',
              color: '#000000', outline: 'none',
            }} />
            <button style={{
              background: 'var(--syn-orange)', color: '#FFFFFF', border: 0, borderRadius: 12,
              padding: '15px 26px', fontFamily: 'var(--syn-font-body)', fontSize: 15, fontWeight: 500,
              cursor: 'pointer', whiteSpace: 'nowrap',
            }}>Save my spot</button>
          </form>
        </div>
      </section>

      {/* Signals, not just summaries */}
      <section style={{ padding: sx('128px 48px'), background: 'transparent', borderTop: '1px solid rgba(251,247,241,0.13)', borderBottom: '1px solid rgba(251,247,241,0.13)' }}>
        <div style={{ maxWidth: 1120, margin: '0 auto', display: 'flex', justifyContent: 'center' }}>
          <SignalsCard />
        </div>
      </section>

      {/* Fan Sentiment */}
      <section style={{ padding: sx('96px 48px 112px') }}>
        <div style={{ maxWidth: 1120, margin: '0 auto' }}>
          <div style={{
            fontFamily: 'var(--syn-font-mono)', fontSize: 12, letterSpacing: '0.16em',
            textTransform: 'uppercase', color: 'var(--syn-navy-300)', fontWeight: 500, marginBottom: 16,
          }}>Fan sentiment · measuring how it feels to be a fan</div>
          <h2 style={{
            fontFamily: 'var(--syn-font-display)', fontSize: isPhone ? 30 : 44, fontWeight: 600,
            letterSpacing: '-0.03em', lineHeight: 1.08, color: '#FBF7F1',
            margin: '0 0 20px', maxWidth: 820, textWrap: 'balance',
          }} id="synFanHeadline">Every fanbase has a mood. We're the first to put a number on it — every single day.</h2>
          <p style={{
            fontFamily: 'var(--syn-font-body)', fontSize: 17, lineHeight: 1.65,
            color: 'var(--syn-navy-300)', margin: '0 0 12px', maxWidth: 720,
          }}>Synth listens where fans actually talk. We filter out the noise to find what a fanbase really cares about, then score the mood from 0 to 100. Trades, injuries, wins and losses show up as data driven by fan voice.</p>
          <div style={{
            background: 'rgba(251,247,241,0.04)', border: '1px solid rgba(251,247,241,0.13)', borderRadius: 24,
            padding: isPhone ? '24px 18px 20px' : '36px 40px 24px', boxShadow: 'none', marginTop: 44,
          }}>
            <p style={{
              fontFamily: 'var(--syn-font-mono)', fontSize: 12, letterSpacing: '0.04em',
              color: 'var(--syn-navy-300)', margin: '0 0 24px',
            }}>DAL COWBOYS · 2025 season (Sep 2025 – Jan 2026) — hover any week to expand</p>
            <SentimentChart />
            <div style={{ display: 'flex', gap: 24, flexWrap: 'wrap', marginTop: 20, paddingTop: 20, borderTop: '1px solid rgba(251,247,241,0.13)' }}>
              {[['var(--syn-red)', 'Season low'], ['var(--syn-orange)', 'Trade / news'], ['var(--syn-up)', 'Season high']].map(([col, lab]) => (
                <div key={lab} style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
                  <span style={{ width: 10, height: 10, borderRadius: 999, border: `1.5px solid ${col}` }} />
                  <span style={{ fontFamily: 'var(--syn-font-mono)', fontSize: 11, letterSpacing: '0.06em', textTransform: 'uppercase', color: 'var(--syn-navy-300)' }}>{lab}</span>
                </div>
              ))}
            </div>
          </div>
        </div>
      </section>
      {/* Rankings */}
      <section style={{ padding: sx('96px 48px 112px'), borderTop: '1px solid rgba(251,247,241,0.13)' }}>
        <div style={{ maxWidth: 1120, margin: '0 auto' }}>
          <div style={{
            fontFamily: 'var(--syn-font-mono)', fontSize: 12, letterSpacing: '0.16em',
            textTransform: 'uppercase', color: 'var(--syn-navy-300)', fontWeight: 500, marginBottom: 16,
          }}>Rankings · A weekly assessment of where your team and coach stand</div>
          <h2 style={{
            fontFamily: 'var(--syn-font-display)', fontSize: isPhone ? 30 : 44, fontWeight: 600,
            letterSpacing: '-0.03em', lineHeight: 1.08, color: '#FBF7F1',
            margin: '0 0 20px', maxWidth: 860, textWrap: 'balance',
          }}>Teams ranked by what they did. Coaches ranked by what they chose.</h2>
          <p style={{
            fontFamily: 'var(--syn-font-body)', fontSize: 17, lineHeight: 1.65,
            color: 'var(--syn-navy-300)', margin: 0, maxWidth: 720,
          }}>Each week our model ranks teams based on their performance, and coaches based on their key decisions.</p>
          <div style={{ display: 'flex', flexDirection: isPhone ? 'column' : 'row', gap: 24, flexWrap: 'wrap', marginTop: 44, maxWidth: isPhone ? 460 : 'none' }}>
            <RankBoard eyebrow="Team Power Rankings · Tuesdays" note="Margin, opponent quality, and drive efficiency. No narrative inputs." seed={SYN_TEAM_SEED} accent="var(--syn-orange)" />
            <RankBoard eyebrow="Coach Decision Rankings · Wednesdays" note="Every in-game decision graded against its win-probability alternative." seed={SYN_COACH_SEED} accent="var(--syn-red)" delay={700} />
          </div>
        </div>
      </section>
      {/* Closing CTA */}
      <section style={{ padding: sx('96px 48px 112px'), borderTop: '1px solid rgba(251,247,241,0.13)', textAlign: 'center' }}>
        <div style={{ maxWidth: 660, margin: '0 auto' }}>
          <div style={{
            fontFamily: 'var(--syn-font-mono)', fontSize: 12, letterSpacing: '0.16em',
            textTransform: 'uppercase', color: 'var(--syn-navy-300)', fontWeight: 500, marginBottom: 18,
          }}>Free · every morning</div>
          <h2 style={{
            fontFamily: 'var(--syn-font-display)', fontSize: isPhone ? 34 : 55, fontWeight: 600,
            letterSpacing: '-0.035em', lineHeight: 1.06, color: '#FBF7F1', margin: '0 0 18px', textWrap: 'balance',
          }}>Wake up sharper than your group chat.</h2>
          <p style={{
            fontFamily: 'var(--syn-font-display)', fontSize: 19, lineHeight: 1.45,
            color: 'var(--syn-navy-300)', margin: '0 0 36px', fontWeight: 400,
          }}>Coverage launching with the 2026 NFL season.</p>
          <form onSubmit={e => { e.preventDefault(); onNav('onboarding', ctaEmail); }} style={{ display: 'flex', flexDirection: isPhone ? 'column' : 'row', gap: 8, maxWidth: 460, margin: '0 auto' }}>
            <input type="email" value={ctaEmail} onChange={e => setCtaEmail(e.target.value)} placeholder="Enter your email" style={{
              flex: 1, padding: '14px 16px', fontFamily: 'var(--syn-font-body)', fontSize: 15,
              border: '1px solid rgba(251,247,241,0.2)', borderRadius: 12, background: '#FFFFFF',
              color: '#000000', outline: 'none',
            }} />
            <button style={{
              background: 'var(--syn-orange)', color: '#FFFFFF', border: 0, borderRadius: 12,
              padding: '14px 24px', fontFamily: 'var(--syn-font-body)', fontSize: 15, fontWeight: 500,
              cursor: 'pointer', whiteSpace: 'nowrap',
            }}>Save my spot</button>
          </form>
        </div>
      </section>
    </main>
  );
}

Object.assign(window, { ProductPage, Reveal, SentimentRing });
