// Replied — demo video scenes (MOBILE, portrait 9:16)
// Spec: 39s, 1080×1920, autoplay-on-scroll friendly. No VO.
// Scenes: Hook (0-5.5) · Thesis sort (5-19) · Drafts (19-31) · Trust (31-35) · CTA (35-39)
// Mirror of demo-v2 with portrait layout — no sidebar, stacked drafts, stacked trust cards.

const { Stage, Sprite, useTime, useSprite, Easing, interpolate, animate } = window;

// ───────────────────────── Spring helpers ─────────────────────────
const overshoot = Easing.easeOutBack;
const settle = Easing.easeOutCubic;
const clamp01 = (v) => Math.max(0, Math.min(1, v));

// ───────────────────────── Color tokens ─────────────────────────
const C = {
  ink: '#0F1419', mute: '#6B7280', border: '#E5E7EB', paper: '#FFFFFF',
  teal: '#1F4D45', tealHover: '#2A6F63',
  pass: '#22C55E', review: '#F59E0B', fail: '#EF4444', grey: '#9CA3AF',
  passBg: 'rgba(34,197,94,0.14)', passText: '#166534',
  reviewBg: 'rgba(245,158,11,0.14)', reviewText: '#92400E',
  failBg: 'rgba(239,68,68,0.14)', failText: '#991B1B',
  greyBg: 'rgba(156,163,175,0.18)', greyText: '#525866',
};

const FONT = '"Inter", system-ui, -apple-system, sans-serif';

// Canvas dimensions
const CW = 1080, CH = 1920;

// ───────────────────────── Backgrounds ─────────────────────────
function StageBg() {
  const t = useTime();
  const a = interpolate([0, 18, 30, 40], [0, 1, 0.5, 0])(t);
  return (
    <div style={{
      position: 'absolute', inset: 0,
      background: `radial-gradient(900px 1200px at 30% 15%, #F4F8F7, #FFFFFF 60%), radial-gradient(700px 900px at 80% 85%, rgba(31,77,69,${0.04 + a * 0.04}), transparent 65%)`,
    }} />
  );
}

// ───────────────────────── Mobile mail frame ─────────────────────────
// Phone-mail-style frame: status bar + header + (optional) chip row + list.
// Lives near full-bleed since the canvas itself is the phone.
function MobileMailFrame({ children, header = 'Inbox', subheader = null, chips = null, fullBleed = false }) {
  const framePos = fullBleed
    ? { left: 32, top: 60, width: CW - 64, height: CH - 120 }
    : { left: 32, top: 200, width: CW - 64, height: CH - 320 };
  return (
    <div style={{
      position: 'absolute', ...framePos,
      background: '#fff', borderRadius: 36,
      boxShadow: '0 32px 80px rgba(15,20,25,0.18), 0 8px 24px rgba(15,20,25,0.08)',
      overflow: 'hidden', display: 'flex', flexDirection: 'column',
      border: `1px solid ${C.border}`, fontFamily: FONT,
    }}>
      {/* Status bar — minimal */}
      <div style={{ height: 52, display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '0 32px', background: '#fff', fontSize: 22, fontWeight: 600, color: C.ink }}>
        <span style={{ fontVariantNumeric: 'tabular-nums' }}>9:41</span>
        <span style={{ display: 'inline-flex', alignItems: 'center', gap: 8 }}>
          <span style={{ width: 18, height: 12, borderRadius: 2, background: C.ink, opacity: 0.9 }} />
          <span style={{ width: 22, height: 12, borderRadius: 2, background: C.ink, opacity: 0.9 }} />
        </span>
      </div>
      {/* Header */}
      <div style={{ padding: '20px 32px 16px', borderBottom: `1px solid ${C.border}`, background: '#FAFAFA' }}>
        <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between' }}>
          <span style={{ fontSize: 42, fontWeight: 700, color: C.ink, letterSpacing: '-0.015em' }}>{header}</span>
          {subheader}
        </div>
        {chips && (
          <div style={{ display: 'flex', gap: 12, marginTop: 18, flexWrap: 'nowrap' }}>
            {chips}
          </div>
        )}
      </div>
      {/* Mail list */}
      <div style={{ flex: 1, display: 'flex', flexDirection: 'column', minWidth: 0, background: '#fff', position: 'relative', overflow: 'hidden' }}>
        {children}
      </div>
    </div>
  );
}

// ───────────────────────── Chip (Match/Review/Fail counters) ─────────────────────────
function Chip({ label, count, color, bg, fg, active }) {
  return (
    <div style={{
      display: 'inline-flex', alignItems: 'center', gap: 10,
      padding: '12px 20px', borderRadius: 999,
      background: active ? bg : 'rgba(0,0,0,0.04)',
      border: active ? `2px solid ${color}` : `2px solid transparent`,
      transition: 'background 200ms, border 200ms, transform 200ms',
      transform: active ? 'scale(1.04)' : 'scale(1)',
      flex: 1, justifyContent: 'center',
    }}>
      <span style={{ width: 14, height: 14, borderRadius: 7, background: color, flexShrink: 0 }} />
      <span style={{ fontSize: 24, fontWeight: 700, color: active ? fg : C.ink, letterSpacing: '-0.005em' }}>{label}</span>
      <span style={{
        fontSize: 22, fontWeight: 700,
        background: active ? color : 'transparent',
        color: active ? '#fff' : C.mute,
        padding: active ? '2px 12px' : '0', borderRadius: 999,
        minWidth: 28, textAlign: 'center', fontVariantNumeric: 'tabular-nums',
      }}>{count}</span>
    </div>
  );
}

