// VSL A — Bloomberg Terminal style.
// Black bg, phosphor green/amber, monospace, scanlines, tickers.

const TERM = {
  bg: '#050706',
  panel: 'rgba(0, 30, 18, 0.4)',
  border: 'rgba(0, 255, 136, 0.2)',
  green: '#00ff88',
  greenDim: '#00b864',
  amber: '#ffb340',
  red: '#ff3b5c',
  white: '#e8f5ec',
  dim: 'rgba(232, 245, 236, 0.5)',
  mono: '"JetBrains Mono", ui-monospace, "SF Mono", Menlo, monospace',
  sans: '"Inter Tight", "Inter", system-ui, sans-serif',
};

// ── helpers ──────────────────────────────────────────────────────────────
const tFade = (t, inDur = 0.3, outDur = 0.3, total) => {
  // returns 0..1 opacity for a sprite of `total` length
  if (t < inDur) return clamp(t / inDur, 0, 1);
  if (t > total - outDur) return clamp((total - t) / outDur, 0, 1);
  return 1;
};

// Type-on text: reveals chars at typing speed
function MonoType({ text, x, y, size = 18, color = TERM.green, charsPerSec = 40, weight = 500, opacity = 1, glow = true }) {
  const { localTime } = useSprite();
  const n = Math.min(text.length, Math.floor(localTime * charsPerSec));
  const cursor = localTime > 0.05 && (Math.floor(localTime * 2) % 2 === 0) ? '▌' : ' ';
  return (
    <div style={{
      position: 'absolute', left: x, top: y,
      fontFamily: TERM.mono, fontSize: size, fontWeight: weight,
      color, opacity,
      letterSpacing: '0.02em', lineHeight: 1.3,
      textShadow: glow ? `0 0 12px ${color}55` : 'none',
      whiteSpace: 'pre',
    }}>
      {text.slice(0, n)}{n < text.length ? cursor : ''}
    </div>
  );
}

// Scanlines overlay for whole stage
function Scanlines() {
  return (
    <div style={{
      position: 'absolute', inset: 0, pointerEvents: 'none',
      background: 'repeating-linear-gradient(to bottom, rgba(0,255,136,0.03) 0 1px, transparent 1px 3px)',
      mixBlendMode: 'screen',
      zIndex: 50,
    }} />
  );
}

// Vignette
function Vignette() {
  return (
    <div style={{
      position: 'absolute', inset: 0, pointerEvents: 'none',
      background: 'radial-gradient(ellipse at center, transparent 50%, rgba(0,0,0,0.7) 100%)',
      zIndex: 49,
    }} />
  );
}

// Top status bar
function StatusBar() {
  const t = useTime();
  const time = `${String(Math.floor(t * 60) % 60).padStart(2, '0')}:${String(Math.floor(t * 100) % 100).padStart(2, '0')}`;
  const blink = Math.floor(t * 2) % 2 === 0;
  return (
    <div style={{
      position: 'absolute', top: 0, left: 0, right: 0, height: 28,
      borderBottom: `1px solid ${TERM.border}`,
      display: 'flex', alignItems: 'center', justifyContent: 'space-between',
      padding: '0 16px',
      fontFamily: TERM.mono, fontSize: 11, color: TERM.dim, letterSpacing: '0.08em',
      background: 'rgba(0, 20, 12, 0.5)',
      zIndex: 30,
    }}>
      <div style={{ display: 'flex', gap: 18 }}>
        <span style={{ color: TERM.green }}>● ECOMMVAULT//TERMINAL</span>
        <span>v3.0.7</span>
        <span>SESSION 0x4F2A</span>
      </div>
      <div style={{ display: 'flex', gap: 18 }}>
        <span>{blink ? '●' : '○'} LIVE</span>
        <span>{time} EST</span>
      </div>
    </div>
  );
}

// Bottom ticker
function Ticker() {
  const t = useTime();
  const items = [
    'LIQUID I.V. +45.0%', 'SOLO STOVE +18.0%', 'HEXCLAD +55.0%',
    'WHOOP +48.0%', 'FEASTABLES +120.0%', 'OURA +40.0%',
    'NATIVE +15.0%', 'MANSCAPED +20.0%', 'BOLL & BRANCH +12.0%',
    'LUME +35.0%',
  ];
  const text = items.join('   ◆   ');
  const offset = (t * 100) % 2000;
  return (
    <div style={{
      position: 'absolute', bottom: 0, left: 0, right: 0, height: 28,
      borderTop: `1px solid ${TERM.border}`,
      overflow: 'hidden',
      background: 'rgba(0, 20, 12, 0.5)',
      display: 'flex', alignItems: 'center',
      fontFamily: TERM.mono, fontSize: 12, color: TERM.amber, letterSpacing: '0.08em',
      zIndex: 30,
    }}>
      <div style={{ whiteSpace: 'nowrap', transform: `translateX(${-offset}px)` }}>
        {text + '   ◆   ' + text}
      </div>
    </div>
  );
}

