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

function useReducedMotion() {
  const [reduced, setReduced] = useState(false);

  useEffect(() => {
    const media = window.matchMedia('(prefers-reduced-motion: reduce)');
    setReduced(media.matches);
    const onChange = (event) => setReduced(event.matches);
    media.addEventListener('change', onChange);
    return () => media.removeEventListener('change', onChange);
  }, []);

  return reduced;
}

const AnimatePresence = ({ children }) => children;

const motion = {
  div: ({ children, animate, initial, exit, transition, ...props }) => <div {...props}>{children}</div>
};

const TURNSTILE_SITE_KEY = '0x4AAAAAACrXXzba84gfzB0x';

function parseTurnstileToken() {
  const responseField = document.querySelector('[name="cf-turnstile-response"]');
  return responseField ? String(responseField.value || '').trim() : '';
}

const tiers = [
  { invites: '3 friends join', reward: 'Your season unlocks' },
  { invites: '6 friends join', reward: 'Guaranteed early beta season' }
];

const faqs = [
  ['Do we need to be online together?', 'No. Moves happen throughout the week. Sunday episodes reveal what happened.'],
  ['How many people are in a season?', '6-10 players works best.'],
  ['When does the app launch?', 'Private beta seasons are forming now.']
];

const steps = [
  { icon: '🚀', title: 'Start a season', body: 'Create a private season in seconds.' },
  { icon: '👥', title: 'Recruit your cast', body: 'Invite 6-10 friends from your group chat.' },
  { icon: '🕵️', title: 'Play the game', body: 'Form alliances, play immunity, and drop confessionals all week.' },
  { icon: '📺', title: 'Watch the episode', body: 'Every Sunday the app reveals the votes and betrayals.' }
];

const pillars = [
  {
    title: 'Strategy game with your friends',
    body: 'Not trivia or polls. Real alliances, betrayals, and votes.'
  },
  {
    title: 'Confessionals expose everything',
    body: 'Drop private takes during the week. Sunday episodes reveal who said what.'
  },
  {
    title: 'A real recap episode',
    body: 'Every Sunday the app reveals the alliances, votes, and blindsides.'
  }
];

const socialSignals = [
  '🔥 First 100 seasons forming',
  '🎭 Private seasons for friend groups',
  '📱 iPhone + Android beta launching soon'
];

function useCountUp(target, duration = 1400) {
  const [value, setValue] = useState(0);

  useEffect(() => {
    let frame;
    const started = performance.now();

    const tick = (now) => {
      const progress = Math.min((now - started) / duration, 1);
      const eased = 1 - Math.pow(1 - progress, 3);
      setValue(Math.round(target * eased));
      if (progress < 1) frame = requestAnimationFrame(tick);
    };

    frame = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(frame);
  }, [target, duration]);

  return value;
}

function Section({ id, className = '', children }) {
  return (
    <section id={id} className={`section-wrap reveal py-12 md:py-16 lg:py-20 scroll-mt-24 ${className}`}>
      {children}
    </section>
  );
}

function IconShare() {
  return (
    <svg viewBox="0 0 24 24" fill="none" className="h-4 w-4" stroke="currentColor" strokeWidth="1.8">
      <path d="M7 12v7a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1v-7" />
      <path d="M12 16V4" />
      <path d="m8.5 7 3.5-3 3.5 3" />
    </svg>
  );
}

function IconLock() {
  return (
    <svg viewBox="0 0 24 24" fill="none" className="h-4 w-4" stroke="currentColor" strokeWidth="1.8">
      <rect x="5" y="11" width="14" height="9" rx="2" />
      <path d="M8 11V8a4 4 0 1 1 8 0v3" />
    </svg>
  );
}

function StatusBar() {
  return (
    <div className="flex items-center justify-between text-[10px] text-slate-300">
      <span className="font-semibold tracking-wide">9:41</span>
      <div className="flex items-center gap-1">
        <span>●●●</span>
        <span>◠◠</span>
        <span className="rounded-[4px] border border-white/30 px-1 leading-none">▮</span>
      </div>
    </div>
  );
}

function ScreenHeader({ title, subtitle, left, right, center = false }) {
  return (
    <div className="flex items-center justify-between">
      <div className="min-w-0">{left}</div>
      <div className={`px-2 ${center ? 'text-center' : 'text-left'}`}>
        <p className="text-sm font-semibold text-slate-100">{title}</p>
        {subtitle ? <p className="text-[10px] uppercase tracking-wide text-slate-400">{subtitle}</p> : null}
      </div>
      <div className="min-w-0 text-right">{right}</div>
    </div>
  );
}

function GlassCard({ className = '', children }) {
  return <div className={`rounded-2xl border border-white/10 bg-white/5 backdrop-blur-xl ${className}`}>{children}</div>;
}

function Avatar({ initials, variant = 'from-fuchsia-500 to-violet-500' }) {
  return (
    <div className={`grid h-7 w-7 place-content-center rounded-full bg-gradient-to-br ${variant} text-[10px] font-semibold text-white`}>
      {initials}
    </div>
  );
}

