// OptimaFlo 60s explainer — scenes
// Timeline:
//  0–6   Scene 1: Tool chaos (the problem)
//  6–12  Scene 2: Cost pain (numbers)
// 12–18  Scene 3: OptimaFlo intro
// 18–30  Scene 4: Prompt → Pipeline materializes (Ingest, Warehouse, Transform, Orchestrate, BI)
// 30–38  Scene 5: Dashboard reveal
// 38–46  Scene 6: BYOC + Human-in-the-loop
// 46–54  Scene 7: Savings (cost + time)
// 54–60  Scene 8: CTA

// ── Design tokens (mirrors design system) ─────────────────────────────────
const ofTokens = {
  cream: '#FEFCF9',
  card: '#F5F0EB',
  line: '#E7DFD3',
  ink900: '#1A1614',
  ink800: '#2C2825',
  ink700: '#44403C',
  ink400: '#B8AFA6',
  amber500: '#F59E0B',
  amber600: '#D97706',
  amber700: '#92400E',
  bronze: '#B97A3D',
  silver: '#9CA09E',
  gold: '#E1A11A',
  fHead: '"Plus Jakarta Sans", "Cal Sans", Inter, system-ui, sans-serif',
  fCal: '"Cal Sans", "Plus Jakarta Sans", Inter, system-ui, sans-serif',
  fBody: 'Inter, system-ui, sans-serif',
  fMono: '"JetBrains Mono", ui-monospace, SFMono-Regular, monospace'
};

// ── Inline OptimaFlo logomark — uses the brand PNG (transparent bg) ───────
function OFLogo({ size = 110, showWordmark = true, src = 'assets/logo.png' }) {
  const r = size;
  return (
    <div style={{ display: 'inline-flex', alignItems: 'center', gap: r * 0.24 }}>
      <img src={src} alt="OptimaFlo" style={{
        width: r, height: r,
        display: 'block',
        flexShrink: 0
      }} />
      {showWordmark &&
      <span style={{
        fontFamily: ofTokens.fHead,
        fontWeight: 700,
        fontSize: r * 0.62,
        letterSpacing: '-0.035em',
        color: ofTokens.ink900,
        lineHeight: 1,
        whiteSpace: 'nowrap'
      }}>
          Optima<span style={{ color: ofTokens.ink900 }}>Flo</span>
        </span>
      }
    </div>);

}

// ── Background: warm cream with subtle radial dot pattern ─────────────────
function StageBg({ mask = 'radial-gradient(circle at 50% 40%, black, transparent 80%)' }) {
  return (
    <div style={{
      position: 'absolute', inset: 0,
      backgroundColor: ofTokens.cream
    }}>
      <div style={{
        position: 'absolute', inset: 0,
        backgroundImage: `radial-gradient(${ofTokens.line} 1.5px, transparent 1.5px)`,
        backgroundSize: '24px 24px',
        WebkitMaskImage: mask,
        maskImage: mask,
        opacity: 0.9
      }} data-comment-anchor="4180fee9f9-div-67-7" />
    </div>);

}

// ── Eyebrow label (mono caps) ─────────────────────────────────────────────
function Eyebrow({ children, color = ofTokens.amber600, x, y, align = 'left' }) {
  const { localTime } = useSprite();
  const opacity = clamp(localTime / 0.4, 0, 1);
  const tx = align === 'center' ? '-50%' : '0';
  return (
    <div style={{
      position: 'absolute', left: x, top: y,
      transform: `translate(${tx}, 0)`,
      fontFamily: ofTokens.fMono,
      fontSize: 18,
      fontWeight: 500,
      letterSpacing: '0.18em',
      textTransform: 'uppercase',
      color,
      opacity
    }}>{children}</div>);

}

// ── ToolChip (tool-being-replaced) — text styled as a logo chip ───────────
function ToolChip({ label, x, y, rotate = 0, scale = 1, glow = false, color = ofTokens.ink800 }) {
  return (
    <div style={{
      position: 'absolute', left: x, top: y,
      transform: `translate(-50%, -50%) rotate(${rotate}deg) scale(${scale})`,
      transformOrigin: 'center',
      background: ofTokens.cream,
      border: `1px solid ${ofTokens.line}`,
      boxShadow: glow ?
      `0 12px 28px -10px rgba(0,0,0,0.18), 0 0 0 4px rgba(245,158,11,0.10)` :
      `0 6px 14px -6px rgba(0,0,0,0.10)`,
      borderRadius: 18,
      padding: '14px 22px',
      fontFamily: ofTokens.fHead,
      fontWeight: 600,
      fontSize: 26,
      letterSpacing: '-0.02em',
      color,
      whiteSpace: 'nowrap',
      display: 'inline-flex',
      alignItems: 'center',
      gap: 12
    }}>
      <span style={{
        width: 12, height: 12, borderRadius: 4, background: color, opacity: 0.85
      }} />
      {label}
    </div>);

}

// ── Cross-out line over a chip ────────────────────────────────────────────
function CrossOut({ x, y, w = 220, progress = 0, angle = -8 }) {
  return (
    <div style={{
      position: 'absolute', left: x, top: y,
      transform: `translate(-50%, -50%) rotate(${angle}deg)`,
      width: w * progress, height: 3,
      background: ofTokens.amber600,
      borderRadius: 2,
      transformOrigin: 'left center',
      transition: 'none'
    }} />);

}

// ───────────────────────────────────────────────────────────────────────────
// SCENE 1 — The current stack: six categories, six bills. 0–6s
// ───────────────────────────────────────────────────────────────────────────
function Scene1Chaos() {
  const { localTime } = useSprite();

  // Six tool cards laid out in a 3x2 grid — each shows category, vendor, cost
  const tools = [
    { cat: 'Ingestion',    name: 'Fivetran',     cost: '$5K / mo' },
    { cat: 'Warehouse',    name: 'Snowflake',    cost: '$15K / mo' },
    { cat: 'Transform',    name: 'dbt Cloud',    cost: '$3K / mo' },
    { cat: 'Orchestrate',  name: 'Airflow',      cost: 'self-host' },
    { cat: 'BI',           name: 'Tableau',      cost: '$2K / mo' },
    { cat: 'Quality',      name: 'Monte Carlo',  cost: '$3K / mo' },
  ];

  // Scene fades in/out at edges
  const sceneFade = localTime < 0.4
    ? Easing.easeOutCubic(localTime / 0.4)
    : localTime > 5.4
      ? 1 - Easing.easeInCubic((localTime - 5.4) / 0.6)
      : 1;

  // Headline at 0.0s
  const headT = clamp(localTime / 0.6, 0, 1);

  // Each card pops in with stagger
  const cardState = (i) => {
    const start = 0.5 + i * 0.18;
    const t = clamp((localTime - start) / 0.55, 0, 1);
    const op = clamp((localTime - start) / 0.35, 0, 1);
    const eased = Easing.easeOutCubic(t);
    return {
      scale: 0.94 + eased * 0.06,
      y: (1 - eased) * 24,
      op,
    };
  };

  // Bottom callout at 3.6s
  const calloutT = clamp((localTime - 3.6) / 0.55, 0, 1);
  const calloutOp = Easing.easeOutCubic(calloutT);

  // Grid layout: 3 columns, 2 rows — evenly spaced (h & v gaps equal)
  const colW = 480;
  const colGap = 48;
  const rowH = 232;
  const rowGap = 48;
  const gridLeft = (1920 - (colW * 3 + colGap * 2)) / 2;
  const rowTop = 380;
  const cardW = colW;
  const cardH = rowH;

  return (
    <div style={{ position: 'absolute', inset: 0, opacity: sceneFade }}>
      <StageBg/>

      {/* Headline */}
      <div style={{
        position: 'absolute',
        left: '50%', top: 110,
        transform: `translate(-50%, ${(1 - headT) * 16}px)`,
        opacity: headT,
        textAlign: 'center',
        width: '90%',
      }}>
        <div style={{
          fontFamily: ofTokens.fMono,
          fontSize: 18,
          letterSpacing: '0.18em',
          textTransform: 'uppercase',
          color: ofTokens.amber600,
          marginBottom: 16,
        }}>The modern data stack</div>
        <div style={{
          fontFamily: ofTokens.fCal,
          fontWeight: 700,
          fontSize: 92,
          lineHeight: 1.0,
          letterSpacing: '-0.035em',
          color: ofTokens.ink900,
          whiteSpace: 'nowrap',
        }}>Six categories. <span style={{ color: ofTokens.amber600 }}>Six bills.</span></div>
      </div>

      {/* Cards */}
      {tools.map((t, i) => {
        const col = i % 3;
        const row = Math.floor(i / 3);
        const x = gridLeft + col * (colW + colGap);
        const y = rowTop + row * (rowH + rowGap);
        const s = cardState(i);
        return (
          <div key={t.name} style={{
            position: 'absolute',
            left: x, top: y + s.y,
            width: cardW, height: cardH,
            opacity: s.op,
            transform: `scale(${s.scale})`,
            transformOrigin: 'center',
            background: ofTokens.cream,
            border: `1px solid ${ofTokens.line}`,
            borderRadius: 22,
            padding: '24px 28px',
            boxShadow: '0 10px 26px -12px rgba(0,0,0,0.10)',
            display: 'flex', flexDirection: 'column', gap: 6,
          }}>
            {/* Category */}
            <div style={{
              fontFamily: ofTokens.fMono, fontSize: 13,
              letterSpacing: '0.16em', textTransform: 'uppercase',
              color: ofTokens.ink400, marginBottom: 4,
            }}>{t.cat}</div>
            {/* Vendor */}
            <div style={{
              fontFamily: ofTokens.fHead, fontWeight: 700,
              fontSize: 48, letterSpacing: '-0.03em',
              color: ofTokens.ink900, lineHeight: 1.0,
            }}>{t.name}</div>
            {/* Cost */}
            <div style={{
              marginTop: 'auto',
              fontFamily: ofTokens.fMono, fontSize: 22,
              fontWeight: 600,
              color: ofTokens.amber700,
              letterSpacing: '-0.005em',
            }}>{t.cost}</div>
          </div>
        );
      })}

      {/* Bottom callout: + data team */}
      <div style={{
        position: 'absolute',
        left: '50%', top: 960,
        transform: `translate(-50%, ${(1 - calloutOp) * 12}px)`,
        opacity: calloutOp,
        textAlign: 'center',
        whiteSpace: 'nowrap',
      }}>
        <span style={{
          display: 'inline-flex', alignItems: 'baseline', gap: 14,
          fontFamily: ofTokens.fHead,
          fontWeight: 600,
          fontSize: 32,
          color: ofTokens.ink700,
          letterSpacing: '-0.015em',
        }}>
          <span style={{ color: ofTokens.amber600, fontWeight: 700, fontSize: 36 }}>+</span>
          A 3-person data team — <span style={{ color: ofTokens.ink900, fontWeight: 700 }}>4–6 months</span> to hire.
        </span>
      </div>
    </div>
  );
}