// ── SCENES ───────────────────────────────────────────────────────────────

// 0-4s: Boot
function SceneBoot() {
  const { localTime } = useSprite();
  const lines = [
    '> ECOMMVAULT TERMINAL // INITIALIZING',
    '> connecting deal-feed.................OK',
    '> verifying revenues (70 brands)......OK',
    '> auth: investor.0x4F2A...............OK',
    '> ready.',
  ];
  return (
    <div style={{ position: 'absolute', left: 80, top: 120, width: 1100 }}>
      {lines.map((line, i) => {
        const start = i * 0.5;
        if (localTime < start) return null;
        const localStart = localTime - start;
        const cps = 60;
        const n = Math.min(line.length, Math.floor(localStart * cps));
        return (
          <div key={i} style={{
            fontFamily: TERM.mono, fontSize: 22, color: i === lines.length - 1 ? TERM.amber : TERM.green,
            letterSpacing: '0.02em', lineHeight: 1.6, fontWeight: 500,
            textShadow: `0 0 14px ${(i === lines.length - 1 ? TERM.amber : TERM.green)}66`,
          }}>{line.slice(0, n)}{n < line.length ? '▌' : ''}</div>
        );
      })}
    </div>
  );
}

// 4-12s: Hook
function SceneHook() {
  const { localTime, duration } = useSprite();
  const numProgress = Easing.easeOutExpo(clamp(localTime / 1.6, 0, 1));
  const num = Math.floor(numProgress * 1247);
  const subOpacity = clamp((localTime - 1.4) / 0.5, 0, 1);
  const punchOpacity = clamp((localTime - 3.6) / 0.4, 0, 1);
  const fade = tFade(localTime, 0.2, 0.6, duration);

  return (
    <div style={{ position: 'absolute', inset: 0, opacity: fade }}>
      <div style={{
        position: 'absolute', left: 80, top: 90,
        fontFamily: TERM.mono, fontSize: 13, color: TERM.greenDim, letterSpacing: '0.18em',
      }}>// QUERY: dealroom.closed_last_quarter</div>

      <div style={{
        position: 'absolute', left: 80, top: 130,
        fontFamily: TERM.sans, fontSize: 280, fontWeight: 700,
        color: TERM.green, letterSpacing: '-0.06em', lineHeight: 0.95,
        fontVariantNumeric: 'tabular-nums',
        textShadow: `0 0 60px ${TERM.green}55`,
      }}>{num.toLocaleString()}</div>

      <div style={{
        position: 'absolute', left: 80, top: 440, opacity: subOpacity,
        fontFamily: TERM.mono, fontSize: 22, color: TERM.white, letterSpacing: '0.16em',
      }}>BRAND DEALS CLOSED · LAST QUARTER</div>

      <div style={{
        position: 'absolute', left: 80, top: 510, opacity: punchOpacity,
        fontFamily: TERM.sans, fontSize: 56, color: TERM.red, fontWeight: 600,
        letterSpacing: '-0.02em',
      }}>You weren't in any of them.</div>
    </div>
  );
}

// 12-22s: Pain 1 — broker fees
function ScenePain1() {
  const { localTime, duration } = useSprite();
  const fade = tFade(localTime, 0.3, 0.5, duration);
  const fees = [
    { label: 'Broker A · "off-market deal"', amt: '$120,000', delay: 0.6 },
    { label: 'Broker B · 12% closing fee',     amt: '$240,000', delay: 1.4 },
    { label: 'Broker C · "exclusivity retainer"', amt: '$87,500',  delay: 2.2 },
    { label: 'Broker D · 8% finders + 4% close', amt: '$1,200,000', delay: 3.0 },
  ];
  return (
    <div style={{ position: 'absolute', inset: 0, opacity: fade }}>
      <div style={{
        position: 'absolute', left: 80, top: 90,
        fontFamily: TERM.mono, fontSize: 13, color: TERM.greenDim, letterSpacing: '0.18em',
      }}>// PROBLEM 01 OF 03</div>
      <div style={{
        position: 'absolute', left: 80, top: 130,
        fontFamily: TERM.sans, fontSize: 84, fontWeight: 600,
        color: TERM.white, letterSpacing: '-0.03em', lineHeight: 1,
      }}>Broker tax.</div>
      <div style={{
        position: 'absolute', left: 80, top: 240,
        fontFamily: TERM.sans, fontSize: 26, color: TERM.dim, fontWeight: 400,
      }}>Three middlemen between you and the deal.</div>

      {fees.map((f, i) => {
        const t0 = f.delay;
        if (localTime < t0) return null;
        const lt = localTime - t0;
        const slideIn = Easing.easeOutCubic(clamp(lt / 0.4, 0, 1));
        // strike-out at lt > 1.5
        const strike = clamp((lt - 1.4) / 0.4, 0, 1);
        return (
          <div key={i} style={{
            position: 'absolute', left: 80, top: 320 + i * 64,
            transform: `translateX(${(1 - slideIn) * -40}px)`,
            opacity: slideIn,
            display: 'flex', alignItems: 'center', gap: 24,
            width: 1120,
          }}>
            <div style={{
              fontFamily: TERM.mono, fontSize: 13, color: TERM.greenDim, width: 32,
            }}>0{i + 1}</div>
            <div style={{
              fontFamily: TERM.sans, fontSize: 24, color: TERM.white, flex: 1,
              position: 'relative',
            }}>
              {f.label}
              <div style={{
                position: 'absolute', left: 0, right: `${(1 - strike) * 100}%`,
                top: '50%', height: 2, background: TERM.red, opacity: strike,
              }}/>
            </div>
            <div style={{
              fontFamily: TERM.mono, fontSize: 28, color: TERM.red, fontWeight: 600,
              fontVariantNumeric: 'tabular-nums',
              transform: `translateY(${strike * -8}px)`,
              opacity: 1 - strike * 0.3,
            }}>−{f.amt}</div>
          </div>
        );
      })}

      {localTime > 4.2 && (
        <div style={{
          position: 'absolute', left: 80, right: 80, bottom: 80,
          paddingTop: 24, borderTop: `1px solid ${TERM.border}`,
          display: 'flex', justifyContent: 'space-between', alignItems: 'baseline',
          opacity: clamp((localTime - 4.2) / 0.4, 0, 1),
        }}>
          <div style={{ fontFamily: TERM.mono, fontSize: 16, color: TERM.dim, letterSpacing: '0.16em' }}>
            TOTAL · LEAKED TO BROKERS
          </div>
          <div style={{
            fontFamily: TERM.sans, fontSize: 64, fontWeight: 600,
            color: TERM.red, fontVariantNumeric: 'tabular-nums', letterSpacing: '-0.02em',
          }}>−$1,647,500</div>
        </div>
      )}
    </div>
  );
}