function SegmentedControl({ items, active }) {
  return (
    <div className="inline-flex rounded-full border border-white/10 bg-white/5 p-1">
      {items.map((item) => (
        <span key={item} className={`rounded-full px-2 py-1 text-[10px] font-medium ${item === active ? 'bg-white/20 text-white' : 'text-slate-400'}`}>
          {item}
        </span>
      ))}
    </div>
  );
}

function ScreenEpisodeReveal() {
  return (
    <div className="screen-ui">
      <StatusBar />
      <ScreenHeader
        title="Sunday Episode"
        left={<span className="rounded-full border border-fuchsia-300/35 bg-fuchsia-400/10 px-2 py-1 text-[10px] font-medium text-fuchsia-200">Episode 03</span>}
        right={<button className="grid h-7 w-7 place-content-center rounded-full border border-white/15 bg-white/5 text-slate-200"><IconShare /></button>}
        center
      />

      <GlassCard className="p-3">
        <p className="text-xl font-semibold text-white">Blindside confirmed.</p>
        <p className="mt-1 text-xs text-slate-300">Two alliances exposed. One last-minute immunity flipped the vote.</p>
      </GlassCard>

      <GlassCard className="p-3">
        <p className="text-[10px] uppercase tracking-wide text-slate-400">Final vote</p>
        <div className="mt-2 space-y-2">
          {[
            ['AR', 'Ari', '+92', 'from-violet-500 to-fuchsia-500'],
            ['MY', 'Maya', '+87', 'from-cyan-500 to-indigo-500'],
            ['NH', 'Noah', '+84', 'from-blue-500 to-violet-500']
          ].map(([initials, name, score, variant]) => (
            <div key={name} className="flex items-center justify-between rounded-xl border border-white/10 bg-white/5 px-2.5 py-2">
              <div className="flex items-center gap-2">
                <Avatar initials={initials} variant={variant} />
                <span className="text-sm text-slate-100">{name}</span>
              </div>
              <span className="text-sm font-semibold text-cyan-200">{score}</span>
            </div>
          ))}
        </div>
      </GlassCard>

      <GlassCard className="p-3">
        <p className="text-[10px] uppercase tracking-wide text-slate-400">Recap timeline</p>
        <div className="mt-2 flex flex-wrap gap-2">
          {['Immunity', 'Flip', 'Blindside'].map((chip) => (
            <span key={chip} className="rounded-full border border-white/10 bg-white/5 px-2 py-1 text-[10px] text-slate-200">{chip}</span>
          ))}
        </div>
      </GlassCard>

      <button className="mt-auto h-11 rounded-xl bg-gradient-to-r from-violet-500 to-fuchsia-500 text-sm font-semibold text-white shadow-[0_10px_28px_rgba(168,85,247,0.35)]">Watch recap</button>
      <p className="text-center text-[10px] tracking-wide text-slate-400">3 confessionals revealed</p>
    </div>
  );
}

function ScreenConfessional() {
  return (
    <div className="screen-ui">
      <StatusBar />
      <ScreenHeader
        title="Confessional"
        subtitle="Posted anonymously"
        right={<button className="grid h-7 w-7 place-content-center rounded-full border border-white/15 bg-white/5 text-slate-200"><IconLock /></button>}
      />

      <GlassCard className="p-3.5">
        <p className="text-[10px] uppercase tracking-wide text-slate-400">Private note</p>
        <div className="mt-2 rounded-2xl border border-white/15 bg-white/10 p-3 text-sm text-slate-100">
          “I trusted Maya but she flipped right before the vote.”
          <span className="ml-1 inline-block h-3 w-[2px] translate-y-[2px] animate-pulse bg-cyan-300" />
        </div>
      </GlassCard>

      <GlassCard className="p-3">
        <div className="flex items-center justify-between text-xs text-slate-300">
          <span>2 hours before the vote</span>
          <span>Anonymous</span>
        </div>
      </GlassCard>

      <GlassCard className="p-3">
        <p className="text-[10px] uppercase tracking-wide text-slate-400">Mood</p>
        <div className="mt-2 flex gap-2">
          {['😏', '🤐', '🔥'].map((emoji, i) => (
            <button key={emoji} className={`grid h-8 w-8 place-content-center rounded-lg border ${i === 1 ? 'border-fuchsia-300/45 bg-fuchsia-400/20' : 'border-white/10 bg-white/5'}`}>
              {emoji}
            </button>
          ))}
        </div>
      </GlassCard>

      <button className="mt-auto h-11 rounded-xl border border-white/15 bg-white/10 text-sm font-semibold text-slate-100">Add confessional</button>
    </div>
  );
}