// ───────────────────────────────────────────────────────────────────────────
// SCENE 2 — Cost pain. 6–12s
// ───────────────────────────────────────────────────────────────────────────
function Scene2Cost() {
  const { localTime } = useSprite();
  const sceneFade = localTime < 0.5 ?
  Easing.easeOutCubic(localTime / 0.5) :
  localTime > 5.4 ?
  1 - Easing.easeInCubic((localTime - 5.4) / 0.6) :
  1;

  // Big number counts up to 100
  const numT = clamp((localTime - 0.5) / 2.2, 0, 1);
  const eased = Easing.easeOutQuart(numT);
  const value = Math.round(eased * 100);

  // Big number scales/settles
  const numScale = interpolate([0, 1, 5, 6], [0.85, 1.0, 1.0, 0.96], Easing.easeOutCubic)(localTime);

  // Three sub-bullets stagger in
  const bullets = [
  { label: 'PER MONTH', value: '$25K–$100K', sub: 'Across tools + headcount' },
  { label: 'TO HIRE A TEAM', value: '4–6 mo', sub: 'Data eng, analytics eng, analyst' },
  { label: 'VENDORS TO MANAGE', value: '6+', sub: 'Six contracts. Six on-call rotations.' }];


  return (
    <div style={{ position: 'absolute', inset: 0, opacity: sceneFade }}>
      <StageBg />

      {/* Eyebrow */}
      <Sprite start={0} end={6}>
        <Eyebrow x="50%" y={150} align="center">The Cost</Eyebrow>
      </Sprite>

      {/* Big "$X00K / month" */}
      <div style={{
        position: 'absolute',
        left: '50%', top: 240,
        transform: `translate(-50%, 0) scale(${numScale})`,
        textAlign: 'center',
        transformOrigin: 'top center'
      }}>
        <div style={{
          fontFamily: ofTokens.fCal,
          fontWeight: 700,
          fontSize: 260,
          lineHeight: 0.9,
          letterSpacing: '-0.05em',
          color: ofTokens.ink900,
          display: 'inline-flex',
          alignItems: 'baseline',
          gap: 8
        }}>
          <span style={{ color: ofTokens.amber600, fontSize: 200 }}>$</span>
          <span style={{ fontVariantNumeric: 'tabular-nums' }}>{value}</span>
          <span style={{ color: ofTokens.amber600, fontSize: 140 }}>K</span>
        </div>
        <div style={{
          fontFamily: ofTokens.fHead,
          fontSize: 36,
          fontWeight: 500,
          color: ofTokens.ink700,
          letterSpacing: '-0.02em',
          marginTop: 14
        }}>per month, to build the stack from scratch</div>
      </div>

      {/* Sub bullets */}
      <div style={{
        position: 'absolute',
        left: '50%', top: 780,
        transform: 'translate(-50%, 0)',
        display: 'grid',
        gridTemplateColumns: 'repeat(3, 1fr)',
        gap: 24,
        width: 1600
      }}>
        {bullets.map((b, i) => {
          const t = clamp((localTime - 2.6 - i * 0.25) / 0.5, 0, 1);
          const eased = Easing.easeOutBack(t);
          const op = clamp((localTime - 2.6 - i * 0.25) / 0.3, 0, 1);
          return (
            <div key={i} style={{
              opacity: op,
              transform: `translateY(${(1 - eased) * 18}px) scale(${0.95 + eased * 0.05})`,
              background: ofTokens.cream,
              border: `1px solid ${ofTokens.line}`,
              borderRadius: 22,
              padding: '28px 30px',
              boxShadow: '0 10px 30px -12px rgba(0,0,0,0.08)'
            }}>
              <div style={{
                fontFamily: ofTokens.fMono,
                fontSize: 14,
                letterSpacing: '0.14em',
                textTransform: 'uppercase',
                color: ofTokens.ink400,
                marginBottom: 10
              }}>{b.label}</div>
              <div style={{
                fontFamily: ofTokens.fHead,
                fontSize: 60,
                fontWeight: 700,
                letterSpacing: '-0.035em',
                color: ofTokens.ink900,
                lineHeight: 1,
                marginBottom: 8
              }}>{b.value}</div>
              <div style={{
                fontFamily: ofTokens.fBody,
                fontSize: 18,
                color: ofTokens.ink700
              }}>{b.sub}</div>
            </div>);

        })}
      </div>
    </div>);

}

// ───────────────────────────────────────────────────────────────────────────
// SCENE 3 — Meet OptimaFlo. 12–18s
// ───────────────────────────────────────────────────────────────────────────
function Scene3Intro() {
  const { localTime } = useSprite();

  // Logo enters with a spring at 0.3s
  const logoT = clamp((localTime - 0.3) / 0.7, 0, 1);
  const logoEased = Easing.easeOutBack(logoT);
  const logoOp = clamp((localTime - 0.3) / 0.4, 0, 1);

  // Headline at 1.3s
  const headT = clamp((localTime - 1.3) / 0.6, 0, 1);
  const headOp = Easing.easeOutCubic(headT);
  const headY = (1 - headOp) * 26;

  // "AI data team" highlight glow at 2.0s
  const glowT = clamp((localTime - 2.0) / 0.8, 0, 1);

  // Sub at 3.0s
  const subT = clamp((localTime - 3.0) / 0.6, 0, 1);
  const subOp = Easing.easeOutCubic(subT);

  // Exit fade
  const exit = localTime > 5.4 ? 1 - Easing.easeInCubic((localTime - 5.4) / 0.6) : 1;

  // Subtle camera pull-in
  const camZoom = interpolate([0, 6], [1.0, 1.04], Easing.easeInOutCubic)(localTime);

  return (
    <div style={{ position: 'absolute', inset: 0, opacity: exit, transform: `scale(${camZoom})`, transformOrigin: 'center' }}>
      <StageBg />

      {/* Amber radial flourish behind logo */}
      <div style={{
        position: 'absolute',
        left: '50%', top: '50%',
        transform: 'translate(-50%, -50%)',
        width: 1200, height: 1200,
        background: 'radial-gradient(circle, rgba(245,158,11,0.18), transparent 60%)',
        opacity: logoOp,
        pointerEvents: 'none'
      }} />

      {/* Logo */}
      <div style={{
        position: 'absolute',
        left: '50%', top: 360,
        transform: `translate(-50%, 0) scale(${0.6 + logoEased * 0.4})`,
        opacity: logoOp
      }}>
        <OFLogo size={140} />
      </div>

      {/* Headline */}
      <div style={{
        position: 'absolute',
        left: '50%', top: 560,
        transform: `translate(-50%, ${headY}px)`,
        opacity: headOp,
        textAlign: 'center',
        fontFamily: ofTokens.fCal,
        fontWeight: 700,
        fontSize: 110,
        lineHeight: 1.0,
        letterSpacing: '-0.04em',
        color: ofTokens.ink900
      }}>
        Meet your{' '}
        <span style={{
          position: 'relative',
          display: 'inline-block'
        }}>
          <span style={{
            background: `linear-gradient(90deg, ${ofTokens.amber600}, ${ofTokens.amber500}, ${ofTokens.amber600})`,
            WebkitBackgroundClip: 'text',
            backgroundClip: 'text',
            color: 'transparent'
          }}>AI data team.</span>
          {/* underline sweep */}
          <span style={{
            position: 'absolute',
            left: 0, bottom: -8,
            height: 6,
            width: `${glowT * 100}%`,
            background: `linear-gradient(90deg, ${ofTokens.amber600}, ${ofTokens.amber500})`,
            borderRadius: 4
          }} />
        </span>
      </div>

      {/* Sub */}
      <div style={{
        position: 'absolute',
        left: '50%', top: 800,
        transform: 'translate(-50%, 0)',
        opacity: subOp,
        textAlign: 'center',
        fontFamily: ofTokens.fBody,
        fontSize: 30,
        color: ofTokens.ink700,
        letterSpacing: '-0.01em',
        maxWidth: 1100
      }}>
        Ingestion. Warehouse. Transforms. Orchestration. BI.<br />
        <span style={{ color: ofTokens.ink900, fontWeight: 600 }}>One platform. One subscription. Deployed in your cloud.</span>
      </div>
    </div>);

}