// 22-32s: Pain 2 — fake numbers
function ScenePain2() {
  const { localTime, duration } = useSprite();
  const fade = tFade(localTime, 0.3, 0.5, duration);
  const stamp = clamp((localTime - 1.8) / 0.2, 0, 1);
  const reveal = clamp((localTime - 2.8) / 0.5, 0, 1);

  return (
    <div style={{ position: 'absolute', inset: 0, opacity: fade }}>
      <div style={{
        position: 'absolute', left: 80, top: 90,
        fontFamily: TERM.mono, fontSize: 13, color: TERM.greenDim, letterSpacing: '0.18em',
      }}>// PROBLEM 02 OF 03</div>
      <div style={{
        position: 'absolute', left: 80, top: 130,
        fontFamily: TERM.sans, fontSize: 84, fontWeight: 600,
        color: TERM.white, letterSpacing: '-0.03em', lineHeight: 1,
      }}>Inflated decks.</div>

      {/* Mock pitch deck card */}
      <div style={{
        position: 'absolute', left: 80, top: 270,
        width: 540, padding: 28,
        background: 'rgba(255,255,255,0.04)', border: `1px solid ${TERM.border}`,
        borderRadius: 4,
      }}>
        <div style={{ fontFamily: TERM.mono, fontSize: 11, color: TERM.dim, letterSpacing: '0.18em', marginBottom: 12 }}>
          BROKER PITCH · CONFIDENTIAL
        </div>
        <div style={{ fontFamily: TERM.sans, fontSize: 28, color: TERM.white, fontWeight: 600, marginBottom: 8 }}>
          DTC Brand · "Project Nimbus"
        </div>
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 16, marginTop: 24 }}>
          <div>
            <div style={{ fontFamily: TERM.mono, fontSize: 11, color: TERM.dim }}>TTM REVENUE</div>
            <div style={{ fontFamily: TERM.sans, fontSize: 36, color: TERM.amber, fontWeight: 600 }}>$14.2M</div>
          </div>
          <div>
            <div style={{ fontFamily: TERM.mono, fontSize: 11, color: TERM.dim }}>GROSS MARGIN</div>
            <div style={{ fontFamily: TERM.sans, fontSize: 36, color: TERM.amber, fontWeight: 600 }}>62%</div>
          </div>
        </div>

        {/* UNVERIFIED stamp */}
        <div style={{
          position: 'absolute', top: 32, right: -20,
          padding: '8px 16px',
          border: `2px solid ${TERM.red}`,
          color: TERM.red,
          fontFamily: TERM.mono, fontSize: 16, fontWeight: 700, letterSpacing: '0.12em',
          transform: `rotate(${-8 + (1 - stamp) * 12}deg) scale(${0.7 + stamp * 0.3})`,
          opacity: stamp,
          textShadow: `0 0 16px ${TERM.red}66`,
          background: 'rgba(255, 59, 92, 0.1)',
        }}>UNVERIFIED</div>
      </div>

      {/* Reveal card */}
      <div style={{
        position: 'absolute', left: 660, top: 270,
        width: 540, padding: 28,
        background: 'rgba(0, 255, 136, 0.04)', border: `1px solid ${TERM.green}`,
        borderRadius: 4,
        opacity: reveal,
        transform: `translateX(${(1 - reveal) * 40}px)`,
      }}>
        <div style={{ fontFamily: TERM.mono, fontSize: 11, color: TERM.green, letterSpacing: '0.18em', marginBottom: 12 }}>
          ECOMMVAULT VERIFIED · STRIPE + SHOPIFY API
        </div>
        <div style={{ fontFamily: TERM.sans, fontSize: 28, color: TERM.white, fontWeight: 600, marginBottom: 8 }}>
          Actual numbers
        </div>
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 16, marginTop: 24 }}>
          <div>
            <div style={{ fontFamily: TERM.mono, fontSize: 11, color: TERM.dim }}>TTM REVENUE</div>
            <div style={{ fontFamily: TERM.sans, fontSize: 36, color: TERM.green, fontWeight: 600 }}>$3.8M</div>
            <div style={{ fontFamily: TERM.mono, fontSize: 11, color: TERM.red }}>−73% vs claim</div>
          </div>
          <div>
            <div style={{ fontFamily: TERM.mono, fontSize: 11, color: TERM.dim }}>GROSS MARGIN</div>
            <div style={{ fontFamily: TERM.sans, fontSize: 36, color: TERM.green, fontWeight: 600 }}>34%</div>
            <div style={{ fontFamily: TERM.mono, fontSize: 11, color: TERM.red }}>−45% vs claim</div>
          </div>
        </div>
      </div>

      {localTime > 5 && (
        <div style={{
          position: 'absolute', left: 80, bottom: 80,
          fontFamily: TERM.sans, fontSize: 32, color: TERM.dim, fontWeight: 400,
          opacity: clamp((localTime - 5) / 0.4, 0, 1),
        }}>
          <span style={{ color: TERM.red, fontWeight: 600 }}>1 in 3</span> broker decks fail verification.
        </div>
      )}
    </div>
  );
}