function ScreenVoteScoreboard() {
  return (
    <div className="screen-ui">
      <StatusBar />
      <ScreenHeader title="Vote" right={<SegmentedControl items={['Scoreboard', 'Alliances']} active="Scoreboard" />} />

      <GlassCard className="p-3">
        <div className="mb-2 flex items-center justify-between">
          <p className="text-xs font-medium text-slate-100">Final vote swing</p>
          <span className="text-[10px] uppercase tracking-wide text-slate-400">This week</span>
        </div>
        <div className="space-y-2">
          <div className="h-1.5 w-4/5 rounded-full bg-gradient-to-r from-fuchsia-500/80 to-violet-500/80" />
          <div className="h-1.5 w-3/5 rounded-full bg-cyan-400/70" />
          <div className="h-1.5 w-11/12 rounded-full bg-indigo-400/70" />
        </div>
      </GlassCard>

      <GlassCard className="p-3">
        <p className="text-[10px] uppercase tracking-wide text-slate-400">Scoreboard</p>
        <div className="mt-2 space-y-2">
          {[
            ['1', 'Ari', '92', '+8'],
            ['2', 'Maya', '87', '+2'],
            ['3', 'Noah', '84', '-3']
          ].map(([rank, name, points, delta]) => (
            <div key={name} className="flex items-center justify-between rounded-xl border border-white/10 bg-white/5 px-2.5 py-2 text-xs">
              <div className="flex items-center gap-2">
                <span className="grid h-5 w-5 place-content-center rounded-full border border-white/15 bg-white/5 text-[10px]">{rank}</span>
                <span className="text-slate-100">{name}</span>
              </div>
              <div className="flex items-center gap-2">
                <span className="font-semibold text-cyan-200">{points}</span>
                <span className={delta.startsWith('+') ? 'text-emerald-300' : 'text-rose-300'}>{delta}</span>
              </div>
            </div>
          ))}
        </div>
      </GlassCard>

      <GlassCard className="p-3">
        <p className="text-xs font-medium text-slate-100">Alliance map</p>
        <div className="mt-2 space-y-2 text-[11px] text-slate-200">
          <div className="rounded-lg border border-white/10 bg-white/5 px-2 py-1.5">Ari • Maya • Sam</div>
          <div className="rounded-lg border border-white/10 bg-white/5 px-2 py-1.5">Noah • Jess • Cal</div>
        </div>
      </GlassCard>

      <button className="mt-auto h-11 rounded-xl bg-gradient-to-r from-violet-500 to-fuchsia-500 text-sm font-semibold text-white shadow-[0_10px_28px_rgba(168,85,247,0.35)]">Lock my vote</button>
      <p className="text-center text-[10px] tracking-wide text-amber-300/90">Locks in 1h 12m</p>
    </div>
  );
}

const heroSlides = [
  { key: 'episode', src: '/hero-screens/recap_hero.png', alt: 'Episode reveal iPhone screen', fallback: ScreenEpisodeReveal },
  { key: 'confessional', src: '/hero-screens/confessional_hero.png', alt: 'Confessional iPhone screen', fallback: ScreenConfessional },
  { key: 'vote', src: '/hero-screens/friends_hero.png', alt: 'Vote and scoreboard iPhone screen', fallback: ScreenVoteScoreboard }
];

const chatScript = [
  'David HOW could you?',
  'YOU SNAKE',
  'I trusted you 😭',
  'nahhhh that blindside was CRAZY',
  'Bro the episode exposed EVERYTHING',
  'I’m never trusting Maya again',
  'That immunity play was villain behavior',
  'who voted for me???',
  'NO WAY THAT VOTE FLIPPED',
  'LMAO Sam’s confessional',
  'Is anyone actually loyal here?',
  'I need receipts right now'
];

const screenToChatMessage = {
  confessional: 'LMAO Sam’s confessional',
  episode: 'NO WAY THAT VOTE FLIPPED',
  vote: 'who voted for me???'
};

function HeroPhoneSlide({ slide }) {
  const [failed, setFailed] = useState(false);
  const Fallback = slide.fallback;

  if (failed) {
    return <Fallback />;
  }

  return (
    <img
      src={slide.src}
      alt={slide.alt}
      loading="eager"
      decoding="async"
      onError={() => setFailed(true)}
      className="h-full w-full object-cover"
    />
  );
}

function IphoneMockup({ children, className = '' }) {
  return (
    <article className={`iphone-shell ${className}`}>
      <div className="iphone-bezel">
        <div className="iphone-notch" />
        <div className="iphone-screen">{children}</div>
      </div>
    </article>
  );
}