// ───────────────────────────────────────────────────────────────────────────
// SCENE 4 — Prompt → Pipeline. 18–30s (12s)
// ───────────────────────────────────────────────────────────────────────────

// Concierge prompt window
function PromptWindow({ typed, x, y, width = 980, focused = true }) {
  return (
    <div style={{
      position: 'absolute',
      left: x, top: y,
      width,
      transform: 'translate(-50%, 0)',
      background: ofTokens.cream,
      border: `1px solid ${ofTokens.line}`,
      borderRadius: 22,
      boxShadow: focused ?
      '0 24px 60px -20px rgba(0,0,0,0.18), 0 0 0 4px rgba(245,158,11,0.12)' :
      '0 16px 40px -16px rgba(0,0,0,0.12)',
      overflow: 'hidden'
    }}>
      {/* Header */}
      <div style={{
        display: 'flex', alignItems: 'center', gap: 12,
        padding: '14px 20px',
        borderBottom: `1px solid ${ofTokens.line}`,
        background: ofTokens.card
      }}>
        <span style={{
          width: 28, height: 28, borderRadius: 8,
          background: `linear-gradient(135deg, ${ofTokens.amber600}, ${ofTokens.amber500})`,
          display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
          color: ofTokens.ink900, fontFamily: ofTokens.fHead, fontWeight: 700, fontSize: 16
        }}>✦</span>
        <span style={{
          fontFamily: ofTokens.fHead, fontWeight: 600, fontSize: 18,
          color: ofTokens.ink900, letterSpacing: '-0.01em'
        }}>OptimaFlo Manager</span>
        <span style={{ marginLeft: 'auto', fontFamily: ofTokens.fMono, fontSize: 13, color: ofTokens.ink400 }}>Plain English →</span>
      </div>
      {/* Body */}
      <div style={{
        padding: '28px 28px 24px',
        fontFamily: ofTokens.fHead,
        fontSize: 30,
        lineHeight: 1.35,
        color: ofTokens.ink900,
        letterSpacing: '-0.01em',
        minHeight: 140
      }}>
        {typed}
        <span style={{
          display: 'inline-block',
          width: 3, height: 32,
          background: ofTokens.amber600,
          verticalAlign: 'text-bottom',
          marginLeft: 2,
          animation: 'caretBlink 0.9s steps(2) infinite'
        }} />
      </div>
    </div>);

}

// Pipeline node — medallion (Bronze/Silver/Gold) style
function PipelineNode({ label, sub, kind, tier, x, y, w = 260, h = 150, appear = 1, highlight = 0 }) {
  const tierColor =
  tier === 'bronze' ? ofTokens.bronze :
  tier === 'silver' ? ofTokens.silver :
  tier === 'gold' ? ofTokens.gold :
  ofTokens.ink700;

  const scale = 0.6 + 0.4 * Easing.easeOutBack(appear);
  const op = clamp(appear, 0, 1);

  return (
    <div style={{
      position: 'absolute',
      left: x, top: y,
      width: w, height: h,
      transform: `translate(-50%, -50%) scale(${scale})`,
      opacity: op,
      background: ofTokens.cream,
      border: `1.5px solid ${highlight > 0 ? ofTokens.amber600 : ofTokens.line}`,
      borderRadius: 18,
      padding: '16px 18px',
      boxShadow: highlight > 0 ?
      `0 20px 40px -15px rgba(217,119,6,0.30), 0 0 0 ${highlight * 4}px rgba(245,158,11,${0.15 * highlight})` :
      '0 8px 18px -10px rgba(0,0,0,0.12)',
      display: 'flex',
      flexDirection: 'column',
      gap: 6
    }}>
      {/* Top: icon + name */}
      <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
        <span style={{
          width: 32, height: 32, borderRadius: 8,
          background: `${tierColor}22`,
          color: tierColor,
          display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
          fontFamily: ofTokens.fHead, fontWeight: 700, fontSize: 16
        }}>{kind === 'src' ? '⬢' : kind === 'tx' ? '∿' : kind === 'wh' ? '◉' : kind === 'orc' ? '↻' : '▤'}</span>
        <div style={{
          fontFamily: ofTokens.fHead, fontWeight: 700, fontSize: 19,
          color: ofTokens.ink900, letterSpacing: '-0.02em',
          lineHeight: 1.1
        }}>{label}</div>
      </div>
      {/* Sub label */}
      <div style={{
        fontFamily: ofTokens.fMono, fontSize: 13,
        color: ofTokens.ink700,
        lineHeight: 1.4
      }}>{sub}</div>
      {/* Tier pill */}
      {tier &&
      <div style={{
        marginTop: 'auto',
        alignSelf: 'flex-start',
        display: 'inline-flex', alignItems: 'center', gap: 6,
        padding: '4px 10px',
        borderRadius: 999,
        background: `${tierColor}1A`,
        border: `1px solid ${tierColor}55`,
        fontFamily: ofTokens.fMono, fontWeight: 600, fontSize: 11,
        color: tierColor,
        letterSpacing: '0.10em',
        textTransform: 'uppercase'
      }}>
          <span style={{
          width: 8, height: 8, borderRadius: 4, background: tierColor
        }} />
          {tier}
        </div>
      }
    </div>);

}

// Pipeline connector line — animated draw
function NodeLink({ from, to, progress = 1, dashed = false }) {
  const dx = to.x - from.x;
  const dy = to.y - from.y;
  const len = Math.hypot(dx, dy);
  const ang = Math.atan2(dy, dx) * 180 / Math.PI;
  return (
    <div style={{
      position: 'absolute',
      left: from.x, top: from.y,
      width: len * clamp(progress, 0, 1), height: 2,
      background: dashed ?
      `repeating-linear-gradient(90deg, ${ofTokens.amber600} 0 8px, transparent 8px 14px)` :
      ofTokens.amber600,
      opacity: 0.8,
      transformOrigin: 'left center',
      transform: `rotate(${ang}deg)`,
      borderRadius: 2
    }} />);

}