// 32-40s: Pain 3 — ghosted
function ScenePain3() {
  const { localTime, duration } = useSprite();
  const fade = tFade(localTime, 0.3, 0.5, duration);
  const messages = [
    { who: 'You', t: 'Hey — would love to chat about taking a position. 30 min?', delay: 0.5, accent: TERM.dim },
    { who: 'You', t: 'Following up on this one.',                                      delay: 1.6, accent: TERM.dim },
    { who: 'You', t: 'Just checking in 👋',                                            delay: 2.5, accent: TERM.dim },
  ];

  const ghosted = clamp((localTime - 4.0) / 0.4, 0, 1);

  return (
    <div style={{ position: 'absolute', inset: 0, opacity: fade }}>
      <div style={{
        position: 'absolute', left: 80, top: 90,
        fontFamily: TERM.mono, fontSize: 13, color: TERM.greenDim, letterSpacing: '0.18em',
      }}>// PROBLEM 03 OF 03</div>
      <div style={{
        position: 'absolute', left: 80, top: 130,
        fontFamily: TERM.sans, fontSize: 84, fontWeight: 600,
        color: TERM.white, letterSpacing: '-0.03em', lineHeight: 1,
      }}>Founder ghost.</div>

      {/* DM thread */}
      <div style={{
        position: 'absolute', left: 80, top: 260,
        width: 700, padding: 24,
        background: 'rgba(255,255,255,0.03)', border: `1px solid ${TERM.border}`,
        borderRadius: 4,
      }}>
        <div style={{
          fontFamily: TERM.mono, fontSize: 11, color: TERM.dim, letterSpacing: '0.18em',
          paddingBottom: 14, borderBottom: `1px solid ${TERM.border}`, marginBottom: 18,
          display: 'flex', justifyContent: 'space-between',
        }}>
          <span>DM · @founder_kitchenware</span>
          <span>READ 47d AGO</span>
        </div>

        {messages.map((m, i) => {
          if (localTime < m.delay) return null;
          const lt = localTime - m.delay;
          const slide = Easing.easeOutCubic(clamp(lt / 0.3, 0, 1));
          return (
            <div key={i} style={{
              opacity: slide, transform: `translateY(${(1 - slide) * 8}px)`,
              marginBottom: 14,
            }}>
              <div style={{
                fontFamily: TERM.mono, fontSize: 11, color: TERM.dim, marginBottom: 4,
              }}>{m.who} · {String(i * 14 + 7).padStart(2, '0')}d ago</div>
              <div style={{
                fontFamily: TERM.sans, fontSize: 20, color: TERM.white,
                padding: '10px 14px',
                background: 'rgba(0, 255, 136, 0.06)',
                borderLeft: `2px solid ${TERM.greenDim}`,
                borderRadius: 4,
              }}>{m.t}</div>
            </div>
          );
        })}

        {ghosted > 0 && (
          <div style={{
            marginTop: 16,
            fontFamily: TERM.mono, fontSize: 14, color: TERM.red,
            letterSpacing: '0.16em', opacity: ghosted,
          }}>
            ▒▒▒ NO RESPONSE ▒▒▒
          </div>
        )}
      </div>

      <div style={{
        position: 'absolute', right: 80, top: 320, width: 360,
        opacity: clamp((localTime - 1.8) / 0.5, 0, 1),
      }}>
        <div style={{ fontFamily: TERM.mono, fontSize: 13, color: TERM.greenDim, letterSpacing: '0.16em', marginBottom: 12 }}>
          AVG TIME TO FIRST CALL
        </div>
        <div style={{ fontFamily: TERM.sans, fontSize: 100, color: TERM.amber, fontWeight: 600, lineHeight: 1, fontVariantNumeric: 'tabular-nums' }}>
          47<span style={{ fontSize: 48, color: TERM.dim }}> days</span>
        </div>
        <div style={{ fontFamily: TERM.sans, fontSize: 18, color: TERM.dim, marginTop: 16 }}>
          for cold-DM'd founders.
        </div>
        <div style={{ fontFamily: TERM.sans, fontSize: 18, color: TERM.green, marginTop: 6, fontWeight: 600 }}>
          ECommVault: 4 hours.
        </div>
      </div>
    </div>
  );
}