function LegacyImessageLiveFeed({ activeScreen, className = "" }) {
  const reduceMotion = useReducedMotion();
  const scripted = [
    'David how could you?',
    'YOU SNAKE!',
    'I trusted you 😭',
    'LMAO Sam your confessional',
    'who voted for me???',
    'Abby I might have called you out in the confessional...',
    'Watch party this weekend for the reveal??',
    'NO WAY THAT VOTE FLIPPED',
    'nahhhh that blindside was crazy',
    'Emma you’re a villain'
  ];

  const [messages, setMessages] = useState(() => {
    if (reduceMotion) {
      return [
        { id: 1, text: 'David how could you?', tone: 'out' },
        { id: 2, text: 'YOU SNAKE!', tone: 'out' },
        { id: 3, text: 'I trusted you 😭', tone: 'in' },
        { id: 4, text: 'who voted for me???', tone: 'out' }
      ];
    }

    return [
      { id: 1, text: 'NO WAY THAT VOTE FLIPPED', tone: 'out' },
      { id: 2, text: 'I trusted you 😭', tone: 'in' }
    ];
  });
  const [typing, setTyping] = useState(false);
  const [cursor, setCursor] = useState(0);
  useEffect(() => {
    if (reduceMotion) return;
    const nextByScreen = {
      confessional: 'LMAO Sam your confessional',
      episode: 'NO WAY THAT VOTE FLIPPED',
      vote: 'who voted for me???'
    };

    setTyping(true);
    const timer = setTimeout(() => {
      const text = nextByScreen[heroSlides[activeScreen]?.key] ?? scripted[cursor % scripted.length];
      setMessages((current) => {
        if (current.some((message) => message.text === text)) return current;
        return [...current, { id: Date.now(), text, tone: 'out' }].slice(-6);
      });
      setTyping(false);
    }, 700);

    return () => clearTimeout(timer);
  }, [activeScreen, reduceMotion]);

  useEffect(() => {
    if (reduceMotion) return;
    const timer = setInterval(() => {
      setTyping(true);
      setTimeout(() => {
        const text = scripted[cursor % scripted.length];
        const tone = cursor % 3 === 0 ? 'in' : 'out';
        setMessages((current) => [...current, { id: Date.now() + Math.random(), text, tone }].slice(-6));
        setTyping(false);
        setCursor((value) => value + 1);
      }, 700);
    }, 2800);

    return () => clearInterval(timer);
  }, [cursor, reduceMotion]);

  return (
    <div className={`imsg w-full ${className}`}>
      <div className="imsg__header">
        <div className="imsg__headerTop">
          <button aria-label="Back" className="text-[#007AFF]">
            <svg viewBox="0 0 20 20" className="h-5 w-5" fill="none" stroke="currentColor" strokeWidth="2.2"><path d="M12.5 3.8 6.5 10l6 6.2" /></svg>
          </button>

          <div className="imsg__headerCenter">
            <div className="imsg__avatars">
              <div className="imsg__avatar" />
              <div className="imsg__avatar" />
              <div className="imsg__avatar" />
              <div className="imsg__avatar" />
            </div>
            <div className="imsg__people">8 People</div>
            <div className="imsg__sub">Cast Chat</div>
          </div>

          <button aria-label="Video" className="text-[#007AFF]">
            <svg viewBox="0 0 24 24" className="h-5 w-5" fill="none" stroke="currentColor" strokeWidth="2"><path d="M3.5 7.5a2 2 0 0 1 2-2h8a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2h-8a2 2 0 0 1-2-2z"/><path d="m15.5 10.5 5-3v9l-5-3z"/></svg>
          </button>
        </div>
      </div>

      <div className="imsg__divider">iMessage • Today 9:41 AM</div>

      <div className="imsg__body">
        <div className="imsg__scroll">
          <AnimatePresence initial={false}>
            {messages.map((message) => (
              <motion.div
                key={message.id}
                initial={reduceMotion ? false : { opacity: 0, y: 10, scale: 0.98 }}
                animate={reduceMotion ? { opacity: 1 } : { opacity: 1, y: 0, scale: 1 }}
                exit={reduceMotion ? undefined : { opacity: 0, y: -10 }}
                className={`imsg__row ${message.tone === 'out' ? 'imsg__row--out' : 'imsg__row--in'}`}
              >
                <div className={`imsg__bubble ${message.tone === 'out' ? 'imsg__bubble--out' : 'imsg__bubble--in'}`}>
                  {message.text}
                </div>
              </motion.div>
            ))}
          </AnimatePresence>

          {!reduceMotion && typing ? (
            <div className="imsg__row imsg__row--in">
              <div className="imsg__typing">
                <span className="imsg__dot" />
                <span className="imsg__dot" />
                <span className="imsg__dot" />
              </div>
            </div>
          ) : null}
        </div>
      </div>

      <div className="imsg__inputBar">
        <div className="imsg__inputInner">
          <button aria-label="Camera" className="text-[#007AFF]"><svg viewBox="0 0 24 24" className="h-5 w-5" fill="none" stroke="currentColor" strokeWidth="2"><path d="M4 8a2 2 0 0 1 2-2h2l1.2-1.5h5.6L16 6h2a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2z"/><circle cx="12" cy="12.5" r="3.4"/></svg></button>
          <div className="imsg__inputPill">iMessage</div>
          <button aria-label="App Store" className="text-[#007AFF]"><svg viewBox="0 0 24 24" className="h-5 w-5" fill="none" stroke="currentColor" strokeWidth="2"><circle cx="12" cy="12" r="9"/><path d="M9 8.8h6M8.8 15.2h6.4M10.2 8.8l3.8 6.4M13.8 8.8 10 15.2"/></svg></button>
          <button aria-label="Audio" className="text-[#007AFF]"><svg viewBox="0 0 24 24" className="h-5 w-5" fill="none" stroke="currentColor" strokeWidth="2"><rect x="9" y="4" width="6" height="10" rx="3"/><path d="M6 11.5a6 6 0 1 0 12 0M12 17.5v3"/></svg></button>
        </div>
      </div>
    </div>
  );
}