function Scene4PromptPipeline() {
  const { localTime } = useSprite();

  // Phase A (0–4s): prompt window center stage, text types out
  // Phase B (4–8s): prompt window shrinks to top, pipeline materializes node by node
  // Phase C (8–12s): pulse runs along the pipeline (bronze → silver → gold)

  const promptText = "Show daily revenue by region from Postgres + Stripe — with a freshness alert.";

  // Typing: chars per second ~40 → 80 chars in 2s
  const typeStart = 0.6;
  const typeEnd = 3.4;
  const typeProgress = clamp((localTime - typeStart) / (typeEnd - typeStart), 0, 1);
  const charCount = Math.floor(typeProgress * promptText.length);
  const typed = promptText.slice(0, charCount);

  // Phase transition
  const phaseB = clamp((localTime - 4.0) / 0.7, 0, 1);
  const phaseBe = Easing.easeInOutCubic(phaseB);

  // Prompt window position: starts center (y=380), moves to top (y=80), shrinks
  const promptY = interpolate([0, 1], [380, 70], Easing.linear)(phaseBe);
  const promptScale = interpolate([0, 1], [1.0, 0.62], Easing.linear)(phaseBe);
  const promptW = 980;

  // Eyebrow above prompt
  const eyebrowOp = phaseBe < 0.3 ? clamp(localTime / 0.4, 0, 1) : 1 - phaseBe;

  // Pipeline nodes layout (after phaseB)
  // 5 nodes left → right: Sources, Warehouse, Transform, Orchestrate, BI
  const nodes = [
  { id: 'src', label: 'Sources', sub: 'Postgres · Stripe · GA4', kind: 'src', tier: 'bronze', x: 220, y: 620 },
  { id: 'wh', label: 'Warehouse', sub: 'Iceberg · BYOC', kind: 'wh', tier: 'bronze', x: 580, y: 620 },
  { id: 'tx', label: 'Transform', sub: 'SQL · dbt-style', kind: 'tx', tier: 'silver', x: 960, y: 620 },
  { id: 'orc', label: 'Orchestrate', sub: 'Airflow-grade', kind: 'orc', tier: 'silver', x: 1340, y: 620 },
  { id: 'bi', label: 'Dashboards', sub: 'Live + governed', kind: 'bi', tier: 'gold', x: 1700, y: 620 }];


  // Node appear sequence: starts at localTime 4.8, each 0.35s apart
  const nodeAppear = (i) => {
    const start = 4.8 + i * 0.35;
    return clamp((localTime - start) / 0.55, 0, 1);
  };

  // Pulse position (Phase C — after 7.5s)
  // Runs over the 4 link segments in 3.5s
  const pulseT = clamp((localTime - 7.5) / 3.5, 0, 1);
  const pulseIdx = pulseT * 4; // 0..4
  const linkProgress = (i) => clamp(pulseIdx - i, 0, 1);

  // Highlight on the node the pulse is currently entering
  const nodeHighlight = (i) => {
    // highlight grows as pulse approaches node, peaks at arrival
    const target = i; // pulse hits node i when pulseIdx >= i
    const d = Math.abs(pulseIdx - target);
    return Math.max(0, 1 - d * 1.8);
  };

  // Concierge AI status badge during phase C
  const statusOp = clamp((localTime - 6.0) / 0.5, 0, 1);

  // Final caption appears at 10s
  const finalT = clamp((localTime - 10.0) / 0.5, 0, 1);

  // Scene exit
  const exit = localTime > 11.4 ? 1 - Easing.easeInCubic((localTime - 11.4) / 0.6) : 1;

  return (
    <div style={{ position: 'absolute', inset: 0, opacity: exit }}>
      <StageBg mask="radial-gradient(circle at 50% 30%, black, transparent 90%)" />

      {/* Eyebrow */}
      <div style={{
        position: 'absolute',
        left: '50%', top: 50 - (1 - eyebrowOp) * 30,
        transform: 'translate(-50%, 0)',
        opacity: eyebrowOp,
        fontFamily: ofTokens.fMono,
        fontSize: 18,
        letterSpacing: '0.18em',
        textTransform: 'uppercase',
        color: ofTokens.amber600,
        whiteSpace: 'nowrap'
      }}>Describe it. Build it.</div>

      {/* Prompt window */}
      <div style={{
        position: 'absolute',
        left: '50%', top: promptY,
        width: promptW,
        transform: `translate(-50%, 0) scale(${promptScale})`,
        transformOrigin: 'top center'
      }}>
        <PromptWindow typed={typed} x={promptW / 2} y={0} width={promptW} focused={phaseBe < 0.5} />
      </div>

      {/* Concierge "thinking → building" status */}
      {localTime > 5.5 &&
      <div style={{
        position: 'absolute',
        left: '50%', top: 280,
        transform: 'translate(-50%, 0)',
        opacity: statusOp,
        display: 'inline-flex', alignItems: 'center', gap: 12,
        padding: '10px 20px',
        background: ofTokens.ink900,
        color: ofTokens.cream,
        borderRadius: 999,
        fontFamily: ofTokens.fMono,
        fontSize: 16,
        letterSpacing: '0.06em',
        whiteSpace: 'nowrap'
      }}>
          <span style={{
          width: 10, height: 10, borderRadius: 5,
          background: ofTokens.amber500,
          animation: 'pulseDot 1s ease-in-out infinite'
        }} />
          AI DATA TEAM · BUILDING PIPELINE
        </div>
      }

      {/* Stage labels above nodes */}
      {phaseBe > 0.5 && nodes.map((n, i) => {
        const labels = ['Ingest', 'Warehouse', 'Transform', 'Orchestrate', 'BI'];
        const op = nodeAppear(i);
        return (
          <div key={'stg-' + n.id} style={{
            position: 'absolute',
            left: n.x, top: 460,
            transform: 'translate(-50%, 0)',
            opacity: op,
            fontFamily: ofTokens.fMono,
            fontSize: 13,
            letterSpacing: '0.16em',
            textTransform: 'uppercase',
            color: ofTokens.ink400,
            fontWeight: 600
          }}>{labels[i]}</div>);

      })}

      {/* Links between nodes */}
      {phaseBe > 0.5 && nodes.slice(0, -1).map((n, i) => {
        const next = nodes[i + 1];
        // Link visible only after both endpoints appear
        const apA = nodeAppear(i);
        const apB = nodeAppear(i + 1);
        const visible = Math.min(apA, apB);
        // Pulse-driven progress
        const prog = pulseT > 0 ? linkProgress(i) : visible * 0.5;
        return (
          <NodeLink
            key={'lk-' + i}
            from={{ x: n.x + 130, y: n.y }}
            to={{ x: next.x - 130, y: next.y }}
            progress={prog}
            dashed={false} />);


      })}

      {/* Nodes */}
      {phaseBe > 0.5 && nodes.map((n, i) =>
      <PipelineNode
        key={n.id}
        label={n.label}
        sub={n.sub}
        kind={n.kind}
        tier={n.tier}
        x={n.x}
        y={n.y}
        appear={nodeAppear(i)}
        highlight={nodeHighlight(i)} />

      )}

      {/* Final caption */}
      {finalT > 0 &&
      <div style={{
        position: 'absolute',
        left: '50%', top: 850,
        transform: `translate(-50%, ${(1 - finalT) * 16}px)`,
        opacity: finalT,
        textAlign: 'center',
        fontFamily: ofTokens.fHead,
        fontWeight: 600,
        fontSize: 44,
        letterSpacing: '-0.025em',
        color: ofTokens.ink900
      }}>
          You describe it. <span style={{ color: ofTokens.amber600 }}>The AI builds it.</span>
        </div>
      }
    </div>);

}