// ───────────────────────── Email row (mobile, single-column) ─────────────────────────
function EmailRow({ sender, subject, preview, time = '2h', verdict, draftReady, style }) {
  const stripe = verdict === 'pass' ? C.pass : verdict === 'review' ? C.review : verdict === 'fail' ? C.fail : verdict === 'grey' ? C.grey : 'transparent';
  const VLAB = { pass: 'Match', review: 'Review', fail: 'Fail', grey: 'Not a pitch' };
  const vbg = verdict === 'pass' ? C.passBg : verdict === 'review' ? C.reviewBg : verdict === 'fail' ? C.failBg : verdict === 'grey' ? C.greyBg : null;
  const vfg = verdict === 'pass' ? C.passText : verdict === 'review' ? C.reviewText : verdict === 'fail' ? C.failText : verdict === 'grey' ? C.greyText : null;
  return (
    <div style={{
      display: 'flex', alignItems: 'stretch',
      borderBottom: `1px solid ${C.border}`,
      background: '#fff',
      ...style,
    }}>
      <div style={{ width: 8, background: stripe }} />
      <div style={{ flex: 1, padding: '22px 28px', minWidth: 0 }}>
        <div style={{ display: 'flex', alignItems: 'baseline', gap: 14, marginBottom: 6 }}>
          <span style={{ fontWeight: 600, fontSize: 30, color: C.ink, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', flex: '0 1 auto' }}>{sender}</span>
          <span style={{ fontSize: 22, color: C.mute, fontVariantNumeric: 'tabular-nums', marginLeft: 'auto' }}>{time}</span>
        </div>
        <div style={{ fontSize: 26, fontWeight: 500, color: C.ink, marginBottom: 6, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{subject}</div>
        {preview && <div style={{ fontSize: 22, color: C.mute, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', marginBottom: verdict || draftReady ? 12 : 0 }}>{preview}</div>}
        {(verdict || draftReady) && (
          <div style={{ display: 'flex', alignItems: 'center', gap: 14, marginTop: 4 }}>
            {verdict && (
              <span style={{ background: vbg, color: vfg, padding: '5px 16px', borderRadius: 999, fontSize: 20, fontWeight: 700, letterSpacing: '0.02em' }}>
                {VLAB[verdict]}
              </span>
            )}
            {draftReady && (
              <span style={{ fontSize: 20, color: C.teal, fontWeight: 600, display: 'inline-flex', alignItems: 'center', gap: 6 }}>
                <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"><polyline points="9 14 4 9 9 4" /><path d="M20 20v-7a4 4 0 0 0-4-4H4" /></svg>
                Draft ready
              </span>
            )}
          </div>
        )}
      </div>
    </div>
  );
}

// ───────────────────────── Shared inbox catalog ─────────────────────────
const INBOX = [
  { sender: 'Sarah Chen',       subject: 'Northwind — AI ops for legal',                   preview: 'ex-A&O + ex-Stripe. £180K ARR.',                time: '2m',  verdict: 'pass'   },
  { sender: 'TechCrunch Daily', subject: 'This week in venture',                            preview: 'Trending: AI infra, EU pre-seed.',              time: '6m',  verdict: null     },
  { sender: 'Tom Rhys',         subject: 'YC W25 — vertical AI for B2B',                   preview: 'Pre-seed, $400K ARR, SF.',                      time: '11m', verdict: 'review' },
  { sender: 'ColdReach Sales',  subject: 'Boost your deal flow!',                           preview: 'Save 15% — book a demo today.',                 time: '14m', verdict: null     },
  { sender: 'Marcus Liu',       subject: 'RigForge — Series C hardware',                   preview: 'Hardware unit margins improving.',              time: '22m', verdict: 'fail'   },
  { sender: 'Priya Patel',      subject: 'Compliance ops for fintech',                     preview: 'ex-Plaid. £900K round.',                        time: '47m', verdict: 'pass'   },
  { sender: 'David Park',       subject: 'Lumen — B2B SaaS payments',                      preview: 'Pre-seed, $250K ARR.',                          time: '1h',  verdict: 'review' },
  { sender: 'AWS',              subject: 'Your AWS bill is ready',                          preview: 'November invoice — $324.18.',                   time: '2h',  verdict: null     },
  { sender: 'Nina Volkov',      subject: 'DevOps for climate teams',                       preview: 'EU-based, technical. €1M round.',               time: '3h',  verdict: 'pass'   },
  { sender: 'Felix Adair',      subject: 'Series B — consumer marketplace',                 preview: '$50M Series B.',                                time: '4h',  verdict: 'fail'   },
];

const SCROLL_FEED = [
  ...INBOX,
  { sender: 'Yara Abboud', subject: 'Pre-seed — voice AI for clinics',  preview: '£500K round, EU.',           time: '5h', verdict: 'pass' },
  { sender: 'LinkedIn',    subject: '12 new connection requests',        preview: 'See who wants to connect.',  time: '5h', verdict: null  },
  { sender: 'Ben Howell',  subject: 'Series A — quick look?',             preview: '$15M Series A.',             time: '6h', verdict: 'fail' },
  { sender: 'Jamie Ortiz', subject: 'Climate fintech, pre-seed',          preview: 'Lisbon-based, technical.',   time: '6h', verdict: 'pass' },
  { sender: 'Notion',      subject: 'Your weekly digest',                  preview: '4 docs updated.',            time: '7h', verdict: null  },
  { sender: 'Felix Tan',   subject: 'Devtools for AI agents',              preview: '£800K round, London.',       time: '7h', verdict: 'pass' },
  { sender: 'GitHub',      subject: 'sarah-chen pushed to dawnvc',         preview: '12 new commits.',            time: '8h', verdict: null  },
  { sender: 'Hana Aiba',   subject: 'Series B fintech — follow-on?',       preview: '$40M Series B.',             time: '8h', verdict: 'fail' },
];

// ═══════════════════════ SCENE 1 — Hook (0-5.5) ═══════════════════════
function Scene1() {
  const t = useTime();
  if (t > 5.5) return null;

  const counter = Math.floor(interpolate([0, 0.4, 1.6, 2.4, 3.0], [0, 22, 96, 218, 312])(t));

  // Title pop at 2.5s — holds extra second, fades 5.3-5.5
  const titleStart = 2.5;
  const titleP = clamp01((t - titleStart) / 0.55);
  const titleScale = 0.7 + 0.3 * overshoot(titleP);
  const titleOp = clamp01((t - titleStart) / 0.4) * (1 - clamp01((t - 5.3) / 0.2));

  // Inbox blur builds in time for the title
  const blur = interpolate([2.0, 2.6], [0, 8])(t);
  const inboxOp = interpolate([2.0, 2.6, 5.3, 5.5], [1, 0.45, 0.45, 0])(t);

  // Fast scroll: list translates upward continuously
  const ROW_H = 168;
  const scrollY = -interpolate([0, 2.4], [0, ROW_H * 10])(t);

  return (
    <>
      <div style={{ position: 'absolute', inset: 0, opacity: inboxOp, filter: `blur(${blur}px)`, transition: 'opacity 200ms' }}>
        <MobileMailFrame fullBleed
          header="Inbox"
          subheader={<span style={{ fontSize: 22, color: C.mute, fontVariantNumeric: 'tabular-nums' }}>
            <b style={{ color: C.ink, fontSize: 30, fontWeight: 700 }}>{counter}</b>&nbsp;new
          </span>}
        >
          <div style={{ flex: 1, overflow: 'hidden', position: 'relative' }}>
            <div style={{ transform: `translateY(${scrollY}px)`, willChange: 'transform' }}>
              {SCROLL_FEED.map((e, i) => {
                const rowStart = 0.05 + i * 0.10;
                const p = clamp01((t - rowStart) / 0.32);
                if (p <= 0) return null;
                return (
                  <div key={i} style={{ opacity: p }}>
                    <EmailRow sender={e.sender} subject={e.subject} preview={e.preview} time={e.time} />
                  </div>
                );
              })}
            </div>
            <div style={{ position: 'absolute', inset: 0, background: 'linear-gradient(180deg, rgba(255,255,255,0.55), transparent 14%, transparent 86%, rgba(255,255,255,0.55))', pointerEvents: 'none' }} />
          </div>
        </MobileMailFrame>
      </div>

      {/* Title pop — centered */}
      {t >= titleStart && (
        <div style={{
          position: 'absolute', left: '50%', top: '46%',
          transform: `translate(-50%, -50%) scale(${titleScale})`,
          opacity: titleOp, textAlign: 'center', fontFamily: FONT,
          width: '90%',
        }}>
          <div style={{ fontSize: 156, fontWeight: 700, letterSpacing: '-0.03em', color: C.teal, lineHeight: 1, marginBottom: 24 }}>
            Replied.
          </div>
          <div style={{ fontSize: 56, fontWeight: 500, color: C.ink, letterSpacing: '-0.015em', marginBottom: 18, lineHeight: 1.2 }}>
            Reads every pitch,<br />drafts every reply.
          </div>
          <div style={{ fontSize: 42, fontWeight: 600, color: C.teal }}>
            Built for investors.
          </div>
        </div>
      )}
    </>
  );
}

// ═══════════════════════ SCENE 2 — Thesis sort (5-19) ═══════════════════════
function Scene2() {
  const t = useTime();
  if (t < 5 || t > 19.2) return null;
  const lt = t - 5;

  // Section title — top of screen
  const titleP = clamp01(lt / 0.5);
  const titleOp = clamp01((lt - 0.05) / 0.4) * (1 - clamp01((lt - 13.6) / 0.5));
  const titleTy = (1 - settle(titleP)) * -30;

  // Thesis card 1.0 - 6.0
  const cardStart = 1.0;
  const cardEnd = 6.0;
  const inThesis = lt >= cardStart && lt < cardEnd;
  const FULL = 'Pre-seed B2B SaaS.\nUK and EU.\nTechnical founders.';
  const typeStart = cardStart + 0.45;
  const typeDur = 1.8;
  const typedLen = Math.floor(interpolate([typeStart, typeStart + typeDur], [0, FULL.length])(lt));
  const typed = FULL.slice(0, typedLen);
  const TAGS = [
    { label: 'Stage: Pre-seed', t0: 3.5 },
    { label: 'Industry: B2B SaaS', t0: 3.7 },
    { label: 'Geo: UK/EU', t0: 3.9 },
    { label: 'Team: Technical', t0: 4.1 },
  ];
  const cardP = clamp01((lt - cardStart) / 0.6);
  const cardScale = 0.7 + 0.3 * overshoot(cardP);
  const cardExitP = clamp01((lt - (cardEnd - 0.4)) / 0.4);
  const cardOp = clamp01((lt - cardStart) / 0.4) * (1 - cardExitP);

  // Inbox stays visible behind everything; dimmed under thesis card, returns clear after
  const inboxFade = clamp01((lt - 0.4) / 0.5);
  const dimBlur = interpolate([cardStart, cardStart + 0.3, cardEnd - 0.3, cardEnd], [0, 6, 6, 0])(lt);
  const dimOp = interpolate([cardStart, cardStart + 0.3, cardEnd - 0.3, cardEnd], [1, 0.35, 0.35, 1])(lt);
  const inboxOp = inboxFade * dimOp * (1 - clamp01((lt - 13.6) / 0.5));

  // Pitch metadata
  const pillBaseT = 6.4;
  const pillStep = 0.32;
  const flyBaseT = 9.0;
  const flyStep = 0.34;
  const PITCHES = [];
  let order = 0;
  INBOX.forEach((e, idx) => {
    if (!e.verdict) return;
    PITCHES.push({
      idx, verdict: e.verdict,
      pillT: pillBaseT + order * pillStep,
      flyT: flyBaseT + order * flyStep,
    });
    order++;
  });

  // Counters tick after a pitch has flown
  const counters = { match: 0, review: 0, fail: 0 };
  PITCHES.forEach(p => {
    if (lt > p.flyT + 0.45) {
      const k = p.verdict === 'pass' ? 'match' : p.verdict === 'review' ? 'review' : 'fail';
      counters[k]++;
    }
  });

  // Active chip — pulses while a pitch is flying toward it
  const activeChip = (() => {
    let h = null;
    PITCHES.forEach(p => {
      if (lt > p.flyT + 0.20 && lt < p.flyT + 0.85) {
        h = p.verdict === 'pass' ? 'match' : p.verdict === 'review' ? 'review' : 'fail';
      }
    });
    return h;
  })();

  // Caption
  const capStart = 12.0;
  const capP = clamp01((lt - capStart) / 0.5);
  const capOp = clamp01((lt - capStart) / 0.4) * (1 - clamp01((lt - 13.6) / 0.5));

  // Fly-out geometry — UPWARD into chips
  // Mail list starts at ~ y=380 (frame top 200 + status 52 + header ~200 incl chip row).
  // Chips live at roughly y=340 from canvas top → fly direction is up.
  const ROW_H = 162;
  const CHIP_Y_FROM_LIST = -240; // approx vertical distance from row centre to chip row
  const chipTargetX = (v) => {
    if (v === 'pass') return -CW * 0.30;
    if (v === 'review') return 0;
    return CW * 0.30;
  };

  const chips = (
    <>
      <Chip label="Match" count={counters.match} color={C.pass} bg={C.passBg} fg={C.passText} active={activeChip === 'match'} />
      <Chip label="Review" count={counters.review} color={C.review} bg={C.reviewBg} fg={C.reviewText} active={activeChip === 'review'} />
      <Chip label="Fail" count={counters.fail} color={C.fail} bg={C.failBg} fg={C.failText} active={activeChip === 'fail'} />
    </>
  );

  return (
    <>
      {/* Section title */}
      <div style={{
        position: 'absolute', left: 60, right: 60, top: 70, fontSize: 50, fontWeight: 700,
        color: C.ink, letterSpacing: '-0.02em', fontFamily: FONT,
        transform: `translateY(${titleTy}px)`, opacity: titleOp,
        lineHeight: 1.15,
      }}>
        Pitches ranked<br />by your thesis.
      </div>

      {/* Inbox — pitches fly UP to chips */}
      <div style={{
        position: 'absolute', inset: 0,
        opacity: inboxOp,
        filter: `blur(${dimBlur}px)`,
        transition: 'opacity 200ms',
      }}>
        <MobileMailFrame
          header="Inbox · today"
          chips={chips}
          subheader={lt > 6.0 ? (
            <span style={{ fontSize: 22, color: C.teal, fontWeight: 600, display: 'inline-flex', alignItems: 'center', gap: 10, opacity: clamp01((lt - 6.0) / 0.4) * (1 - clamp01((lt - 11.5) / 0.5)) }}>
              <span style={{ width: 14, height: 14, borderRadius: 7, background: C.pass, animation: 'pulse 1.4s ease-in-out infinite' }} />
              Sorting
            </span>
          ) : null}
        >
          <div style={{ flex: 1, padding: 0, position: 'relative', overflow: 'hidden' }}>
            {INBOX.map((e, i) => {
              const pitch = PITCHES.find(p => p.idx === i);
              const showVerdict = pitch && lt > pitch.pillT;
              let flyTx = 0, flyTy = 0, flyScale = 1, flyOp = 1;
              if (pitch && lt > pitch.flyT) {
                const fp = clamp01((lt - pitch.flyT) / 0.6);
                const ease = settle(fp);
                flyTx = chipTargetX(pitch.verdict) * ease;
                flyTy = (CHIP_Y_FROM_LIST - i * (ROW_H * 0.2)) * ease;
                flyScale = 1 - 0.85 * ease;
                flyOp = 1 - clamp01((lt - pitch.flyT - 0.32) / 0.28);
              }
              const pillP = pitch ? clamp01((lt - pitch.pillT) / 0.35) : 0;
              const pulse = pillP > 0 && pillP < 1 ? 1 + 0.02 * Math.sin(pillP * Math.PI) : 1;
              return (
                <div key={i} style={{
                  transform: `translate(${flyTx}px, ${flyTy}px) scale(${flyScale * pulse})`,
                  opacity: flyOp,
                  transformOrigin: 'center center',
                  transition: 'none',
                }}>
                  <EmailRow
                    sender={e.sender}
                    subject={e.subject}
                    preview={e.preview}
                    time={e.time}
                    verdict={showVerdict ? pitch.verdict : null}
                  />
                </div>
              );
            })}
          </div>
        </MobileMailFrame>
      </div>

      {/* Thesis card overlay — narrower for portrait */}
      {inThesis && (
        <div style={{
          position: 'absolute', left: '50%', top: '50%',
          transform: `translate(-50%, -50%) scale(${cardScale})`,
          opacity: cardOp, fontFamily: FONT,
          width: 920, padding: '52px 56px', borderRadius: 28,
          background: '#fff', border: `1px solid ${C.border}`,
          boxShadow: '0 32px 80px rgba(15,20,25,0.28)',
        }}>
          <div style={{ fontSize: 22, color: C.mute, letterSpacing: '0.14em', textTransform: 'uppercase', fontWeight: 700, marginBottom: 22 }}>Your thesis</div>
          <div style={{ fontSize: 52, fontWeight: 600, color: C.ink, letterSpacing: '-0.015em', lineHeight: 1.25, minHeight: 200, whiteSpace: 'pre-line' }}>
            {typed}
            {lt < typeStart + typeDur + 0.2 && <span style={{ display: 'inline-block', width: 4, height: 48, background: C.teal, marginLeft: 4, verticalAlign: '-8px', animation: 'cursor 0.6s steps(2) infinite' }} />}
          </div>
          <div style={{ display: 'flex', gap: 14, marginTop: 36, flexWrap: 'wrap' }}>
            {TAGS.map((tag, i) => {
              const p = clamp01((lt - tag.t0) / 0.45);
              if (p <= 0) return null;
              const sc = 0.7 + 0.3 * overshoot(p);
              return (
                <div key={i} style={{
                  background: 'rgba(31,77,69,0.08)', color: C.teal,
                  padding: '10px 22px', borderRadius: 999,
                  fontSize: 24, fontWeight: 600,
                  transform: `scale(${sc})`, opacity: clamp01((lt - tag.t0) / 0.3),
                }}>{tag.label}</div>
              );
            })}
          </div>
        </div>
      )}

      {/* Caption */}
      {lt >= capStart && (
        <div style={{
          position: 'absolute', left: '50%', top: '50%',
          transform: `translate(-50%, calc(-50% + ${(1 - settle(capP)) * 18}px)) scale(${0.85 + 0.15 * overshoot(capP)})`,
          opacity: capOp, fontSize: 96, fontWeight: 700,
          color: C.teal, fontFamily: FONT, letterSpacing: '-0.025em',
          textAlign: 'center', whiteSpace: 'nowrap',
          padding: '32px 56px', borderRadius: 28,
          background: 'rgba(255,255,255,0.92)',
          backdropFilter: 'blur(16px)',
          WebkitBackdropFilter: 'blur(16px)',
          boxShadow: '0 32px 80px rgba(15,20,25,0.18)',
        }}>
          Pitches in. Spam out.
        </div>
      )}
    </>
  );
}

// ═══════════════════════ SCENE 3 — Drafts (19-31) ═══════════════════════
function Scene3() {
  const t = useTime();
  if (t < 19 || t > 31.2) return null;
  const lt = t - 19;

  // Section title — top
  const titleP = clamp01(lt / 0.5);
  const titleOp = clamp01(lt / 0.4) * (1 - clamp01((lt - 11.5) / 0.5));
  const titleTy = (1 - settle(titleP)) * -30;

  // Timing anchors (kept identical to v2)
  const T_BULLET1 = 0.8;
  const T_MATCH_PILL = 1.3;
  const T_BULLET2 = 2.6;
  const T_HIGHLIGHT = 2.95;
  const T_VAR2 = 4.1;
  const T_VAR3 = 5.4;
  const T_BULLET3 = 6.9;
  const T_SHUFFLE = 7.1;
  const T_REFERRAL = 8.5;

  // Sarah card entry + exit
  const sarahCardP = clamp01((lt - 0.2) / 0.6);
  const sarahEntryTy = (1 - overshoot(sarahCardP)) * 50;
  const sarahEntryOp = clamp01((lt - 0.2) / 0.5);
  const shuffleP = clamp01((lt - T_SHUFFLE) / 0.7);
  const sarahExitOp = 1 - settle(shuffleP);
  const sarahExitTx = -settle(shuffleP) * 18;
  const sarahExitRot = settle(shuffleP) * -2;
  const sarahExitScale = 1 - settle(shuffleP) * 0.04;

  // Match pill pop
  const pillP = clamp01((lt - T_MATCH_PILL) / 0.45);
  const matchPillScale = pillP <= 0 ? 0 : (0.4 + 0.6 * overshoot(pillP));
  const matchPillOp = clamp01((lt - T_MATCH_PILL) / 0.3);

  // Variants
  const VARIANTS = [
    { text: 'Grab a 30-min slot:', link: 'calendly.com/replied-vc', start: 0 },
    { text: 'Please fill the form at:', link: 'dawnvc.com/intake', start: T_VAR2 },
    { text: 'Upload a founder video here:', link: 'upload.dawnvc.com', start: T_VAR3 },
  ];

  const highlightOp = (lt > T_HIGHLIGHT)
    ? clamp01((lt - T_HIGHLIGHT) / 0.3) * (1 - clamp01((lt - 10.6) / 0.6))
    : 0;

  const pulseAtTime = (t0) => {
    const dt = lt - t0;
    if (dt < 0 || dt > 0.6) return 0;
    return Math.sin((dt / 0.6) * Math.PI);
  };
  const variantPulse = Math.max(
    pulseAtTime(T_HIGHLIGHT),
    pulseAtTime(T_VAR2),
    pulseAtTime(T_VAR3),
  );

  // Marcus
  const marcusP = clamp01((lt - T_SHUFFLE) / 0.7);
  const marcusOp = clamp01((lt - (T_SHUFFLE - 0.05)) / 0.55) * (1 - clamp01((lt - 11.5) / 0.5));
  const marcusTx = (1 - settle(marcusP)) * 22;
  const marcusScale = 0.94 + 0.06 * overshoot(marcusP);
  const marcusRot = (1 - settle(marcusP)) * 2.5;

  const referralPulse = lt > T_REFERRAL && lt < T_REFERRAL + 2.0;

  // Bullets — stacked vertically on mobile
  const BULLETS = [
    { label: 'Knows your thesis',          t0: T_BULLET1 },
    { label: 'Fits your workflow',         t0: T_BULLET2 },
    { label: 'Suggests referral funds',    t0: T_BULLET3 },
  ];

  return (
    <>
      <div style={{
        position: 'absolute', left: 60, right: 60, top: 70, fontSize: 48, fontWeight: 700,
        color: C.ink, letterSpacing: '-0.02em', fontFamily: FONT,
        transform: `translateY(${titleTy}px)`, opacity: titleOp,
        lineHeight: 1.15,
      }}>
        Replies drafted<br />in your voice.
      </div>

      {/* Vertical bullets — below title, above cards */}
      <div style={{
        position: 'absolute', left: 60, right: 60, top: 220,
        display: 'flex', flexDirection: 'column', gap: 16,
        fontFamily: FONT,
      }}>
        {BULLETS.map((b, i) => {
          const p = clamp01((lt - b.t0) / 0.6);
          const pop = (() => {
            if (p <= 0) return 0;
            if (p >= 1) return 1;
            const c1 = 2.5, c3 = c1 + 1;
            return 1 + c3 * Math.pow(p - 1, 3) + c1 * Math.pow(p - 1, 2);
          })();
          const sc = 0.5 + 0.5 * pop;
          const tx = (1 - pop) * -20;
          const rot = (1 - settle(p)) * -3;
          const op = clamp01((lt - b.t0) / 0.4) * (1 - clamp01((lt - 11.5) / 0.5));
          return (
            <div key={i} style={{
              display: 'flex', alignItems: 'center', gap: 16,
              transform: `translateX(${tx}px) scale(${sc}) rotate(${rot}deg)`,
              opacity: op, transformOrigin: 'left center',
            }}>
              <div style={{
                width: 48, height: 48, flexShrink: 0, borderRadius: 24,
                background: C.teal, color: '#fff', display: 'flex',
                alignItems: 'center', justifyContent: 'center', fontWeight: 700,
                fontSize: 28, fontFamily: FONT,
              }}>{i + 1}</div>
              <div style={{ fontSize: 34, color: C.ink, fontWeight: 500, lineHeight: 1.3 }}>{b.label}</div>
            </div>
          );
        })}
      </div>

      {/* Cards container — Sarah / Marcus stacked draft cards */}
      <div style={{
        position: 'absolute', left: '50%', top: 510, fontFamily: FONT,
        transform: 'translateX(-50%)', width: 980,
      }}>
        {/* Sarah */}
        <div style={{
          position: 'absolute', top: 0, left: 0, width: '100%',
          transform: `translate(${sarahExitTx}px, ${sarahEntryTy}px) scale(${sarahExitScale}) rotate(${sarahExitRot}deg)`,
          opacity: sarahEntryOp * sarahExitOp,
          transformOrigin: 'center center',
          zIndex: 2,
        }}>
          <DraftCard
            verdict="pass"
            senderName="Sarah Chen"
            senderMeta="Northwind — AI ops for legal"
            pillScale={matchPillScale}
            pillOpacity={matchPillOp}
            original={[
              'Hi Jeremy,',
              "We're a 3-person team — ex-Allen & Overy + ex-Stripe — building the AI ops layer for in-house legal.",
              '6 paying design partners, £180K ARR, raising £1.2M pre-seed.',
            ]}
            draft={[
              'Hey Sarah —',
              "really like what you're building.",
              <VariantLine
                key="action"
                variants={VARIANTS}
                lt={lt}
                highlightOp={highlightOp}
                pulse={variantPulse}
              />,
              'Jeremy',
            ]}
          />
        </div>

        {/* Marcus */}
        <div style={{
          position: 'absolute', top: 0, left: 0, width: '100%',
          transform: `translateX(${marcusTx}px) scale(${marcusScale}) rotate(${marcusRot}deg)`,
          opacity: marcusOp,
          transformOrigin: 'center center',
          zIndex: 3,
        }}>
          <DraftCard
            verdict="fail"
            senderName="Marcus Liu"
            senderMeta="Series A consumer hardware — RigForge"
            original={[
              'Hi Jeremy,',
              "We're raising $12M Series A for our consumer hardware platform.",
              '$2.4M ARR, 18% MoM growth.',
            ]}
            draft={[
              'Hey Marcus —',
              'not a fit at this stage.',
              <>Worth trying <Highlight on={referralPulse}>Seedcamp</Highlight>, <Highlight on={referralPulse}>Connect Ventures</Highlight>, or <Highlight on={referralPulse}>Concept Ventures</Highlight> — they back this space.</>,
              'Jeremy',
            ]}
          />
        </div>
      </div>
    </>
  );
}

function VariantLine({ variants, lt, highlightOp, pulse }) {
  let activeIdx = 0;
  variants.forEach((v, i) => { if (lt >= v.start) activeIdx = i; });
  const v = variants[activeIdx];
  const pulseBg = 0.10 + 0.18 * pulse;
  const pulseShadow = 1.5 + 2.0 * pulse;
  return (
    <div style={{ minHeight: 72 }}>
      <div style={{
        display: 'inline-block',
        maxWidth: '100%',
        padding: '8px 14px',
        borderRadius: 6,
        background: highlightOp > 0 ? `rgba(31,77,69,${pulseBg * highlightOp})` : 'transparent',
        boxShadow: highlightOp > 0 ? `0 0 0 ${pulseShadow}px rgba(31,77,69,${0.55 * highlightOp})` : 'none',
        transition: 'background 200ms, box-shadow 200ms',
        lineHeight: 1.5,
      }}>
        {v.text}&nbsp;<a style={{
          color: C.teal, textDecoration: 'none', fontWeight: 600,
        }}>{v.link}</a>
      </div>
    </div>
  );
}

function Highlight({ children, on }) {
  return (
    <span style={{
      background: on ? 'rgba(31,77,69,0.18)' : 'transparent',
      boxShadow: on ? `0 0 0 1.5px ${C.teal}` : 'none',
      padding: '0 4px', borderRadius: 4,
      transition: 'background 250ms, box-shadow 250ms',
      fontWeight: 600, color: C.teal,
    }}>{children}</span>
  );
}

function DraftCard({ verdict, senderName, senderMeta, original, draft, pillScale = 1, pillOpacity = 1 }) {
  const VLAB = { pass: 'Match', fail: 'Fail' };
  const vbg = verdict === 'pass' ? C.passBg : C.failBg;
  const vfg = verdict === 'pass' ? C.passText : C.failText;
  return (
    <div style={{
      width: 980, background: '#fff', borderRadius: 28,
      border: `1px solid ${C.border}`,
      boxShadow: '0 28px 72px rgba(15,20,25,0.18)',
      overflow: 'hidden',
    }}>
      <div style={{ padding: '28px 36px 22px', borderBottom: `1px solid ${C.border}`, display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
        <div style={{ minWidth: 0, flex: 1 }}>
          <div style={{ fontSize: 34, fontWeight: 700, color: C.ink, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{senderName}</div>
          <div style={{ fontSize: 22, color: C.mute, marginTop: 4, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{senderMeta}</div>
        </div>
        <span style={{
          background: vbg, color: vfg, padding: '8px 22px', borderRadius: 999, fontSize: 22, fontWeight: 700, letterSpacing: '0.02em',
          transform: `scale(${pillScale})`,
          opacity: pillOpacity,
          transformOrigin: 'center',
          display: 'inline-block',
          marginLeft: 14, flexShrink: 0,
        }}>
          {VLAB[verdict]}
        </span>
      </div>
      {/* STACKED: Original above, Draft below */}
      <div style={{ padding: '20px 36px 16px', borderBottom: `1px solid ${C.border}`, background: '#FBFBFA' }}>
        <div style={{ fontSize: 18, color: C.mute, letterSpacing: '0.14em', textTransform: 'uppercase', fontWeight: 700, marginBottom: 10 }}>Original</div>
        <div style={{ fontSize: 22, color: C.ink, lineHeight: 1.5, display: 'flex', flexDirection: 'column', gap: 5 }}>
          {original.map((p, i) => <div key={i}>{p}</div>)}
        </div>
      </div>
      <div style={{ padding: '20px 36px 26px' }}>
        <div style={{ fontSize: 18, color: C.teal, letterSpacing: '0.14em', textTransform: 'uppercase', fontWeight: 700, marginBottom: 10 }}>Replied — Draft</div>
        <div style={{ fontSize: 24, color: C.ink, lineHeight: 1.55, display: 'flex', flexDirection: 'column', gap: 8 }}>
          {draft.map((p, i) => <div key={i}>{p}</div>)}
        </div>
      </div>
    </div>
  );
}

// ═══════════════════════ SCENE 4 — Trust (31-35) ═══════════════════════
function Scene4() {
  const t = useTime();
  if (t < 31 || t > 35.2) return null;
  const lt = t - 31;

  const BADGES = [
    { lines: ['Drafts only.', 'Never sends. Never deletes.'], glyph: 'shield', t0: 0.2 },
    { lines: ['EU-hosted.', 'GDPR compliant.'], img: '../assets/eu-shield.svg', imgHeight: 110, t0: 0.6 },
    { lines: ['Microsoft', 'Verified Publisher.'], img: '../assets/microsoft-partner.png', imgWidth: 200, t0: 1.0 },
  ];

  return (
    <div style={{
      position: 'absolute', inset: 0,
      display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', gap: 40,
      fontFamily: FONT, padding: '0 60px',
    }}>
      {BADGES.map((b, i) => {
        const p = clamp01((lt - b.t0) / 0.55);
        const sc = 0.6 + 0.4 * overshoot(p);
        const op = clamp01((lt - b.t0) / 0.4) * (1 - clamp01((lt - 3.5) / 0.5));
        return (
          <div key={i} style={{
            width: '100%', maxWidth: 880,
            padding: '44px 48px', borderRadius: 28,
            background: '#fff', border: `1px solid ${C.border}`,
            boxShadow: '0 24px 64px rgba(15,20,25,0.12)',
            transform: `scale(${sc})`, opacity: op, textAlign: 'center',
            display: 'flex', flexDirection: 'row', alignItems: 'center', gap: 36,
          }}>
            <div style={{ width: 220, height: 120, flexShrink: 0, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
              {b.img ? (
                <img
                  src={b.img}
                  alt=""
                  style={{
                    height: b.imgHeight ? `${b.imgHeight}px` : 'auto',
                    width: b.imgWidth ? `${b.imgWidth}px` : 'auto',
                    maxHeight: 120, maxWidth: 200,
                    objectFit: 'contain',
                  }}
                />
              ) : (
                <div style={{ width: 110, height: 110, borderRadius: 55, background: 'rgba(31,77,69,0.08)', display: 'flex', alignItems: 'center', justifyContent: 'center', color: C.teal }}>
                  <BadgeGlyph kind={b.glyph} />
                </div>
              )}
            </div>
            <div style={{ flex: 1, textAlign: 'left' }}>
              {b.lines.map((line, j) => (
                <div key={j} style={{ fontSize: j === 0 ? 38 : 28, fontWeight: j === 0 ? 700 : 500, color: j === 0 ? C.ink : C.mute, letterSpacing: '-0.01em', lineHeight: 1.25 }}>
                  {line}
                </div>
              ))}
            </div>
          </div>
        );
      })}
    </div>
  );
}

function BadgeGlyph({ kind }) {
  const stroke = { stroke: 'currentColor', strokeWidth: 2, fill: 'none', strokeLinecap: 'round', strokeLinejoin: 'round' };
  if (kind === 'shield') return (
    <svg width="56" height="56" viewBox="0 0 24 24" {...stroke}>
      <path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z" />
      <path d="m9 12 2 2 4-4" />
    </svg>
  );
  return (
    <svg width="56" height="56" viewBox="0 0 24 24" {...stroke}>
      <path d="M12 2 4 5v6c0 5.5 3.8 10.7 8 11 4.2-.3 8-5.5 8-11V5z" />
      <polyline points="9 12 11 14 15 10" />
    </svg>
  );
}

// ═══════════════════════ SCENE 5 — CTA (35-39) ═══════════════════════
function Scene5() {
  const t = useTime();
  if (t < 35 || t > 39.5) return null;
  const lt = t - 35;

  const wordmarkP = clamp01(lt / 0.5);
  const wordmarkSc = 0.6 + 0.4 * overshoot(wordmarkP);
  const wordmarkOp = clamp01(lt / 0.4);

  const btnStart = 0.5;
  const btnP = clamp01((lt - btnStart) / 0.55);
  const btnSc = 0.6 + 0.4 * overshoot(btnP);
  const btnOp = clamp01((lt - btnStart) / 0.4);

  const kickerStart = 1.2;
  const FULL_K = 'Your deal flow, sorted —\nbefore your first coffee.';
  const len = Math.floor(interpolate([kickerStart, kickerStart + 1.4], [0, FULL_K.length])(lt));
  const kicker = FULL_K.slice(0, len);

  return (
    <div style={{ position: 'absolute', inset: 0, display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', fontFamily: FONT, gap: 56, padding: '0 60px' }}>
      <div style={{ transform: `scale(${wordmarkSc})`, opacity: wordmarkOp, display: 'flex', alignItems: 'center', gap: 24 }}>
        <img src="../assets/replied-glyph.png" alt="" style={{ height: 144, width: 'auto' }} />
        <span style={{ fontSize: 156, fontWeight: 700, color: C.teal, letterSpacing: '-0.03em', lineHeight: 1 }}>Replied</span>
      </div>

      <button style={{
        transform: `scale(${btnSc})`, opacity: btnOp,
        background: C.teal, color: '#fff', border: 'none',
        padding: '32px 64px', borderRadius: 18, fontSize: 40, fontWeight: 600, fontFamily: FONT,
        display: 'inline-flex', alignItems: 'center', gap: 16, cursor: 'pointer',
        boxShadow: '0 16px 32px rgba(31,77,69,0.32)',
      }}>
        Connect Outlook <span aria-hidden style={{ fontSize: 44 }}>→</span>
      </button>

      <div style={{ fontSize: 32, color: C.mute, textAlign: 'center', lineHeight: 1.45, whiteSpace: 'pre-line', minHeight: 140 }}>
        {kicker}
        {lt < kickerStart + 1.5 && <span style={{ display: 'inline-block', width: 3, height: 28, background: C.mute, marginLeft: 2, verticalAlign: '-4px', animation: 'cursor 0.6s steps(2) infinite' }} />}
      </div>
    </div>
  );
}

// ═══════════════════════ Root ═══════════════════════
function DemoRoot() {
  return (
    <Stage width={CW} height={CH} duration={39} background="#FFFFFF" persistKey="replied-demo-mobile">
      <StageBg />
      <Scene1 />
      <Scene2 />
      <Scene3 />
      <Scene4 />
      <Scene5 />
    </Stage>
  );
}

window.DemoRoot = DemoRoot;