function FloatingChatStack({ activeScreen, className = "" }) {
  const reduceMotion = useReducedMotion();
  const scripted = [
    'David how could you?',
    'YOU SNAKE!',
    'I trusted you ðŸ˜­',
    'LMAO Sam your confessional',
    'who voted for me???',
    'Abby I might have called you out in the confessional...',
    'Watch party this weekend for the reveal??',
    'NO WAY THAT VOTE FLIPPED',
    'nahhhh that blindside was crazy',
    'Emma youâ€™re a villain'
  ];

  const [messages, setMessages] = useState(() => {
    if (reduceMotion) {
      return [
        { id: 1, text: 'YOU SNAKE!', tone: 'in', speaker: 0 },
        { id: 2, text: 'I trusted you ðŸ˜­', tone: 'out', speaker: 1 },
        { id: 3, text: 'LMAO Sam your confessional', tone: 'in', speaker: 2 },
        { id: 4, text: 'who voted for me???', tone: 'out', speaker: 3 }
      ];
    }

    return [
      { id: 1, text: 'YOU SNAKE!', tone: 'in', speaker: 0 },
      { id: 2, text: 'I trusted you ðŸ˜­', tone: 'out', speaker: 1 },
      { id: 3, text: 'LMAO Sam your confessional', tone: 'in', speaker: 2 }
    ];
  });
  const [cursor, setCursor] = useState(0);

  function normalizeText(text) {
    if (text.startsWith('I trusted you')) return 'I trusted you lol';
    if (text.startsWith('Emma ')) return 'Emma you are a villain';
    return text;
  }

  function getNextSpeaker(seed, previousSpeaker) {
    const candidate = seed % cast.length;
    if (previousSpeaker == null || candidate !== previousSpeaker) return candidate;
    return (candidate + 1) % cast.length;
  }

  function buildMessage(text, tone, seed, previousSpeaker) {
    return {
      id: Date.now() + Math.random(),
      text: normalizeText(text),
      tone,
      speaker: getNextSpeaker(seed, previousSpeaker)
    };
  }

  useEffect(() => {
    setMessages((current) => current.map((message) => ({ ...message, text: normalizeText(message.text) })));
  }, []);

  useEffect(() => {
    if (reduceMotion) return;

    const nextByScreen = {
      confessional: 'LMAO Sam your confessional',
      episode: 'NO WAY THAT VOTE FLIPPED',
      vote: 'who voted for me???'
    };

    const timer = setTimeout(() => {
      const text = nextByScreen[heroSlides[activeScreen]?.key] ?? normalizeText(scripted[cursor % scripted.length]);
      setMessages((current) => {
        if (current.some((message) => message.text === text)) return current;
        return [...current, buildMessage(text, 'out', current.length + cursor, current[current.length - 1]?.speaker)].slice(-4);
      });
    }, 700);

    return () => clearTimeout(timer);
  }, [activeScreen, cursor, reduceMotion]);

  useEffect(() => {
    if (reduceMotion) return;

    let delayed;
    const timer = setInterval(() => {
      const currentCursor = cursor;
      const tone = currentCursor % 3 === 1 ? 'out' : 'in';
      delayed = setTimeout(() => {
        const text = normalizeText(scripted[currentCursor % scripted.length]);
        setMessages((current) => [
          ...current,
          buildMessage(text, tone, current.length + currentCursor, current[current.length - 1]?.speaker)
        ].slice(-4));
        setCursor((value) => value + 1);
      }, 700);
    }, 2800);

    return () => {
      clearInterval(timer);
      clearTimeout(delayed);
    };
  }, [cursor, reduceMotion]);

  return (
    <div className={`chatfloat ${className}`}>
      <div className="chatfloat__stack">
        <AnimatePresence initial={false}>
          {messages.map((message, index) => {
            const speaker = cast[message.speaker % cast.length];
            const bubbleTone = index % 2 === 0 ? 'in' : 'out';

            return (
              <motion.div
                key={message.id}
                initial={reduceMotion ? false : { opacity: 0, y: 18, scale: 0.96 }}
                animate={reduceMotion ? { opacity: 1 } : { opacity: 1, y: 0, scale: 1 }}
                exit={reduceMotion ? undefined : { opacity: 0, y: -22, scale: 0.96 }}
                className={`chatfloat__row chatfloat__row--depth-${index}`}
              >
                <div className={`chatfloat__avatar bg-gradient-to-br ${speaker.avatar}`} aria-hidden="true">
                  {speaker.name[0]}
                </div>
                <div className={`chatfloat__bubble chatfloat__bubble--${bubbleTone}`}>
                  {message.text}
                </div>
              </motion.div>
            );
          })}
        </AnimatePresence>
      </div>
    </div>
  );
}