// ── DashboardMock — a hand-built OptimaFlo dashboard (replaces canvas img) ──
function DashboardMock({ progress = 1 }) {
  // KPI tiles
  const kpis = [
    { label: 'Revenue',       value: '$142,310', delta: '+18.2%', up: true,  spark: [4,6,5,8,7,10,12,11,14,16,15,18] },
    { label: 'Orders',        value: '1,284',    delta: '+12.4%', up: true,  spark: [6,7,7,9,8,10,11,12,13,14,14,15] },
    { label: 'Avg order val', value: '$110.84',  delta: '+5.6%',  up: true,  spark: [10,10,11,12,11,12,13,13,12,13,14,14] },
    { label: 'Conv. rate',    value: '3.24%',    delta: '−0.3%',  up: false, spark: [9,10,9,8,9,8,7,8,7,7,7,6] },
  ];

  // Top regions
  const regions = [
    { name: 'United States', pct: 86, value: '$122.4K' },
    { name: 'Canada',        pct: 38, value: '$54.1K' },
    { name: 'United Kingdom',pct: 28, value: '$39.6K' },
    { name: 'Germany',       pct: 22, value: '$31.2K' },
  ];

  // Main chart — current period (amber) vs previous (gray, dashed)
  // 12 daily points, returns smooth bezier-ish polyline path
  const curr = [180, 165, 175, 150, 160, 130, 140, 115, 95, 105, 80, 60];
  const prev = [200, 195, 200, 185, 190, 180, 175, 170, 165, 170, 160, 155];
  const W = 950, H = 360;
  const stepX = W / (curr.length - 1);

  const buildPath = (pts) => pts.map((y, i) => `${i === 0 ? 'M' : 'L'} ${(i * stepX).toFixed(1)} ${y}`).join(' ');
  const buildArea = (pts) => buildPath(pts) + ` L ${W} ${H} L 0 ${H} Z`;

  // Animated stroke draw via dashoffset
  // Each path "approx length" = sum of segment lengths
  const pathLen = (pts) => pts.slice(1).reduce((acc, y, i) => {
    const dx = stepX, dy = y - pts[i];
    return acc + Math.hypot(dx, dy);
  }, 0);
  const currLen = pathLen(curr);
  const prevLen = pathLen(prev);
  const drawProg = clamp(progress, 0, 1);

  return (
    <div style={{
      width: 1500, height: 720,
      background: ofTokens.cream,
      border: `1px solid ${ofTokens.line}`,
      borderRadius: 24,
      padding: '24px 28px 28px',
      display: 'flex',
      flexDirection: 'column',
      gap: 16,
      fontFamily: ofTokens.fBody,
      overflow: 'hidden',
    }}>
      {/* Header bar */}
      <div style={{ display: 'flex', alignItems: 'center', gap: 16 }}>
        <div>
          <div style={{
            fontFamily: ofTokens.fMono, fontSize: 12,
            letterSpacing: '0.16em', textTransform: 'uppercase',
            color: ofTokens.ink400, marginBottom: 4,
          }}>Workspace · acme · gold</div>
          <div style={{
            fontFamily: ofTokens.fHead, fontWeight: 700,
            fontSize: 38, letterSpacing: '-0.03em',
            color: ofTokens.ink900, lineHeight: 1.0,
          }}>Daily Revenue</div>
        </div>

        {/* Segmented control */}
        <div style={{
          marginLeft: 'auto',
          display: 'inline-flex', alignItems: 'center',
          background: ofTokens.card,
          border: `1px solid ${ofTokens.line}`,
          borderRadius: 10,
          padding: 4,
        }}>
          {['7D', '30D', '90D', '12M'].map((s, i) => (
            <span key={s} style={{
              padding: '6px 14px',
              borderRadius: 7,
              fontFamily: ofTokens.fMono, fontSize: 13, fontWeight: 600,
              color: i === 1 ? ofTokens.ink900 : ofTokens.ink700,
              background: i === 1 ? ofTokens.cream : 'transparent',
              boxShadow: i === 1 ? '0 1px 2px rgba(0,0,0,0.06)' : 'none',
            }}>{s}</span>
          ))}
        </div>

        {/* Live pill */}
        <div style={{
          display: 'inline-flex', alignItems: 'center', gap: 8,
          padding: '8px 14px',
          background: 'rgba(16,185,129,0.10)',
          border: `1px solid rgba(16,185,129,0.30)`,
          borderRadius: 999,
          fontFamily: ofTokens.fMono, fontSize: 13, fontWeight: 600,
          color: '#0F6E4F',
          letterSpacing: '0.04em',
        }}>
          <span style={{
            width: 8, height: 8, borderRadius: 4, background: '#10B981',
            boxShadow: '0 0 10px rgba(16,185,129,0.7)',
          }}/>
          LIVE · 2 min ago
        </div>
      </div>

      {/* KPI row */}
      <div style={{
        display: 'grid',
        gridTemplateColumns: 'repeat(4, 1fr)',
        gap: 14,
      }}>
        {kpis.map((k, i) => (
          <div key={k.label} style={{
            background: ofTokens.cream,
            border: `1px solid ${ofTokens.line}`,
            borderRadius: 16,
            padding: '18px 20px',
            display: 'flex', flexDirection: 'column', gap: 4,
          }}>
            <div style={{
              fontFamily: ofTokens.fMono, fontSize: 11,
              letterSpacing: '0.16em', textTransform: 'uppercase',
              color: ofTokens.ink400,
            }}>{k.label}</div>
            <div style={{
              fontFamily: ofTokens.fHead, fontWeight: 700,
              fontSize: 36, letterSpacing: '-0.025em',
              color: ofTokens.ink900, lineHeight: 1.0,
              fontVariantNumeric: 'tabular-nums',
            }}>{k.value}</div>
            <div style={{ display: 'flex', alignItems: 'center', gap: 10, marginTop: 6 }}>
              <span style={{
                display: 'inline-flex', alignItems: 'center', gap: 4,
                padding: '2px 8px',
                background: k.up ? 'rgba(16,185,129,0.12)' : 'rgba(217,119,6,0.12)',
                color: k.up ? '#0F6E4F' : ofTokens.amber700,
                borderRadius: 6,
                fontFamily: ofTokens.fMono, fontSize: 12, fontWeight: 600,
              }}>
                {k.up ? '▲' : '▼'} {k.delta}
              </span>
              {/* sparkline */}
              <svg width="90" height="22" viewBox={`0 0 90 22`} style={{ flex: 1 }}>
                <polyline
                  fill="none"
                  stroke={k.up ? '#10B981' : ofTokens.amber600}
                  strokeWidth="1.6"
                  strokeLinecap="round"
                  strokeLinejoin="round"
                  points={k.spark.map((v, j) => `${(j / (k.spark.length - 1)) * 90},${22 - (v / 20) * 20}`).join(' ')}
                />
              </svg>
            </div>
          </div>
        ))}
      </div>

      {/* Main chart + sidebar */}
      <div style={{
        display: 'grid',
        gridTemplateColumns: '1fr 420px',
        gap: 16,
        flex: 1,
        minHeight: 0,
      }}>
        {/* Chart card */}
        <div style={{
          background: ofTokens.cream,
          border: `1px solid ${ofTokens.line}`,
          borderRadius: 16,
          padding: '20px 22px',
          display: 'flex', flexDirection: 'column',
        }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 18, marginBottom: 14 }}>
            <div style={{
              fontFamily: ofTokens.fHead, fontWeight: 700,
              fontSize: 18, color: ofTokens.ink900, letterSpacing: '-0.015em',
            }}>Revenue by day</div>
            {/* Legend */}
            <div style={{ display: 'flex', gap: 14, marginLeft: 'auto' }}>
              <span style={{
                display: 'inline-flex', alignItems: 'center', gap: 6,
                fontFamily: ofTokens.fMono, fontSize: 12, color: ofTokens.ink700,
              }}>
                <span style={{ width: 10, height: 3, background: ofTokens.amber600, borderRadius: 2 }}/>
                This period
              </span>
              <span style={{
                display: 'inline-flex', alignItems: 'center', gap: 6,
                fontFamily: ofTokens.fMono, fontSize: 12, color: ofTokens.ink400,
              }}>
                <span style={{ width: 10, height: 3, background: 'repeating-linear-gradient(90deg, ' + ofTokens.ink400 + ' 0 3px, transparent 3px 6px)', borderRadius: 2 }}/>
                Previous
              </span>
            </div>
          </div>

          {/* SVG chart */}
          <div style={{ flex: 1, position: 'relative' }}>
            <svg width="100%" height="100%" viewBox={`-30 -20 ${W + 60} ${H + 40}`} preserveAspectRatio="none">
              {/* Grid lines */}
              {[0, 0.25, 0.5, 0.75, 1].map((g, i) => (
                <g key={i}>
                  <line x1="0" x2={W} y1={g * H} y2={g * H}
                        stroke={ofTokens.line} strokeWidth="1"
                        strokeDasharray={i === 4 ? '0' : '2 4'}/>
                  <text x="-8" y={g * H + 4} textAnchor="end"
                        fontFamily={ofTokens.fMono} fontSize="10"
                        fill={ofTokens.ink400}>
                    ${Math.round((1 - g) * 200)}K
                  </text>
                </g>
              ))}
              {/* X labels */}
              {['Mar 1','5','10','15','20','25','30'].map((lbl, i) => (
                <text key={i} x={(i / 6) * W} y={H + 18} textAnchor="middle"
                      fontFamily={ofTokens.fMono} fontSize="10"
                      fill={ofTokens.ink400}>{lbl}</text>
              ))}

              {/* Previous period — gray dashed */}
              <path d={buildPath(prev)}
                    fill="none"
                    stroke={ofTokens.ink400}
                    strokeWidth="1.8"
                    strokeDasharray="5 6"
                    strokeLinecap="round"
                    style={{
                      strokeDasharray: '5 6',
                      opacity: Math.max(0, (drawProg - 0.3) * 2),
                    }}/>

              {/* Current period area fill */}
              <defs>
                <linearGradient id="dash-grad" x1="0" y1="0" x2="0" y2="1">
                  <stop offset="0" stopColor={ofTokens.amber500} stopOpacity="0.35"/>
                  <stop offset="1" stopColor={ofTokens.amber500} stopOpacity="0"/>
                </linearGradient>
                <clipPath id="dash-clip">
                  <rect x="0" y="0" width={W * drawProg} height={H + 20}/>
                </clipPath>
              </defs>
              <g clipPath="url(#dash-clip)">
                <path d={buildArea(curr)} fill="url(#dash-grad)"/>
                <path d={buildPath(curr)}
                      fill="none"
                      stroke={ofTokens.amber600}
                      strokeWidth="3"
                      strokeLinecap="round"
                      strokeLinejoin="round"/>
              </g>

              {/* End-of-chart dot */}
              {drawProg > 0.98 && (
                <g>
                  <circle cx={W} cy={curr[curr.length - 1]} r="6" fill={ofTokens.amber600}/>
                  <circle cx={W} cy={curr[curr.length - 1]} r="12" fill={ofTokens.amber600} opacity="0.18"/>
                </g>
              )}
            </svg>
          </div>
        </div>

        {/* Sidebar: top regions */}
        <div style={{
          background: ofTokens.cream,
          border: `1px solid ${ofTokens.line}`,
          borderRadius: 16,
          padding: '20px 22px',
          display: 'flex', flexDirection: 'column',
        }}>
          <div style={{
            fontFamily: ofTokens.fHead, fontWeight: 700,
            fontSize: 18, color: ofTokens.ink900, letterSpacing: '-0.015em',
            marginBottom: 16,
          }}>Top regions</div>
          {regions.map((r, i) => (
            <div key={r.name} style={{ marginBottom: 14 }}>
              <div style={{
                display: 'flex', justifyContent: 'space-between',
                fontFamily: ofTokens.fBody, fontSize: 15,
                marginBottom: 6,
              }}>
                <span style={{ color: ofTokens.ink900, fontWeight: 500 }}>{r.name}</span>
                <span style={{ color: ofTokens.ink700, fontFamily: ofTokens.fMono, fontVariantNumeric: 'tabular-nums' }}>{r.value}</span>
              </div>
              <div style={{
                height: 8, borderRadius: 4,
                background: ofTokens.card, overflow: 'hidden',
              }}>
                <div style={{
                  height: '100%',
                  width: `${Math.min(100, r.pct * clamp(drawProg * 1.4, 0, 1))}%`,
                  background: `linear-gradient(90deg, ${ofTokens.amber600}, ${ofTokens.amber500})`,
                  borderRadius: 4,
                }}/>
              </div>
            </div>
          ))}

          {/* Footer pill: pipeline source */}
          <div style={{
            marginTop: 'auto', paddingTop: 14,
            borderTop: `1px solid ${ofTokens.line}`,
            display: 'flex', alignItems: 'center', gap: 10,
            fontFamily: ofTokens.fMono, fontSize: 12,
            color: ofTokens.ink700,
          }}>
            <span style={{
              padding: '3px 8px', borderRadius: 6,
              background: 'rgba(217,119,6,0.12)',
              color: ofTokens.amber700,
              fontWeight: 700, letterSpacing: '0.08em',
            }}>GOLD</span>
            bi.gold.daily_revenue · refreshed hourly
          </div>
        </div>
      </div>
    </div>
  );
}
function Scene5Dashboard() {
  const { localTime } = useSprite();

  // Dashboard frame enters with ease, then ken-burns zoom + pan
  const enterT = clamp((localTime - 0.2) / 0.9, 0, 1);
  const enterEased = Easing.easeOutCubic(enterT);

  // Ken Burns: hold from 1s to 6.5s
  const burnsT = clamp((localTime - 1.0) / 5.5, 0, 1);
  const burnsScale = 1.04 + burnsT * 0.06;
  const burnsX = burnsT * -30;

  // Exit
  const exit = localTime > 7.2 ? 1 - Easing.easeInCubic((localTime - 7.2) / 0.8) : 1;

  // Headline appears at 0.6s
  const headT = clamp((localTime - 0.6) / 0.6, 0, 1);

  // Floating badges that appear over the dashboard
  const badges = [
  { label: 'Pipeline · GREEN',  x: 260,  y: 280, delay: 1.6 },
  { label: 'Tests passing 21/21', x: 1670, y: 1010, delay: 2.4 }];


  return (
    <div style={{ position: 'absolute', inset: 0, opacity: exit }}>
      <StageBg mask="radial-gradient(circle at 50% 50%, black, transparent 90%)" />

      {/* Eyebrow + headline */}
      <div style={{
        position: 'absolute',
        left: '50%', top: 60,
        transform: `translate(-50%, ${(1 - headT) * 16}px)`,
        opacity: headT,
        textAlign: 'center'
      }}>
        <div style={{
          fontFamily: ofTokens.fMono,
          fontSize: 17,
          letterSpacing: '0.18em',
          textTransform: 'uppercase',
          color: ofTokens.amber600,
          marginBottom: 10
        }}>The output</div>
        <div style={{
          fontFamily: ofTokens.fCal,
          fontWeight: 700,
          fontSize: 80,
          letterSpacing: '-0.035em',
          color: ofTokens.ink900,
          lineHeight: 1.0,
          whiteSpace: 'nowrap'
        }}>Clean dashboards. <span style={{ color: ofTokens.amber600 }}>Live data.</span></div>
      </div>

      {/* Dashboard frame */}
      <div style={{
        position: 'absolute',
        left: '50%', top: 290,
        transform: `translate(${-50 + 0}%, 0) scale(${(0.95 + enterEased * 0.05) * burnsScale}) translateX(${burnsX}px)`,
        transformOrigin: 'top center',
        opacity: enterT,
        width: 1500,
        borderRadius: 24,
        overflow: 'hidden',
        boxShadow: '0 50px 100px -30px rgba(0,0,0,0.35), 0 18px 40px -12px rgba(0,0,0,0.2)'
      }}>
        <DashboardMock progress={clamp((localTime - 0.4) / 2.4, 0, 1)}/>
      </div>

      {/* Floating badges */}
      {badges.map((b, i) => {
        const t = clamp((localTime - b.delay) / 0.5, 0, 1);
        const op = clamp((localTime - b.delay) / 0.3, 0, 1);
        const eased = Easing.easeOutBack(t);
        return (
          <div key={i} style={{
            position: 'absolute',
            left: b.x, top: b.y,
            transform: `translate(-50%, -50%) scale(${0.7 + eased * 0.3})`,
            opacity: op,
            background: ofTokens.cream,
            border: `1px solid ${ofTokens.line}`,
            borderRadius: 999,
            padding: '10px 18px',
            boxShadow: '0 16px 30px -10px rgba(0,0,0,0.18)',
            fontFamily: ofTokens.fMono,
            fontSize: 15,
            fontWeight: 600,
            color: ofTokens.ink900,
            letterSpacing: '0.04em',
            display: 'inline-flex', alignItems: 'center', gap: 10
          }}>
            <span style={{
              width: 10, height: 10, borderRadius: 5, background: '#10B981',
              boxShadow: '0 0 12px rgba(16,185,129,0.6)'
            }} />
            {b.label}
          </div>);

      })}
    </div>);

}