// 40-48s: Solution reveal — full screen logo
function SceneReveal() {
  const { localTime, duration } = useSprite();
  const fade = tFade(localTime, 0.3, 0.4, duration);
  const ringScale = Easing.easeOutBack(clamp(localTime / 0.8, 0, 1));
  const sub1 = clamp((localTime - 1.4) / 0.5, 0, 1);
  const sub2 = clamp((localTime - 2.6) / 0.5, 0, 1);
  const sub3 = clamp((localTime - 3.8) / 0.5, 0, 1);

  return (
    <div style={{ position: 'absolute', inset: 0, opacity: fade,
      display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center',
    }}>
      <div style={{
        fontFamily: TERM.sans, fontSize: 32, color: TERM.green,
        transform: `scale(${ringScale})`, letterSpacing: '0.04em',
        textShadow: `0 0 30px ${TERM.green}88`, marginBottom: 12,
      }}>✦</div>
      <div style={{
        fontFamily: TERM.sans, fontSize: 140, fontWeight: 700,
        color: TERM.white, letterSpacing: '-0.04em', lineHeight: 1,
        textShadow: `0 0 60px ${TERM.green}33`,
      }}>ECOMMVAULT</div>
      <div style={{
        fontFamily: TERM.mono, fontSize: 18, color: TERM.green, letterSpacing: '0.32em',
        marginTop: 24, opacity: sub1,
      }}>THE&nbsp;&nbsp;DEAL&nbsp;&nbsp;TERMINAL</div>
      <div style={{
        fontFamily: TERM.sans, fontSize: 28, color: TERM.dim,
        marginTop: 60, opacity: sub2, fontWeight: 400,
      }}>Track the top 1% of brands.</div>
      <div style={{
        fontFamily: TERM.sans, fontSize: 28, color: TERM.dim,
        marginTop: 6, opacity: sub3, fontWeight: 400,
      }}>See their numbers. Close the deal.</div>
    </div>
  );
}