function HeroReactionBubbles({ activeScreen, className = "" }) {
  const reduceMotion = useReducedMotion();
  const hasMountedRef = useRef(false);
  const recentTextsRef = useRef(['YOU SNAKE!']);
  const scripted = [
    'YOU SNAKE!',
    'I trusted you lol',
    'NO WAY THAT VOTE FLIPPED',
    'LMAO Sam your confessional',
    'who voted for me???',
    'David how could you?',
    'nahhhh that blindside was crazy'
  ];
  const lanes = [
    { right: '4%', bottom: '-4%', drift: '-18px', tone: 'violet' },
    { right: '18%', bottom: '2%', drift: '12px', tone: 'light' },
    { right: '10%', bottom: '8%', drift: '-10px', tone: 'rose' }
  ];
  const [messages, setMessages] = useState([
    { id: 1, text: 'YOU SNAKE!', lane: 0, duration: 8600, right: '4%', bottom: '-4%', drift: '-18px', tone: 'violet' }
  ]);
  const [cursor, setCursor] = useState(0);

  function buildMessage(text, index) {
    const laneIndex = index % lanes.length;
    const lane = lanes[laneIndex];
    return {
      id: Date.now() + Math.random(),
      text,
      lane: laneIndex,
      duration: 8400 + ((index % 3) * 600),
      right: lane.right,
      bottom: lane.bottom,
      drift: lane.drift,
      tone: lane.tone
    };
  }

  function chooseNextText(preferredText) {
    const recent = recentTextsRef.current;
    const candidates = [preferredText, ...scripted.filter((text) => text !== preferredText)];
    const selected = candidates.find((text) => !recent.includes(text)) ?? preferredText;
    recentTextsRef.current = [...recent, selected].slice(-4);
    return selected;
  }

  function queueMessage(preferredText, index) {
    const text = chooseNextText(preferredText);
    const message = buildMessage(text, index);
    setMessages((current) => [...current, message].slice(-4));
    window.setTimeout(() => {
      setMessages((current) => current.filter((item) => item.id !== message.id));
    }, message.duration);
  }

  useEffect(() => {
    if (reduceMotion) return;

    if (!hasMountedRef.current) {
      hasMountedRef.current = true;
      return;
    }

    const nextByScreen = {
      confessional: 'LMAO Sam your confessional',
      episode: 'NO WAY THAT VOTE FLIPPED',
      vote: 'who voted for me???'
    };

    const timer = setTimeout(() => {
      queueMessage(nextByScreen[heroSlides[activeScreen]?.key] ?? scripted[0], cursor);
      setCursor((value) => value + 1);
    }, 900);

    return () => clearTimeout(timer);
  }, [activeScreen, reduceMotion]);

  useEffect(() => {
    if (reduceMotion) return;

    let delayed;
    const timer = setInterval(() => {
      const currentCursor = cursor;
      delayed = setTimeout(() => {
        const text = scripted[currentCursor % scripted.length];
        queueMessage(text, currentCursor);
        setCursor((value) => value + 1);
      }, 700);
    }, 3200);

    return () => {
      clearInterval(timer);
      clearTimeout(delayed);
    };
  }, [cursor, reduceMotion]);

  return (
    <div className={`hero-reactions ${className}`}>
      <AnimatePresence initial={false}>
        {messages.map((message) => (
          <motion.div
            key={message.id}
            className={`hero-reactions__bubble hero-reactions__bubble--${message.tone}`}
            style={{
              right: message.right,
              bottom: message.bottom,
              '--hero-bubble-drift': message.drift,
              '--hero-bubble-duration': `${message.duration}ms`
            }}
          >
            {message.text}
          </motion.div>
        ))}
      </AnimatePresence>
    </div>
  );
}