// ───────────────────────────────────────────────────────────────────────────
// SCENE 6 — BYOC + Human-in-the-loop. 38–46s (8s)
// ───────────────────────────────────────────────────────────────────────────
function Scene6Trust() {
  const { localTime } = useSprite();

  // Headline at 0.3s
  const headT = clamp((localTime - 0.2) / 0.6, 0, 1);

  // Left card (BYOC) at 0.8s
  const leftT = clamp((localTime - 0.8) / 0.7, 0, 1);
  const leftE = Easing.easeOutBack(leftT);

  // Right card (HITL) at 1.3s
  const rightT = clamp((localTime - 1.3) / 0.7, 0, 1);
  const rightE = Easing.easeOutBack(rightT);

  // Approve click animation at 4.8s
  const clickT = clamp((localTime - 4.8) / 0.5, 0, 1);

  // After click, "Approved" check
  const checkT = clamp((localTime - 5.4) / 0.4, 0, 1);

  // Exit
  const exit = localTime > 7.4 ? 1 - Easing.easeInCubic((localTime - 7.4) / 0.6) : 1;

  return (
    <div style={{ position: 'absolute', inset: 0, opacity: exit }}>
      <StageBg mask="radial-gradient(circle at 50% 50%, black, transparent 90%)" />

      {/* Headline */}
      <div style={{
        position: 'absolute',
        left: '50%', top: 110,
        transform: `translate(-50%, ${(1 - headT) * 20}px)`,
        opacity: headT,
        textAlign: 'center'
      }}>
        <div style={{
          fontFamily: ofTokens.fMono,
          fontSize: 17,
          letterSpacing: '0.18em',
          textTransform: 'uppercase',
          color: ofTokens.amber600,
          marginBottom: 14
        }}>Trust by design</div>
        <div style={{
          fontFamily: ofTokens.fCal,
          fontWeight: 700,
          fontSize: 86,
          letterSpacing: '-0.035em',
          color: ofTokens.ink900,
          lineHeight: 1.0,
          whiteSpace: 'nowrap'
        }}>Your cloud. <span style={{ color: ofTokens.amber600 }}>Your rules.</span></div>
      </div>

      {/* Two cards side by side */}
      {/* LEFT — BYOC */}
      <div style={{
        position: 'absolute',
        left: 220, top: 380,
        width: 720, height: 540,
        transform: `translateY(${(1 - leftE) * 30}px) scale(${0.95 + leftE * 0.05})`,
        opacity: leftT,
        background: ofTokens.cream,
        border: `1px solid ${ofTokens.line}`,
        borderRadius: 28,
        padding: 40,
        boxShadow: '0 30px 60px -25px rgba(0,0,0,0.15)'
      }}>
        <div style={{
          fontFamily: ofTokens.fMono,
          fontSize: 13,
          letterSpacing: '0.16em',
          textTransform: 'uppercase',
          color: ofTokens.ink400,
          marginBottom: 14
        }}>BYOC · Bring your own cloud</div>
        <div style={{
          fontFamily: ofTokens.fHead,
          fontWeight: 700,
          fontSize: 44,
          letterSpacing: '-0.03em',
          color: ofTokens.ink900,
          lineHeight: 1.0,
          marginBottom: 28
        }}>Data never leaves your perimeter.</div>

        {/* Cloud illustration: a "perimeter" box with cloud + your data inside */}
        <div style={{
          position: 'relative',
          height: 280,
          border: `2px dashed ${ofTokens.amber600}55`,
          borderRadius: 20,
          background: 'rgba(245,158,11,0.04)',
          padding: 24
        }}>
          <div style={{
            position: 'absolute', top: -14, left: 24,
            background: ofTokens.cream,
            padding: '0 12px',
            fontFamily: ofTokens.fMono, fontSize: 13,
            color: ofTokens.amber700,
            letterSpacing: '0.10em',
            textTransform: 'uppercase', fontWeight: 600
          }}>YOUR VPC</div>

          {/* Cloud providers */}
          <div style={{
            display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 14,
            marginBottom: 18
          }}>
            {['AWS', 'GCP', 'Azure'].map((p, i) =>
            <div key={p} style={{
              background: ofTokens.cream,
              border: `1px solid ${ofTokens.line}`,
              borderRadius: 12,
              padding: '14px 12px',
              textAlign: 'center',
              fontFamily: ofTokens.fHead,
              fontWeight: 700,
              fontSize: 22,
              letterSpacing: '-0.02em',
              color: ofTokens.ink900
            }}>{p}</div>
            )}
          </div>

          {/* Data table mock */}
          <div style={{
            background: ofTokens.card,
            borderRadius: 12,
            padding: 14,
            fontFamily: ofTokens.fMono,
            fontSize: 14,
            color: ofTokens.ink700,
            lineHeight: 1.7
          }}>
            <div style={{ color: ofTokens.ink900, fontWeight: 700, marginBottom: 4 }}>customers.parquet</div>
            <div>regions/us-east-1/iceberg/...</div>
            <div style={{ color: ofTokens.amber700 }}>encrypted at rest · KMS</div>
          </div>
        </div>
      </div>

      {/* RIGHT — HITL */}
      <div style={{
        position: 'absolute',
        left: 980, top: 380,
        width: 720, height: 540,
        transform: `translateY(${(1 - rightE) * 30}px) scale(${0.95 + rightE * 0.05})`,
        opacity: rightT,
        background: ofTokens.cream,
        border: `1px solid ${ofTokens.line}`,
        borderRadius: 28,
        padding: 40,
        boxShadow: '0 30px 60px -25px rgba(0,0,0,0.15)'
      }} data-comment-anchor="198c3c512a-div-1111-7">
        <div style={{
          fontFamily: ofTokens.fMono,
          fontSize: 13,
          letterSpacing: '0.16em',
          textTransform: 'uppercase',
          color: ofTokens.ink400,
          marginBottom: 14
        }}>Human in the loop</div>
        <div style={{
          fontFamily: ofTokens.fHead,
          fontWeight: 700,
          fontSize: 44,
          letterSpacing: '-0.03em',
          color: ofTokens.ink900,
          lineHeight: 1.0,
          marginBottom: 28
        }}>Review and ship. Never babysit.</div>

        {/* Manager interrupt card (mirrors OptimaFlo Manager review flow) */}
        <div style={{
          background: ofTokens.cream,
          border: `1px solid ${ofTokens.line}`,
          borderRadius: 16,
          padding: 18,
          boxShadow: '0 12px 24px -10px rgba(0,0,0,0.10)'
        }}>
          {/* Card header — Manager + status */}
          <div style={{
            display: 'flex', alignItems: 'center', gap: 10,
            marginBottom: 14
          }}>
            <span style={{
              width: 30, height: 30, borderRadius: 9,
              background: `linear-gradient(135deg, ${ofTokens.amber600}, ${ofTokens.amber500})`,
              color: ofTokens.ink900,
              display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
              fontFamily: ofTokens.fHead, fontWeight: 800, fontSize: 16,
              letterSpacing: '-0.02em',
            }}>M</span>
            <div style={{ display: 'flex', flexDirection: 'column' }}>
              <span style={{ fontFamily: ofTokens.fHead, fontWeight: 700, fontSize: 17, color: ofTokens.ink900, lineHeight: 1.1 }}>
                Manager — ready to run
              </span>
              <span style={{ fontFamily: ofTokens.fMono, fontSize: 12, color: ofTokens.ink400, letterSpacing: '0.04em' }}>
                4 steps planned · awaiting your approval
              </span>
            </div>
          </div>

          {/* Structured plan — pipeline fields */}
          <div style={{
            background: ofTokens.card,
            borderRadius: 10,
            padding: '14px 16px',
            marginBottom: 16,
            display: 'flex', flexDirection: 'column', gap: 10,
          }}>
            {[
              { k: 'Pipeline',    v: 'daily_revenue',            tag: null },
              { k: 'Schedule',    v: 'Hourly · 09:00–18:00 ET',  tag: null },
              { k: 'Destination', v: 'bi.gold.daily_revenue',    tag: 'GOLD' },
              { k: 'Tests',       v: 'not_null · unique · freshness', tag: '3 passing' },
            ].map(row => (
              <div key={row.k} style={{
                display: 'grid',
                gridTemplateColumns: '110px 1fr auto',
                gap: 10,
                alignItems: 'center',
                fontFamily: ofTokens.fMono, fontSize: 13,
              }}>
                <span style={{
                  color: ofTokens.ink400,
                  letterSpacing: '0.08em',
                  textTransform: 'uppercase',
                  fontWeight: 600,
                }}>{row.k}</span>
                <span style={{ color: ofTokens.ink900, fontWeight: 500 }}>{row.v}</span>
                {row.tag && (
                  <span style={{
                    padding: '2px 8px',
                    borderRadius: 6,
                    background: row.tag === 'GOLD'
                      ? 'rgba(217,119,6,0.12)'
                      : 'rgba(16,185,129,0.12)',
                    color: row.tag === 'GOLD' ? ofTokens.amber700 : '#0F6E4F',
                    fontWeight: 700, fontSize: 11,
                    letterSpacing: '0.08em',
                  }}>{row.tag}</span>
                )}
              </div>
            ))}
          </div>

          {/* Buttons */}
          <div style={{
            display: 'flex', gap: 10, alignItems: 'center'
          }}>
            <div style={{
              padding: '12px 18px',
              border: `1px solid ${ofTokens.line}`,
              borderRadius: 10,
              fontFamily: ofTokens.fHead,
              fontWeight: 500, fontSize: 16,
              color: ofTokens.ink700,
              background: ofTokens.cream
            }}>Edit plan</div>

            <div style={{
              padding: '12px 22px',
              borderRadius: 10,
              fontFamily: ofTokens.fHead,
              fontWeight: 600, fontSize: 16,
              color: ofTokens.ink900,
              background: ofTokens.amber600,
              boxShadow: clickT > 0 ?
              `0 0 0 ${10 * (1 - clickT)}px rgba(245,158,11,${0.35 * (1 - clickT)})` :
              '0 4px 10px -2px rgba(217,119,6,0.30)',
              transform: clickT > 0 && clickT < 0.4 ? 'translateY(2px)' : 'translateY(0)',
              display: 'inline-flex', alignItems: 'center', gap: 8
            }}>
              Approve &amp; run
              {checkT > 0 &&
              <span style={{
                display: 'inline-flex', alignItems: 'center', gap: 4,
                marginLeft: 4, opacity: checkT,
                color: '#10B981', fontWeight: 700
              }}>✓</span>
              }
            </div>

            {/* "You" cursor pointer that flies in to click */}
            {localTime > 4.0 && localTime < 5.8 && (() => {
              const flyT = clamp((localTime - 4.0) / 0.8, 0, 1);
              const cx = interpolate([0, 1], [700, 460], Easing.easeOutCubic)(flyT);
              const cy = interpolate([0, 1], [620, 490], Easing.easeOutCubic)(flyT);
              return (
                <div style={{
                  position: 'absolute',
                  left: cx - 980, top: cy - 380,
                  pointerEvents: 'none'
                }}>
                  <svg width="36" height="36" viewBox="0 0 24 24">
                    <path d="M3 2l7 18 2.5-7.5L20 10z" fill={ofTokens.ink900} stroke="#fff" strokeWidth="1.2" />
                  </svg>
                </div>);

            })()}
          </div>
        </div>
      </div>
    </div>);

}