// 48-60s: Live dealroom feed
function SceneDealroom() {
  const { localTime, duration } = useSprite();
  const fade = tFade(localTime, 0.3, 0.5, duration);
  const brands = [
    { sym: 'LIQ', name: 'Liquid I.V.',    cat: 'Health',    rev: '$35.0M/mo', g: '+45.0%' },
    { sym: 'SOL', name: 'Solo Stove',     cat: 'Outdoor',   rev: '$30.0M/mo', g: '+18.0%' },
    { sym: 'MAN', name: 'Manscaped',      cat: 'Personal',  rev: '$25.0M/mo', g: '+20.0%' },
    { sym: 'HEX', name: 'Hexclad',        cat: 'Kitchen',   rev: '$14.0M/mo', g: '+55.0%' },
    { sym: 'WHO', name: 'Whoop',          cat: 'Wearable',  rev: '$12.0M/mo', g: '+48.0%' },
    { sym: 'FEA', name: 'Feastables',     cat: 'Snacks',    rev: '$10.0M/mo', g: '+120.0%' },
    { sym: 'OUR', name: 'Oura',           cat: 'Wearable',  rev: '$10.0M/mo', g: '+40.0%' },
    { sym: 'LUM', name: 'Lume',           cat: 'Personal',  rev: '$12.0M/mo', g: '+35.0%' },
    { sym: 'NAT', name: 'Native',         cat: 'Personal',  rev: '$15.0M/mo', g: '+15.0%' },
  ];

  return (
    <div style={{ position: 'absolute', inset: 0, opacity: fade }}>
      <div style={{
        position: 'absolute', left: 80, top: 90,
        fontFamily: TERM.mono, fontSize: 13, color: TERM.greenDim, letterSpacing: '0.18em',
      }}>// LIVE DEALROOM · 70 BRANDS · STREAMING</div>
      <div style={{
        position: 'absolute', left: 80, top: 130,
        fontFamily: TERM.sans, fontSize: 60, fontWeight: 600,
        color: TERM.white, letterSpacing: '-0.03em', lineHeight: 1,
      }}>Verified revenue. <span style={{ color: TERM.green }}>Live feed.</span></div>

      {/* Header row */}
      <div style={{
        position: 'absolute', left: 80, right: 80, top: 240,
        display: 'grid', gridTemplateColumns: '60px 1fr 120px 160px 100px 120px',
        gap: 16, padding: '8px 0', borderBottom: `1px solid ${TERM.border}`,
        fontFamily: TERM.mono, fontSize: 11, color: TERM.dim, letterSpacing: '0.16em',
      }}>
        <div>SYM</div><div>BRAND</div><div>CAT</div><div>MRR</div><div>GROWTH</div><div>STATUS</div>
      </div>

      {brands.map((b, i) => {
        const t0 = 0.4 + i * 0.18;
        if (localTime < t0) return null;
        const lt = localTime - t0;
        const slide = Easing.easeOutCubic(clamp(lt / 0.3, 0, 1));
        const flash = lt < 0.4 ? 1 - lt / 0.4 : 0;
        return (
          <div key={i} style={{
            position: 'absolute', left: 80, right: 80, top: 290 + i * 40,
            display: 'grid', gridTemplateColumns: '60px 1fr 120px 160px 100px 120px',
            gap: 16, padding: '6px 0', alignItems: 'center',
            opacity: slide,
            background: `rgba(0, 255, 136, ${flash * 0.08})`,
            transform: `translateX(${(1 - slide) * 12}px)`,
            fontFamily: TERM.mono, fontSize: 18,
          }}>
            <div style={{ color: TERM.amber, fontWeight: 600 }}>{b.sym}</div>
            <div style={{ color: TERM.white, fontFamily: TERM.sans, fontSize: 20, fontWeight: 500 }}>{b.name}</div>
            <div style={{ color: TERM.dim, fontSize: 14 }}>{b.cat}</div>
            <div style={{ color: TERM.white, fontVariantNumeric: 'tabular-nums', fontWeight: 500 }}>{b.rev}</div>
            <div style={{ color: TERM.green, fontVariantNumeric: 'tabular-nums', fontWeight: 600 }}>{b.g}</div>
            <div style={{
              color: TERM.green, fontSize: 11, letterSpacing: '0.12em',
              padding: '2px 8px', border: `1px solid ${TERM.green}`,
              display: 'inline-block', justifySelf: 'start',
            }}>● VERIFIED</div>
          </div>
        );
      })}
    </div>
  );
}

// 60-68s: Stats
function SceneStats() {
  const { localTime, duration } = useSprite();
  const fade = tFade(localTime, 0.3, 0.5, duration);
  const stats = [
    { num: 4507, prefix: '$', suffix: 'M', label: 'VERIFIED REVENUE TRACKED', color: TERM.green },
    { num: 70,   prefix: '',  suffix: '',  label: 'TOP-1% BRANDS',            color: TERM.amber },
    { num: 3200, prefix: '',  suffix: '',  label: 'ACTIVE DEALMAKERS',        color: TERM.green },
  ];

  return (
    <div style={{ position: 'absolute', inset: 0, opacity: fade,
      display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center',
    }}>
      <div style={{ fontFamily: TERM.mono, fontSize: 13, color: TERM.greenDim, letterSpacing: '0.18em', marginBottom: 24 }}>
        // SYSTEM CHECK
      </div>
      <div style={{ display: 'flex', gap: 100 }}>
        {stats.map((s, i) => {
          const t0 = 0.4 + i * 0.5;
          const counter = Easing.easeOutExpo(clamp((localTime - t0) / 1.6, 0, 1));
          const n = Math.floor(counter * s.num);
          const labelOp = clamp((localTime - t0 - 1.4) / 0.4, 0, 1);
          return (
            <div key={i} style={{ textAlign: 'center', minWidth: 280 }}>
              <div style={{
                fontFamily: TERM.sans, fontSize: 140, fontWeight: 700,
                color: s.color, letterSpacing: '-0.04em', lineHeight: 1,
                fontVariantNumeric: 'tabular-nums',
                textShadow: `0 0 40px ${s.color}55`,
              }}>{s.prefix}{s.num >= 1000 ? n.toLocaleString() : n}{s.suffix}</div>
              <div style={{
                fontFamily: TERM.mono, fontSize: 14, color: TERM.dim,
                letterSpacing: '0.18em', marginTop: 16, opacity: labelOp,
              }}>{s.label}</div>
            </div>
          );
        })}
      </div>
    </div>
  );
}