function LandingPage() {
  const [isSubmitting, setIsSubmitting] = useState(false);
  const [error, setError] = useState(null);
  const [response, setResponse] = useState(null);
  const [copied, setCopied] = useState(false);
  const [formState, setFormState] = useState({ email: '' });
  const [emailError, setEmailError] = useState('');
  const [showStickyCta, setShowStickyCta] = useState(false);
  const [turnstileToken, setTurnstileToken] = useState('');
  const [turnstileReady, setTurnstileReady] = useState(false);
  const heroRef = useRef(null);
  const turnstileContainerRef = useRef(null);
  const turnstileWidgetIdRef = useRef(null);

  const referralCode = useMemo(() => {
    return new URLSearchParams(window.location.search).get('ref')?.toUpperCase() ?? '';
  }, []);

  const [utmParams] = useState(() => {
    const params = new URLSearchParams(window.location.search);
    return {
      utmSource: params.get('utm_source') || '',
      utmMedium: params.get('utm_medium') || '',
      utmCampaign: params.get('utm_campaign') || ''
    };
  });

  const invitesToThree = response?.milestoneProgress?.invites3 ?? 0;
  const invitesToSix = response?.milestoneProgress?.invites6 ?? 0;

  useEffect(() => {
    if (!TURNSTILE_SITE_KEY) return;

    if (window.turnstile) {
      setTurnstileReady(true);
      return;
    }

    const intervalId = window.setInterval(() => {
      if (window.turnstile) {
        setTurnstileReady(true);
        window.clearInterval(intervalId);
      }
    }, 250);

    return () => window.clearInterval(intervalId);
  }, []);

  useEffect(() => {
    if (!TURNSTILE_SITE_KEY || !turnstileReady || !turnstileContainerRef.current || !window.turnstile) {
      return;
    }

    if (turnstileWidgetIdRef.current !== null) {
      window.turnstile.remove(turnstileWidgetIdRef.current);
      turnstileWidgetIdRef.current = null;
    }

    turnstileWidgetIdRef.current = window.turnstile.render(turnstileContainerRef.current, {
      sitekey: TURNSTILE_SITE_KEY,
      theme: 'light',
      callback: (token) => setTurnstileToken(String(token || '').trim()),
      'expired-callback': () => setTurnstileToken(''),
      'error-callback': () => setTurnstileToken('')
    });

    return () => {
      if (turnstileWidgetIdRef.current !== null && window.turnstile) {
        window.turnstile.remove(turnstileWidgetIdRef.current);
        turnstileWidgetIdRef.current = null;
      }
    };
  }, [turnstileReady]);

  useEffect(() => {
    const observer = new IntersectionObserver(
      (entries) => {
        entries.forEach((entry) => {
          if (entry.isIntersecting) entry.target.classList.add('is-visible');
        });
      },
      { threshold: 0.12 }
    );

    document.querySelectorAll('.reveal').forEach((element) => observer.observe(element));
    return () => observer.disconnect();
  }, []);

  useEffect(() => {
    function onScroll() {
      if (!heroRef.current) return;
      const rect = heroRef.current.getBoundingClientRect();
      setShowStickyCta(rect.bottom < 120);
    }

    onScroll();
    window.addEventListener('scroll', onScroll, { passive: true });
    return () => window.removeEventListener('scroll', onScroll);
  }, []);

  function validateEmail(email) {
    return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
  }

  async function handleSubmit(event) {
    event.preventDefault();
    setError(null);

    if (!validateEmail(formState.email)) {
      setEmailError('Enter a valid email address.');
      return;
    }

    setEmailError('');
    setIsSubmitting(true);

    try {
      if (!turnstileToken) {
        setError('Please complete the bot check.');
        return;
      }

      const result = await fetch('/api/waitlist', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          ...formState,
          referralCode,
          turnstileToken,
          ...utmParams
        })
      });

      const data = await result.json();

      if (!result.ok || !data.success) {
        setError(data.error ?? 'Unable to join right now.');
        return;
      }

      setResponse(data);
      setTurnstileToken('');
    } catch {
      setError('Unable to join right now.');
    } finally {
      setIsSubmitting(false);
    }
  }

  async function copyLink() {
    if (!response?.referralLink) return;
    await navigator.clipboard.writeText(response.referralLink);
    setCopied(true);
    setTimeout(() => setCopied(false), 1500);
  }

  return (
    <div className="relative pb-20">
      <div className="noise-layer" />
      <div className="pointer-events-none absolute inset-0 -z-10 overflow-hidden" aria-hidden="true">
        <img
          src="/hero-screens/background.png"
          alt=""
          className="absolute left-1/2 top-0 w-screen min-w-full -translate-x-1/2 opacity-[0.56] blur-[1px] [mask-image:linear-gradient(180deg,black_0%,black_44%,rgba(0,0,0,0.78)_66%,transparent_100%)] sm:opacity-[0.62] lg:opacity-[0.68]"
        />
        <div className="absolute inset-0 bg-[linear-gradient(180deg,rgba(63,11,115,0.68)_0%,rgba(46,10,88,0.64)_18%,rgba(37,9,70,0.52)_46%,rgba(25,18,58,0.34)_74%,rgba(11,16,32,0.14)_100%)]" />
        <div className="absolute inset-0 bg-[radial-gradient(circle_at_top_right,rgba(255,255,255,0.14),transparent_28%),radial-gradient(circle_at_18%_22%,rgba(244,114,182,0.14),transparent_26%)]" />
      </div>

      <header className="relative z-20 bg-transparent">
        <div className="section-shell flex h-20 items-center justify-between">
          <div className="flex items-center gap-2 text-white">
            <span className="h-7 w-7 rounded-full bg-white/90 shadow-[0_2px_10px_rgba(255,255,255,0.4)]" />
            <span className="text-3xl font-semibold tracking-tight">Logo</span>
          </div>
          <a href="#waitlist" className="rounded-full bg-gradient-to-r from-fuchsia-500 to-pink-400 px-6 py-3 text-2xl font-semibold text-white shadow-[0_12px_30px_rgba(240,46,170,0.58)] md:px-10">Join Season One Now</a>
        </div>
      </header>

      <main className="section-shell">
        <section ref={heroRef} className="reveal relative isolate grid gap-12 py-10 lg:grid-cols-[1.05fr_0.95fr] lg:items-start">
          <div className="z-10 min-w-0 px-5 pt-6 sm:px-7 lg:px-0 lg:pt-14">
            <h1 className="text-5xl font-bold leading-[1.08] tracking-tight text-white sm:text-6xl lg:text-7xl">
              What if your friend group was a reality TV season?
            </h1>
            <p className="mt-3 text-xl font-medium text-fuchsia-100 sm:text-2xl">Who in your friend group would get voted out first?</p>
            <p className="mt-6 text-2xl leading-snug text-white/90 sm:text-3xl">
              Challenges, votes, and confessionals. Your friend group becomes the show.
            </p>

            <form onSubmit={handleSubmit} id="waitlist" className="mt-8 space-y-4">
              {!response ? (
                <>
                  <div className="flex flex-col overflow-hidden rounded-2xl border border-fuchsia-200/30 bg-white/95 shadow-[0_12px_28px_rgba(73,7,110,0.4)] sm:flex-row">
                    <label htmlFor="hero-email" className="sr-only">Email address</label>
                    <input
                      id="hero-email"
                      aria-label="Email address"
                      type="email"
                      required
                      value={formState.email}
                      onChange={(e) => {
                        const email = e.target.value;
                        setFormState({ email });
                        if (emailError && validateEmail(email)) setEmailError('');
                      }}
                      className={`w-full bg-transparent px-5 py-4 text-xl text-slate-800 placeholder:text-slate-500 ${emailError ? 'ring-1 ring-rose-400/80' : ''}`}
                      placeholder="Enter your email..."
                    />
                    <button type="submit" disabled={isSubmitting} className="bg-gradient-to-r from-fuchsia-500 to-pink-500 px-8 py-4 text-2xl font-semibold text-white shadow-[0_12px_30px_rgba(240,46,170,0.45)] disabled:opacity-70">{isSubmitting ? 'Joining...' : 'Join Season One Now'}</button>
                  </div>
                  {TURNSTILE_SITE_KEY ? (
                    <div>
                      <div ref={turnstileContainerRef} />
                      {!turnstileReady ? <p className="mt-1 text-xs text-white/80">Loading bot check…</p> : null}
                    </div>
                  ) : null}
                  {emailError ? <p className="text-sm text-rose-300">{emailError}</p> : null}
                  {error ? <p className="text-sm text-rose-300">{error}</p> : null}
                </>
              ) : (
                <div className="space-y-4">
                  <div className="rounded-xl border border-emerald-300/25 bg-emerald-400/10 p-3 text-sm text-emerald-100">You’re in. Invite friends to unlock your season faster.</div>
                  <div className="flex flex-col gap-2 sm:flex-row">
                    <input id="referralLinkHero" readOnly value={response.referralLink} className="w-full rounded-xl border border-white/20 bg-slate-900/80 px-4 py-3" />
                    <button type="button" onClick={copyLink} className="rounded-xl border border-cyan-300/60 px-4 py-2">{copied ? 'Copied' : 'Copy'}</button>
                  </div>
                  <div className="rounded-xl border border-white/10 bg-white/5 p-4 text-sm text-white">
                    <p>{invitesToThree} / 3 invites</p>
                    <p className="mt-2">{invitesToSix} / 6 invites</p>
                  </div>
                </div>
              )}
            </form>

            <ul className="mt-4 space-y-2 text-3xl text-white/90 sm:text-[2rem]">
              <li>✓ <strong>3 friends</strong> → unlock your season</li>
              <li>✓ <strong>6 friends</strong> → guaranteed early access</li>
            </ul>
          </div>

          <div className="relative mx-auto w-full max-w-[860px] min-w-0 px-5 sm:px-7 lg:px-0 lg:pt-2">
            <div className="relative ml-auto w-full max-w-[820px] motion-safe:animate-[floatSoft_6s_ease-in-out_infinite] sm:w-full">
              <img src="/hero-screens/confessional_hero.png" alt="App preview" className="h-full w-full rounded-[38px] object-cover" />
              <span className="absolute right-[-22px] top-12 rounded-full border border-white/30 bg-fuchsia-500/60 px-3 py-1 text-sm font-semibold text-white">ON AIR</span>
            </div>
            <div className="pointer-events-none absolute right-[27%] top-[66%] hidden h-10 w-16 rounded-full border border-fuchsia-300/45 bg-fuchsia-300/20 blur-[1px] md:block" aria-hidden="true" />
            <div className="pointer-events-none absolute bottom-[-10%] left-[22%] right-0 top-[18%] z-10">
              <HeroReactionBubbles activeScreen={0} className="h-full w-full" />
            </div>
          </div>
        </section>

        <section id="how" className="reveal py-10 lg:py-14">
          <h2 className="text-5xl font-bold text-white sm:text-6xl">Why friend groups get addicted</h2>
          <div className="mt-7 grid gap-5 md:grid-cols-3">
            {pillars.map((pillar, idx) => (
              <article key={pillar.title} className="rounded-3xl border border-white/20 bg-white/10 p-6 text-center shadow-[0_10px_24px_rgba(10,0,35,0.35)] backdrop-blur-lg">
                <div className="mb-4 text-5xl">{idx === 0 ? '🧠' : idx === 1 ? '📹' : '🎬'}</div>
                <h3 className="text-4xl font-semibold leading-tight text-white">{pillar.title}</h3>
                <p className="mt-3 text-2xl text-white/85">{pillar.body}</p>
              </article>
            ))}
          </div>

          <div className="mt-10 flex justify-center">
            <a href="#waitlist" className="rounded-full bg-gradient-to-r from-fuchsia-500 to-pink-400 px-14 py-4 text-4xl font-semibold text-white shadow-[0_14px_36px_rgba(240,46,170,0.5)]">Join Season One Now</a>
          </div>
        </section>
      </main>

      {showStickyCta && (
        <div className="fixed bottom-4 left-4 right-4 z-40 sm:hidden">
          <a href="#waitlist" className="mobile-sticky-cta flex items-center justify-center gap-2 rounded-full border border-white/20 px-6 py-3 text-center font-semibold text-white">
            Join Season One Now <span aria-hidden="true">→</span>
          </a>
        </div>
      )}
    </div>
  );
}

ReactDOM.createRoot(document.getElementById('root')).render(<LandingPage />);