// ───────────────────────────────────────────────────────────────────────────
// SCENE 7 — Savings (cost + time). 46–54s (8s)
// ───────────────────────────────────────────────────────────────────────────
function Scene7Savings() {
  const { localTime } = useSprite();

  const headT = clamp((localTime - 0.2) / 0.5, 0, 1);

  // Cost row appears at 0.8s, big strikethrough animates at 2.0s
  const costT = clamp((localTime - 0.7) / 0.6, 0, 1);
  const strikeT = clamp((localTime - 2.0) / 0.6, 0, 1);

  // Time row appears at 3.4s
  const timeT = clamp((localTime - 3.4) / 0.6, 0, 1);
  const timeStrikeT = clamp((localTime - 4.7) / 0.6, 0, 1);

  // Final punchline
  const finalT = clamp((localTime - 6.0) / 0.6, 0, 1);

  const exit = localTime > 7.4 ? 1 - Easing.easeInCubic((localTime - 7.4) / 0.6) : 1;

  const Row = ({ y, eyebrow, oldVal, newVal, oldOp, oldStrike, newOp, oldUnit, newUnit, newSub }) =>
  <div style={{
    position: 'absolute', left: '50%', top: y,
    transform: 'translate(-50%, 0)',
    display: 'grid',
    gridTemplateColumns: '1fr auto 1fr',
    gap: 70,
    alignItems: 'center',
    width: 1600
  }}>
      {/* OLD */}
      <div style={{ textAlign: 'right', opacity: oldOp }}>
        <div style={{
        fontFamily: ofTokens.fMono, fontSize: 14,
        letterSpacing: '0.16em', textTransform: 'uppercase',
        color: ofTokens.ink400, marginBottom: 10
      }}>{eyebrow} — before</div>
        <div style={{
        position: 'relative',
        display: 'inline-flex', alignItems: 'baseline', gap: 4,
        fontFamily: ofTokens.fCal, fontWeight: 700,
        letterSpacing: '-0.04em',
        color: ofTokens.ink400, lineHeight: 0.95,
        whiteSpace: 'nowrap',
        padding: '0 12px'
      }}>
          <span style={{ fontSize: 130 }}>{oldVal}</span>
          <span style={{ fontSize: 60 }}>{oldUnit}</span>
          {/* Strike — overlays the full inline-flex (both value + unit) */}
          <div style={{
          position: 'absolute',
          left: 0, right: 0, top: '58%',
          height: 8,
          background: ofTokens.amber600,
          borderRadius: 4,
          transformOrigin: 'left center',
          transform: `scaleX(${oldStrike})`,
          pointerEvents: 'none'
        }} />
        </div>
      </div>

      {/* Arrow */}
      <div style={{
      opacity: Math.min(oldOp, newOp),
      fontFamily: ofTokens.fHead,
      fontSize: 64,
      color: ofTokens.amber600,
      fontWeight: 700
    }}>→</div>

      {/* NEW */}
      <div style={{ opacity: newOp }}>
        <div style={{
        fontFamily: ofTokens.fMono, fontSize: 14,
        letterSpacing: '0.16em', textTransform: 'uppercase',
        color: ofTokens.amber600, marginBottom: 10, fontWeight: 600
      }}>{eyebrow} — with optimaflo</div>
        <div style={{
        fontFamily: ofTokens.fCal, fontWeight: 700,
        letterSpacing: '-0.04em',
        color: ofTokens.ink900, lineHeight: 0.95,
        display: 'inline-flex', alignItems: 'baseline', gap: 4,
        whiteSpace: 'nowrap'
      }}>
          <span style={{ fontSize: 130 }}>{newVal}</span>
          <span style={{ fontSize: 60, color: ofTokens.amber600 }}>{newUnit}</span>
        </div>
        {newSub &&
      <div style={{
        fontFamily: ofTokens.fBody, fontSize: 18, color: ofTokens.ink700,
        marginTop: 6
      }}>{newSub}</div>
      }
      </div>
    </div>;


  return (
    <div style={{ position: 'absolute', inset: 0, opacity: exit }}>
      <StageBg mask="radial-gradient(circle at 50% 50%, black, transparent 90%)" />

      {/* Headline */}
      <div style={{
        position: 'absolute',
        left: '50%', top: 90,
        transform: `translate(-50%, ${(1 - headT) * 20}px)`,
        opacity: headT,
        textAlign: 'center'
      }}>
        <div style={{
          fontFamily: ofTokens.fMono,
          fontSize: 17,
          letterSpacing: '0.18em',
          textTransform: 'uppercase',
          color: ofTokens.amber600,
          marginBottom: 12
        }}>The math</div>
        <div style={{
          fontFamily: ofTokens.fCal,
          fontWeight: 700,
          fontSize: 80,
          letterSpacing: '-0.035em',
          color: ofTokens.ink900,
          lineHeight: 1.0
        }}>40× cheaper. <span style={{ color: ofTokens.amber600 }}>Hundreds of times faster.</span></div>
      </div>

      <Row
        y={310}
        eyebrow="COST"
        oldVal="$100" oldUnit="K/mo"
        newVal="$2.5" newUnit="K/mo"
        oldOp={costT} newOp={costT}
        oldStrike={strikeT}
        newSub="Starting price — everything included" />
      

      <Row
        y={620}
        eyebrow="TIME"
        oldVal="4–6" oldUnit="months"
        newVal="One" newUnit="afternoon"
        oldOp={timeT} newOp={timeT}
        oldStrike={timeStrikeT}
        newSub="From raw data to first dashboard" />
      

      {/* Punchline */}
      <div style={{
        position: 'absolute',
        left: '50%', top: 920,
        transform: `translate(-50%, ${(1 - finalT) * 16}px)`,
        opacity: finalT,
        textAlign: 'center',
        fontFamily: ofTokens.fHead,
        fontWeight: 600,
        fontSize: 32,
        color: ofTokens.ink700,
        letterSpacing: '-0.015em'
      }}>
        No per-seat. No per-row. No surprise bills.
      </div>
    </div>);

}