// 68-78s: Tiers
function SceneTiers() {
  const { localTime, duration } = useSprite();
  const fade = tFade(localTime, 0.3, 0.4, duration);
  const tiers = [
    { name: 'BASIC',  price: '$99',  cap: 'Source deals · talk to founders', features: ['Dealroom access', 'Verified financials', 'Founder DMs'] },
    { name: 'PRO',    price: '$199', cap: 'For active investors', features: ['Everything in Basic', 'Early dealroom', 'AI deal matching'], featured: true },
    { name: 'ELITE',  price: '$499', cap: 'Full-service close',   features: ['Everything in Pro', 'Account manager', 'Escrow + Legal'] },
  ];

  return (
    <div style={{ position: 'absolute', inset: 0, opacity: fade }}>
      <div style={{
        position: 'absolute', left: 80, top: 90,
        fontFamily: TERM.mono, fontSize: 13, color: TERM.greenDim, letterSpacing: '0.18em',
      }}>// ACCESS · /MO · CANCEL ANY TIME</div>
      <div style={{
        position: 'absolute', left: 80, top: 130,
        fontFamily: TERM.sans, fontSize: 60, fontWeight: 600,
        color: TERM.white, letterSpacing: '-0.03em',
      }}>Pick your seat.</div>

      <div style={{
        position: 'absolute', left: 80, right: 80, top: 250,
        display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', gap: 24,
      }}>
        {tiers.map((t, i) => {
          const t0 = 0.4 + i * 0.3;
          const slide = Easing.easeOutCubic(clamp((localTime - t0) / 0.5, 0, 1));
          const accent = t.featured ? TERM.amber : TERM.green;
          return (
            <div key={i} style={{
              padding: 28,
              background: t.featured ? 'rgba(255, 179, 64, 0.05)' : 'rgba(0, 255, 136, 0.03)',
              border: `1px solid ${t.featured ? TERM.amber : TERM.border}`,
              borderRadius: 4,
              opacity: slide, transform: `translateY(${(1 - slide) * 24}px)`,
              position: 'relative',
            }}>
              {t.featured && (
                <div style={{
                  position: 'absolute', top: -10, left: 24,
                  padding: '2px 10px', background: TERM.amber, color: TERM.bg,
                  fontFamily: TERM.mono, fontSize: 10, letterSpacing: '0.18em', fontWeight: 700,
                }}>MOST CHOSEN</div>
              )}
              <div style={{ fontFamily: TERM.mono, fontSize: 12, color: accent, letterSpacing: '0.2em', marginBottom: 18 }}>
                {t.name}
              </div>
              <div style={{
                fontFamily: TERM.sans, fontSize: 80, fontWeight: 700,
                color: TERM.white, letterSpacing: '-0.04em', lineHeight: 1,
              }}>{t.price}<span style={{ fontSize: 22, color: TERM.dim, fontWeight: 400 }}>/mo</span></div>
              <div style={{ fontFamily: TERM.sans, fontSize: 16, color: TERM.dim, marginTop: 8, marginBottom: 24 }}>
                {t.cap}
              </div>
              {t.features.map((f, j) => (
                <div key={j} style={{
                  fontFamily: TERM.mono, fontSize: 13, color: TERM.white,
                  padding: '6px 0', display: 'flex', gap: 10,
                  borderTop: j === 0 ? `1px solid ${TERM.border}` : 'none',
                  paddingTop: j === 0 ? 14 : 6,
                }}>
                  <span style={{ color: accent }}>+</span> {f}
                </div>
              ))}
            </div>
          );
        })}
      </div>
    </div>
  );
}

// 78-86s: CTA
function SceneCTA() {
  const { localTime, duration } = useSprite();
  const fade = tFade(localTime, 0.4, 0.4, duration);
  const t1 = clamp(localTime / 0.6, 0, 1);
  const t2 = clamp((localTime - 1.0) / 0.6, 0, 1);
  const t3 = clamp((localTime - 2.0) / 0.6, 0, 1);
  const blink = Math.floor(localTime * 1.5) % 2 === 0;

  return (
    <div style={{ position: 'absolute', inset: 0, opacity: fade,
      display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center',
    }}>
      <div style={{
        fontFamily: TERM.sans, fontSize: 32, color: TERM.dim, opacity: t1,
        letterSpacing: '-0.01em', marginBottom: 8, fontWeight: 400,
      }}>Track the top 1% of brands.</div>
      <div style={{
        fontFamily: TERM.sans, fontSize: 32, color: TERM.dim, opacity: t1,
        letterSpacing: '-0.01em', fontWeight: 400,
      }}>See their numbers.</div>
      <div style={{
        fontFamily: TERM.sans, fontSize: 120, color: TERM.green, fontWeight: 700,
        letterSpacing: '-0.04em', marginTop: 24, opacity: t2,
        textShadow: `0 0 60px ${TERM.green}66`, lineHeight: 1,
      }}>Close the deal.</div>

      <div style={{
        marginTop: 80, opacity: t3,
        padding: '20px 40px', border: `1.5px solid ${TERM.green}`,
        background: 'rgba(0,255,136,0.05)',
        display: 'flex', alignItems: 'center', gap: 14,
      }}>
        <span style={{ color: TERM.green, fontFamily: TERM.mono, fontSize: 18, opacity: blink ? 1 : 0.3 }}>▌</span>
        <span style={{ fontFamily: TERM.mono, fontSize: 24, color: TERM.white, letterSpacing: '0.06em' }}>
          joinecommvault.com
        </span>
      </div>
      <div style={{
        marginTop: 24, opacity: t3,
        fontFamily: TERM.mono, fontSize: 13, color: TERM.dim, letterSpacing: '0.18em',
      }}>7-DAY FREE TRIAL · NO CARD</div>
    </div>
  );
}

// ── Sound cues ────────────────────────────────────────────────────────
// Watches the timeline. On each frame, fires any cues whose `t` is between
// the last fire time and the current playhead. Backward seeks (loop) reset.
function SoundCues() {
  const t = useTime();
  const lastRef = React.useRef(-1);

  const cues = React.useMemo(() => [
    { t: 0.05, fn: () => window.VSLAudio?.sfx('thud') },
    { t: 0.5,  fn: () => window.VSLAudio?.sfx('beep') },
    { t: 1.0,  fn: () => window.VSLAudio?.sfx('beep') },
    { t: 1.5,  fn: () => window.VSLAudio?.sfx('beep') },
    { t: 2.2,  fn: () => window.VSLAudio?.sfx('kaching') },
    { t: 2.5,  fn: () => window.VSLAudio?.speak('Initializing E-Comm-Vault terminal.') },

    { t: 4.0,  fn: () => { window.VSLAudio?.sfx('whoosh');
      window.VSLAudio?.speak("Last quarter, twelve hundred and forty-seven Shopify brand deals closed. You weren't in any of them. Here's why."); } },

    { t: 12.0, fn: () => { window.VSLAudio?.sfx('thud');
      window.VSLAudio?.speak("Three middlemen between you and the deal. Twelve percent finder's fees. Exclusivity retainers. Closing fees. One point six million dollars — gone, before a single wire."); } },

    { t: 22.0, fn: () => { window.VSLAudio?.sfx('glitch');
      window.VSLAudio?.speak("Then the numbers themselves. One in three broker decks fail verification. The deck says fourteen million. The Stripe API says three point eight."); } },

    { t: 32.0, fn: () => { window.VSLAudio?.sfx('thud');
      window.VSLAudio?.speak("And when you cold-D-M the founder? Forty-seven days to first call. If they reply at all."); } },

    { t: 40.0, fn: () => { window.VSLAudio?.sfx('whoosh');
      window.VSLAudio?.speak("There is a tool the top one percent of operators stopped paying broker tax with this year. E-Comm-Vault. The deal terminal."); } },

    { t: 48.0, fn: () => { window.VSLAudio?.sfx('beep');
      window.VSLAudio?.speak("Seventy verified Shopify brands. Live revenue, straight from Stripe and Shopify. No founder vibes. No spreadsheet roulette."); } },

    { t: 60.0, fn: () => { window.VSLAudio?.sfx('kaching');
      window.VSLAudio?.speak("Four point five billion dollars in verified revenue tracked. Seventy top one percent brands. Three thousand two hundred active dealmakers."); } },

    { t: 68.0, fn: () => { window.VSLAudio?.sfx('beep');
      window.VSLAudio?.speak("Three seats. Basic at ninety-nine. Pro at one ninety-nine. Elite at four ninety-nine. Cancel any time."); } },

    { t: 78.0, fn: () => { window.VSLAudio?.sfx('whoosh');
      window.VSLAudio?.speak("Track the top one percent of brands. See their numbers. Close the deal. Visit join e-comm-vault dot com."); } },
  ], []);

  React.useEffect(() => {
    if (t < lastRef.current - 0.5) {
      window.VSLAudio?.cancelSpeech();
      lastRef.current = -0.001;
    }
    for (const cue of cues) {
      if (cue.t > lastRef.current && cue.t <= t) {
        cue.fn();
        lastRef.current = cue.t;
      }
    }
  }, [t, cues]);

  return null;
}

// ── ROOT ─────────────────────────────────────────────────────────────────
function VSLTerminal() {
  return (
    <Stage width={1280} height={720} duration={86} background={TERM.bg}
      persistKey="vsl-terminal" globalKeys={false} loop={true}>
      <SoundCues />
      <StatusBar />
      <Sprite start={0}    end={4}>  <SceneBoot /></Sprite>
      <Sprite start={4}    end={12}> <SceneHook /></Sprite>
      <Sprite start={12}   end={22}> <ScenePain1 /></Sprite>
      <Sprite start={22}   end={32}> <ScenePain2 /></Sprite>
      <Sprite start={32}   end={40}> <ScenePain3 /></Sprite>
      <Sprite start={40}   end={48}> <SceneReveal /></Sprite>
      <Sprite start={48}   end={60}> <SceneDealroom /></Sprite>
      <Sprite start={60}   end={68}> <SceneStats /></Sprite>
      <Sprite start={68}   end={78}> <SceneTiers /></Sprite>
      <Sprite start={78}   end={86}> <SceneCTA /></Sprite>
      <Ticker />
      <Scanlines />
      <Vignette />
    </Stage>
  );
}

window.VSLTerminal = VSLTerminal;