// ───────────────────────────────────────────────────────────────────────────
// SCENE 8 — CTA. 54–60s (6s)
// ───────────────────────────────────────────────────────────────────────────
function Scene8CTA() {
  const { localTime } = useSprite();

  const logoT = clamp((localTime - 0.2) / 0.7, 0, 1);
  const logoE = Easing.easeOutBack(logoT);
  const taglineT = clamp((localTime - 0.9) / 0.6, 0, 1);
  const subT = clamp((localTime - 1.7) / 0.6, 0, 1);
  const ctaT = clamp((localTime - 2.4) / 0.6, 0, 1);
  const metaT = clamp((localTime - 3.2) / 0.6, 0, 1);

  // CTA breathes
  const breathe = 1 + 0.02 * Math.sin(localTime * 2.0);

  return (
    <div style={{ position: 'absolute', inset: 0 }}>
      <StageBg mask="radial-gradient(circle at 50% 40%, black, transparent 80%)" />

      {/* Amber radial behind logo */}
      <div style={{
        position: 'absolute',
        left: '50%', top: 330,
        transform: 'translate(-50%, -50%)',
        width: 1400, height: 1400,
        background: 'radial-gradient(circle, rgba(245,158,11,0.18), transparent 55%)',
        opacity: logoT,
        pointerEvents: 'none'
      }} />

      {/* Logo */}
      <div style={{
        position: 'absolute',
        left: '50%', top: 260,
        transform: `translate(-50%, 0) scale(${0.7 + logoE * 0.3})`,
        opacity: logoT
      }}>
        <OFLogo size={150} />
      </div>

      {/* Tagline */}
      <div style={{
        position: 'absolute',
        left: '50%', top: 480,
        transform: `translate(-50%, ${(1 - taglineT) * 18}px)`,
        opacity: taglineT,
        textAlign: 'center',
        fontFamily: ofTokens.fCal,
        fontWeight: 700,
        fontSize: 96,
        lineHeight: 1.0,
        letterSpacing: '-0.04em',
        color: ofTokens.ink900
      }}>
        From raw data to <span style={{
          background: `linear-gradient(90deg, ${ofTokens.amber600}, ${ofTokens.amber500}, ${ofTokens.amber600})`,
          WebkitBackgroundClip: 'text', backgroundClip: 'text', color: 'transparent'
        }}>clean dashboards.</span>
      </div>

      {/* Sub */}
      <div style={{
        position: 'absolute',
        left: '50%', top: 700,
        transform: 'translate(-50%, 0)',
        opacity: subT,
        textAlign: 'center',
        fontFamily: ofTokens.fBody,
        fontSize: 28,
        color: ofTokens.ink700,
        letterSpacing: '-0.01em'
      }}>
        The AI data platform for growing companies.
      </div>

      {/* URL / meta */}
      <div style={{
        position: 'absolute',
        left: '50%', top: 840,
        transform: 'translate(-50%, 0)',
        opacity: metaT,
        textAlign: 'center',
        fontFamily: ofTokens.fMono,
        fontSize: 20,
        letterSpacing: '0.12em',
        textTransform: 'uppercase',
        color: ofTokens.ink400
      }}>
        optimaflo.io   ·   Now in early beta
      </div>
    </div>);

}

// ───────────────────────────────────────────────────────────────────────────
// MAIN COMPOSITION
// ───────────────────────────────────────────────────────────────────────────
function Composition() {
  const t = useTime();
  // Update screen label for comment context (per second)
  React.useEffect(() => {
    const sec = Math.floor(t);
    const root = document.querySelector('[data-video-root]');
    if (root) root.setAttribute('data-screen-label', `t=${sec}s`);
  }, [Math.floor(t)]);

  return (
    <React.Fragment>
      <Sprite start={0} end={6}>  <Scene1Chaos />          </Sprite>
      <Sprite start={6} end={12}> <Scene2Cost />           </Sprite>
      <Sprite start={12} end={18}> <Scene3Intro />          </Sprite>
      <Sprite start={18} end={30}> <Scene4PromptPipeline /> </Sprite>
      <Sprite start={30} end={38}> <Scene5Dashboard />      </Sprite>
      <Sprite start={38} end={46}> <Scene6Trust />          </Sprite>
      <Sprite start={46} end={54}> <Scene7Savings />        </Sprite>
      <Sprite start={54} end={60}> <Scene8CTA />            </Sprite>
    </React.Fragment>);

}

// Export
Object.assign(window, {
  Composition, ofTokens,
  Scene1Chaos, Scene2Cost, Scene3Intro,
  Scene4PromptPipeline, Scene5Dashboard,
  Scene6Trust, Scene7Savings, Scene8CTA
});