/* global React, ProofExplainer */
const { useEffect, useState, useRef, useMemo } = React;
const { T, FONT_MONO, FONT_SANS } = window.ProofExplainer;

// =============================================================
// Time engine
// =============================================================
function useTimeline(totalMs, seed) {
  const [t, setT] = useState(0);
  useEffect(() => {
    setT(0);
    let raf;
    let start = null;
    const tick = (ts) => {
      if (start === null) start = ts;
      const elapsed = ts - start;
      setT(elapsed);
      if (elapsed < totalMs + 500) raf = requestAnimationFrame(tick);
    };
    raf = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(raf);
  }, [seed, totalMs]);
  return t;
}

// progress 0..1 between from and to
const p01 = (t, from, to) => {
  if (t <= from) return 0;
  if (t >= to) return 1;
  return (t - from) / (to - from);
};
// 0..1 visible window with fade in/out
const fade = (t, from, to, fadeIn = 250, fadeOut = 250) => {
  if (t < from) return 0;
  if (t < from + fadeIn) return (t - from) / fadeIn;
  if (t < to - fadeOut) return 1;
  if (t < to) return (to - t) / fadeOut;
  return 0;
};
const lerp = (a, b, t) => a + (b - a) * t;
const eOut = (t) => 1 - Math.pow(1 - t, 3);
const eInOut = (t) => (t < 0.5 ? 2 * t * t : 1 - Math.pow(-2 * t + 2, 2) / 2);

// =============================================================
// Beat schedule (ms)
// =============================================================
const B = {
  PROMPT_OPEN: 300,
  PROMPT_TYPED: 3400,
  PROMPT_FLY: 3650,
  SANDBOX_OPEN: 4450,
  PI_RECEIVE: 6200,
  TERM_START: 6900,
  TERM_END: 15000,
  BROWSER_OPEN: 10200,
  BROWSER_LOADED: 12600,
  SANDBOX_COMPRESS: 17600,
  TIMELINE_HOLD: 19400,
  SPLIT_START: 21400,
  TRANSCRIPT_LAND: 24300,
  VIDEO_LAND: 24300,
  NARRATE_RENDER: 25800,
  VOICE_FLY: 28400,
  VDB_COMPOSE: 29600,
  STREAM_OPEN: 32200,
  SUMMARY_IN: 34000,
  END: 36000,
};

// =============================================================
// Color & icon helpers (placeholder marks, not real logos)
// =============================================================
function ModalMark({ size = 22 }) {
  const s = size;
  return (
    <svg
      width={s}
      height={s}
      viewBox="0 0 24 24"
      style={{ flexShrink: 0, borderRadius: 4, display: "block" }}
      aria-label="Modal"
    >
      <rect width="24" height="24" rx="5" fill="#0d1117" />
      <path d="M4.4 17.8V6.2l4.3 2.5v6.6l-4.3 2.5Z" fill="#7FEE64" />
      <path d="M9.85 15.05V8.95L12 10.2l2.15-1.25v6.1L12 16.3l-2.15-1.25Z" fill="#98F77C" />
      <path d="M15.3 15.3V8.7l4.3-2.5v11.6l-4.3-2.5Z" fill="#55D94A" />
    </svg>
  );
}
function PiLogoMark({ size = 22 }) {
  return (
    <span
      style={{
        width: size,
        height: size,
        borderRadius: 5,
        background: T.blue + "22",
        border: `1px solid ${T.blue}66`,
        display: "inline-flex",
        alignItems: "center",
        justifyContent: "center",
        flexShrink: 0,
      }}
    >
      <img src="logos/pi-logo.svg" alt="Pi" width={size * 0.62} height={size * 0.62} style={{ display: "block" }} />
    </span>
  );
}
function PiMark({ size = 22, accent = T.blue }) {
  return (
    <div
      style={{
        width: size,
        height: size,
        borderRadius: 5,
        background: accent + "22",
        border: `1px solid ${accent}66`,
        display: "flex",
        alignItems: "center",
        justifyContent: "center",
        color: accent,
        fontFamily: FONT_MONO,
        fontWeight: 800,
        fontSize: size * 0.6,
        flexShrink: 0,
      }}
    >
      π
    </div>
  );
}
function ElevenMark({ size = 22 }) {
  return (
    <img
      src="https://11labs-nonprd-15f22c1d.s3.eu-west-3.amazonaws.com/a2ea339b-8b5e-41bb-b706-24eda8a4c9e3/elevenlabs-symbol.svg"
      alt="ElevenLabs"
      width={size}
      height={size}
      style={{
        width: size,
        height: size,
        flexShrink: 0,
        objectFit: "contain",
        filter: "invert(1)",
      }}
    />
  );
}
function VdbMark({ size = 22 }) {
  return (
    <img
      src="logos/videodb-favicon.svg"
      alt="VideoDB"
      width={size}
      height={size}
      style={{
        width: size,
        height: size,
        flexShrink: 0,
        borderRadius: 4,
        objectFit: "contain",
      }}
    />
  );
}
function LlmMark({ size = 22 }) {
  return (
    <img
      src="logos/openai-2025-alt.svg"
      alt="OpenAI"
      width={size}
      height={size}
      style={{
        width: size,
        height: size,
        flexShrink: 0,
        borderRadius: 999,
        objectFit: "contain",
      }}
    />
  );
}

// little reusable: window chrome dots
function ChromeDots() {
  return (
    <div style={{ display: "flex", gap: 5 }}>
      <span style={{ width: 9, height: 9, borderRadius: 999, background: "#ff5f57" }} />
      <span style={{ width: 9, height: 9, borderRadius: 999, background: "#febc2e" }} />
      <span style={{ width: 9, height: 9, borderRadius: 999, background: "#28c940" }} />
    </div>
  );
}

const PROMPT_TEXT = "Run cypress smoke test on this repo";

// =============================================================
// SCENE 1 — Prompt window (center) → morphs into a packet
// =============================================================
function PromptScene({ t }) {
  const opacity = fade(t, 0, B.SANDBOX_OPEN + 200, 300, 200);
  if (opacity <= 0) return null;

  // typing
  const typedTo = Math.min(
    PROMPT_TEXT.length,
    Math.floor(p01(t, B.PROMPT_OPEN, B.PROMPT_TYPED) * PROMPT_TEXT.length)
  );
  const typed = PROMPT_TEXT.slice(0, typedTo);
  const showCaret = t < B.PROMPT_TYPED + 200;

  // morph: when flying, the window shrinks and slides to top-left into sandbox header
  const flyP = eInOut(p01(t, B.PROMPT_FLY, B.PI_RECEIVE));
  const fromW = 560, fromH = 180, fromX = (1320 - fromW) / 2, fromY = 120;
  const toW = 220, toH = 36, toX = 110, toY = 92;
  const w = lerp(fromW, toW, flyP);
  const h = lerp(fromH, toH, flyP);
  const x = lerp(fromX, toX, flyP);
  const y = lerp(fromY, toY, flyP);
  const padding = lerp(20, 6, flyP);
  const radius = lerp(12, 999, flyP);
  const showLabels = flyP < 0.4;
  const fontSize = lerp(15, 11, flyP);

  return (
    <div
      style={{
        position: "absolute",
        left: x,
        top: y,
        width: w,
        height: h,
        background: T.panel,
        border: `1px solid ${flyP > 0.5 ? T.green + "88" : T.border}`,
        borderRadius: radius,
        boxShadow: flyP > 0.5
          ? `0 0 0 4px ${T.green}11, 0 0 24px ${T.green}33`
          : "0 12px 40px rgba(0,0,0,0.5)",
        opacity,
        padding,
        transition: "border-color 200ms ease",
        overflow: "hidden",
        display: "flex",
        flexDirection: flyP > 0.5 ? "row" : "column",
        gap: flyP > 0.5 ? 8 : 12,
        alignItems: flyP > 0.5 ? "center" : "stretch",
      }}
    >
      {showLabels && (
        <div
          style={{
            display: "flex",
            alignItems: "center",
            justifyContent: "space-between",
            opacity: 1 - flyP * 2,
          }}
        >
          <div
            style={{
              fontFamily: FONT_MONO,
              fontSize: 11,
              letterSpacing: 1.6,
              color: T.textMuted,
              textTransform: "uppercase",
              display: "flex",
              alignItems: "center",
              gap: 8,
            }}
          >
            <span
              style={{
                width: 6,
                height: 6,
                borderRadius: 999,
                background: T.green,
                boxShadow: `0 0 8px ${T.green}`,
              }}
            />
            01 · prompt
          </div>
          <span
            style={{
              fontFamily: FONT_MONO,
              fontSize: 10,
              color: T.textMuted,
              letterSpacing: 1,
            }}
          >
            user request
          </span>
        </div>
      )}
      <div
        style={{
          flex: 1,
          background: flyP > 0.5 ? "transparent" : T.bgDeep,
          border: flyP > 0.5 ? "none" : `1px solid ${T.borderSoft}`,
          borderRadius: lerp(8, 999, flyP),
          padding: flyP > 0.5 ? "0 4px" : "14px 16px",
          display: "flex",
          alignItems: "center",
          gap: 10,
          minHeight: 0,
        }}
      >
        <span style={{ color: T.green, fontFamily: FONT_MONO, fontSize, opacity: 0.9 }}>
          ❯
        </span>
        <span
          style={{
            color: T.text,
            fontFamily: FONT_MONO,
            fontSize,
            flex: 1,
            whiteSpace: "nowrap",
            overflow: "hidden",
            textOverflow: "ellipsis",
          }}
        >
          {typed}
          {showCaret && flyP < 0.3 && (
            <span
              style={{
                display: "inline-block",
                width: 8,
                height: fontSize,
                background: T.green,
                marginLeft: 2,
                transform: "translateY(2px)",
                animation: "caretBlink 900ms steps(2) infinite",
              }}
            />
          )}
        </span>
      </div>
    </div>
  );
}

// =============================================================
// SCENE 2 — Sandbox window (Modal-themed) opens, hosts Pi + Browser
// =============================================================
const TERM_LINES = [
  { c: T.textMuted, prefix: "$", body: "git clone github.com/repo.git" },
  { c: T.green,     prefix: "✓", body: "cloned 142 files · 2.1s" },
  { c: T.textMuted, prefix: "$", body: "npm install" },
  { c: T.green,     prefix: "✓", body: "deps installed · 14.2s" },
  { c: T.textMuted, prefix: "$", body: "npm run dev" },
  { c: T.green,     prefix: "✓", body: "vite ready · localhost:5173" },
  { c: T.textMuted, prefix: "$", body: "cypress run --headed smoke" },
  { c: T.green,     prefix: "✓", body: "3 specs passed · 0 failed" },
  { c: T.textMuted, prefix: "$", body: "open chrome localhost:5173" },
];

function SandboxScene({ t }) {
  const opacity = fade(t, B.SANDBOX_OPEN, B.SANDBOX_COMPRESS + 200, 350, 200);
  if (opacity <= 0) return null;

  // open animation: scale up from center
  const openP = eOut(p01(t, B.SANDBOX_OPEN, B.SANDBOX_OPEN + 700));
  const scale = lerp(0.85, 1, openP);
  const op = openP * opacity;

  // visible REC during recording
  const rec = t > B.PI_RECEIVE && t < B.SANDBOX_COMPRESS;
  const recSecs = Math.max(0, Math.floor((Math.min(t, B.SANDBOX_COMPRESS) - B.TERM_START) / 800));
  const recLabel = `00:${String(Math.min(recSecs, 14)).padStart(2, "0")}`;

  // terminal lines reveal
  const termP = p01(t, B.TERM_START, B.TERM_END);
  const lineCount = Math.floor(termP * TERM_LINES.length);

  // browser slide-in
  const browserP = eOut(p01(t, B.BROWSER_OPEN, B.BROWSER_OPEN + 700));
  const browserAppLoaded = t > B.BROWSER_LOADED;

  return (
    <div
      style={{
        position: "absolute",
        left: 60,
        top: 52,
        width: 1200,
        height: 392,
        background: T.panel,
        border: `1px solid ${T.border}`,
        borderRadius: 12,
        boxShadow: "0 24px 60px rgba(0,0,0,0.55)",
        opacity: op,
        transform: `scale(${scale})`,
        transformOrigin: "center",
        overflow: "hidden",
      }}
    >
      {/* sandbox header */}
      <div
        style={{
          height: 48,
          padding: "0 16px",
          background: T.panel2,
          borderBottom: `1px solid ${T.borderSoft}`,
          display: "flex",
          alignItems: "center",
          justifyContent: "space-between",
        }}
      >
        <div style={{ display: "flex", alignItems: "center", gap: 12 }}>
          <ChromeDots />
          <ModalMark size={20} />
          <span
            style={{
              fontFamily: FONT_MONO,
              fontSize: 12,
              fontWeight: 700,
              color: T.text,
              letterSpacing: 1.2,
            }}
          >
            MODAL
          </span>
          <span style={{ color: T.textDim, fontFamily: FONT_MONO, fontSize: 12 }}>·</span>
          <span style={{ color: T.textMuted, fontFamily: FONT_MONO, fontSize: 12 }}>
            sandbox · ephemeral
          </span>
        </div>
        <div style={{ display: "flex", alignItems: "center", gap: 12 }}>
          {/* RecBadge */}
          <div
            style={{
              display: "inline-flex",
              alignItems: "center",
              gap: 6,
              padding: "3px 9px",
              borderRadius: 999,
              background: rec ? "#f8514922" : "transparent",
              border: `1px solid ${rec ? T.red + "66" : T.borderSoft}`,
              fontFamily: FONT_MONO,
              fontSize: 10,
              letterSpacing: 1,
              color: rec ? T.red : T.textDim,
              transition: "all 300ms",
            }}
          >
            <span
              style={{
                width: 7,
                height: 7,
                borderRadius: 999,
                background: rec ? T.red : T.textDim,
                animation: rec ? "recPulse 1.2s ease-in-out infinite" : "none",
              }}
            />
            REC · {rec ? recLabel : "00:00"}
          </div>
        </div>
      </div>

      {/* body — split panels */}
      <div style={{ display: "flex", height: "calc(100% - 48px)" }}>
        {/* PI TERMINAL panel */}
        <div
          style={{
            width: "50%",
            borderRight: `1px solid ${T.borderSoft}`,
            display: "flex",
            flexDirection: "column",
            background: T.bg,
          }}
        >
          <div
            style={{
              height: 34,
              padding: "0 14px",
              borderBottom: `1px solid ${T.borderSoft}`,
              display: "flex",
              alignItems: "center",
              gap: 10,
              background: T.panel,
            }}
          >
            <PiMark size={18} accent={T.blue} />
            <span
              style={{
                fontFamily: FONT_MONO,
                fontSize: 11,
                color: T.text,
                letterSpacing: 1.2,
                fontWeight: 700,
              }}
            >
              PI
            </span>
            <span style={{ color: T.textDim, fontFamily: FONT_MONO, fontSize: 11 }}>·</span>
            <span style={{ color: T.textMuted, fontFamily: FONT_MONO, fontSize: 11 }}>
              agent · session 7e2
            </span>
          </div>
          <div
            style={{
              flex: 1,
              padding: "12px 14px",
              fontFamily: FONT_MONO,
              fontSize: 11.5,
              lineHeight: "17px",
              overflow: "hidden",
              display: "flex",
              flexDirection: "column",
              gap: 3,
            }}
          >
            {/* prompt as user message inside terminal */}
            {t > B.PI_RECEIVE && (
              <div
                style={{
                  background: T.blue + "12",
                  border: `1px solid ${T.blue}33`,
                  borderRadius: 6,
                  padding: "5px 9px",
                  marginBottom: 6,
                  color: T.text,
                  display: "flex",
                  gap: 7,
                  animation: "fadeUp 320ms ease both",
                }}
              >
                <span style={{ color: T.blue, opacity: 0.9 }}>›</span>
                <span>{PROMPT_TEXT}</span>
              </div>
            )}
            {TERM_LINES.slice(0, lineCount).map((l, i) => (
              <div
                key={i}
                style={{
                  display: "flex",
                  gap: 8,
                  animation: "fadeUp 320ms ease both",
                }}
              >
                <span style={{ color: l.c, width: 10 }}>{l.prefix}</span>
                <span style={{ color: T.text, opacity: 0.92 }}>{l.body}</span>
              </div>
            ))}
            {t > B.TERM_START && lineCount < TERM_LINES.length && (
              <div style={{ display: "flex", gap: 8, color: T.textMuted }}>
                <span>·</span>
                <span>
                  pi <CaretInline />
                </span>
              </div>
            )}
          </div>
        </div>

        {/* BROWSER panel */}
        <div
          style={{
            width: "50%",
            display: "flex",
            flexDirection: "column",
            background: T.bgDeep,
            transform: `translateX(${(1 - browserP) * 100}%)`,
            opacity: browserP,
            transition: "none",
          }}
        >
          <div
            style={{
              height: 34,
              padding: "0 14px",
              borderBottom: `1px solid ${T.borderSoft}`,
              display: "flex",
              alignItems: "center",
              gap: 10,
              background: T.panel,
            }}
          >
            <div style={{ display: "flex", gap: 6 }}>
              <span style={{ width: 14, height: 14, borderRadius: 3, border: `1px solid ${T.border}` }} />
              <span style={{ width: 14, height: 14, borderRadius: 3, border: `1px solid ${T.border}` }} />
            </div>
            <div
              style={{
                flex: 1,
                background: T.bgDeep,
                border: `1px solid ${T.borderSoft}`,
                borderRadius: 999,
                padding: "3px 12px",
                fontFamily: FONT_MONO,
                fontSize: 11,
                color: T.textMuted,
                display: "flex",
                alignItems: "center",
                gap: 8,
              }}
            >
              <span style={{ color: T.green }}>●</span>
              localhost:5173
            </div>
          </div>
          <div style={{ flex: 1, padding: 16, position: "relative" }}>
            {!browserAppLoaded ? (
              <div
                style={{
                  display: "flex",
                  alignItems: "center",
                  gap: 10,
                  color: T.textMuted,
                  fontFamily: FONT_MONO,
                  fontSize: 11,
                }}
              >
                <span
                  style={{
                    width: 10,
                    height: 10,
                    borderRadius: 999,
                    border: `2px solid ${T.green}`,
                    borderTopColor: "transparent",
                    animation: "spin 800ms linear infinite",
                  }}
                />
                booting dev server…
              </div>
            ) : (
              <BrowserMock />
            )}
          </div>
        </div>
      </div>
    </div>
  );
}

function CaretInline() {
  return (
    <span
      style={{
        display: "inline-block",
        width: 7,
        height: 12,
        background: T.green,
        marginLeft: 2,
        transform: "translateY(2px)",
        animation: "caretBlink 900ms steps(2) infinite",
      }}
    />
  );
}

function BrowserMock() {
  // tiny dashboard mock
  return (
    <div style={{ display: "flex", flexDirection: "column", gap: 10 }}>
      <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center" }}>
        <div
          style={{
            fontFamily: FONT_SANS,
            fontWeight: 700,
            color: T.text,
            fontSize: 14,
          }}
        >
          Acme Dashboard
        </div>
        <div style={{ display: "flex", gap: 6 }}>
          <span style={{ width: 22, height: 22, borderRadius: 999, background: T.borderSoft }} />
          <span style={{ width: 56, height: 22, borderRadius: 6, background: T.green }} />
        </div>
      </div>
      <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr 1fr", gap: 8 }}>
        {[T.green, T.blue, T.purple].map((c, i) => (
          <div
            key={i}
            style={{
              height: 56,
              borderRadius: 8,
              background: T.panel,
              border: `1px solid ${T.borderSoft}`,
              padding: 10,
              animation: `fadeUp 360ms ease both`,
              animationDelay: `${i * 80}ms`,
            }}
          >
            <div
              style={{
                width: 18,
                height: 4,
                background: c,
                borderRadius: 2,
                marginBottom: 8,
              }}
            />
            <div
              style={{
                width: 38,
                height: 14,
                background: T.borderSoft,
                borderRadius: 3,
              }}
            />
          </div>
        ))}
      </div>
      <div
        style={{
          height: 86,
          borderRadius: 8,
          background: T.panel,
          border: `1px solid ${T.borderSoft}`,
          padding: 10,
          position: "relative",
          overflow: "hidden",
        }}
      >
        {/* fake chart bars */}
        <div style={{ display: "flex", alignItems: "flex-end", gap: 4, height: "100%" }}>
          {[40, 60, 35, 80, 55, 90, 70, 50, 75, 95, 65, 85].map((h, i) => (
            <span
              key={i}
              style={{
                flex: 1,
                background: T.green,
                opacity: 0.5 + (i / 24),
                height: `${h}%`,
                borderRadius: 2,
                animation: `growBar 500ms ease both`,
                animationDelay: `${i * 30}ms`,
                transformOrigin: "bottom",
              }}
            />
          ))}
        </div>
      </div>
    </div>
  );
}

// =============================================================
// SCENE 3 — Recording compresses into a Timeline strip
// =============================================================
function TimelineScene({ t }) {
  const opacity = fade(t, B.SANDBOX_COMPRESS - 100, B.SPLIT_START + 1500, 350, 350);
  if (opacity <= 0) return null;

  const compressP = eInOut(p01(t, B.SANDBOX_COMPRESS, B.SANDBOX_COMPRESS + 1000));
  const playP = p01(t, B.TIMELINE_HOLD, B.SPLIT_START + 1200);

  // height interpolates from sandbox-tall to thin timeline
  const h = lerp(392, 96, compressP);
  const top = lerp(52, 195, compressP);
  const w = 1200;

  return (
    <div
      style={{
        position: "absolute",
        left: 60,
        top,
        width: w,
        height: h,
        background: T.panel,
        border: `1px solid ${T.border}`,
        borderRadius: 12,
        opacity,
        overflow: "hidden",
        boxShadow: "0 18px 50px rgba(0,0,0,0.45)",
      }}
    >
      <div
        style={{
          height: 32,
          padding: "0 14px",
          borderBottom: `1px solid ${T.borderSoft}`,
          background: T.panel2,
          display: "flex",
          alignItems: "center",
          justifyContent: "space-between",
          fontFamily: FONT_MONO,
          fontSize: 11,
        }}
      >
        <span
          style={{
            color: T.text,
            letterSpacing: 1.2,
            fontWeight: 700,
            display: "flex",
            alignItems: "center",
            gap: 8,
          }}
        >
          <span style={{ width: 7, height: 7, borderRadius: 1, background: T.green }} />
          recording.timeline
        </span>
        <span style={{ color: T.textMuted, letterSpacing: 0.8 }}>
          duration · 00:14 · 720p
        </span>
      </div>
      <div style={{ padding: "10px 14px", height: "calc(100% - 32px)" }}>
        {/* faux frames */}
        <div
          style={{
            display: "flex",
            gap: 4,
            height: 30,
            marginBottom: 6,
          }}
        >
          {Array.from({ length: 28 }).map((_, i) => (
            <div
              key={i}
              style={{
                flex: 1,
                background: `linear-gradient(135deg, ${T.panel2}, ${T.bgDeep})`,
                border: `1px solid ${T.borderSoft}`,
                borderRadius: 2,
                opacity: 0.7 + (i % 4) * 0.05,
              }}
            />
          ))}
        </div>
        {/* scrubber */}
        <div style={{ position: "relative", height: 14 }}>
          <div
            style={{
              position: "absolute",
              left: 0,
              right: 0,
              top: 6,
              height: 2,
              background: T.borderSoft,
              borderRadius: 999,
            }}
          />
          <div
            style={{
              position: "absolute",
              left: 0,
              top: 6,
              height: 2,
              width: `${playP * 100}%`,
              background: T.green,
              borderRadius: 999,
              boxShadow: `0 0 10px ${T.green}88`,
            }}
          />
          <div
            style={{
              position: "absolute",
              left: `${playP * 100}%`,
              top: 0,
              transform: "translateX(-50%)",
              width: 14,
              height: 14,
              borderRadius: 999,
              background: T.green,
              boxShadow: `0 0 12px ${T.green}`,
            }}
          />
        </div>
        <div
          style={{
            display: "flex",
            justifyContent: "space-between",
            marginTop: 4,
            fontFamily: FONT_MONO,
            fontSize: 9.5,
            color: T.textMuted,
            letterSpacing: 0.6,
          }}
        >
          {["00:00", "00:03", "00:06", "00:09", "00:12", "00:14"].map((s) => (
            <span key={s}>{s}</span>
          ))}
        </div>
      </div>
    </div>
  );
}

// =============================================================
// SCENE 4 — Distribution: video → VideoDB, transcript → Narrate, voice → VideoDB
// =============================================================

function VideoDbCard({ t }) {
  const opacity = fade(t, B.SPLIT_START - 200, B.END, 350, 0);
  if (opacity <= 0) return null;

  const videoIn = t > B.VIDEO_LAND;
  const voiceIn = t > B.VOICE_FLY + 600;
  const composeP = p01(t, B.VDB_COMPOSE, B.STREAM_OPEN);
  const ready = t > B.STREAM_OPEN;

  return (
    <div
      style={{
        position: "absolute",
        left: 720,
        top: 100,
        width: 280,
        height: 196,
        background: T.panel,
        border: `1px solid ${ready ? T.green + "66" : T.orange + "55"}`,
        borderRadius: 12,
        boxShadow: ready
          ? `0 0 0 4px ${T.green}11, 0 0 28px ${T.green}33`
          : `0 0 22px ${T.orange}22`,
        opacity,
        padding: "12px 14px",
        transition: "border-color 400ms, box-shadow 400ms",
      }}
    >
      <div style={{ display: "flex", alignItems: "center", gap: 8, marginBottom: 8 }}>
        <VdbMark size={22} />
        <span
          style={{
            fontFamily: FONT_MONO,
            fontWeight: 700,
            fontSize: 12,
            color: T.text,
            letterSpacing: 1.2,
          }}
        >
          VIDEODB
        </span>
        <span style={{ color: T.textDim, fontFamily: FONT_MONO, fontSize: 11 }}>·</span>
        <span
          style={{
            color: T.textMuted,
            fontFamily: FONT_MONO,
            fontSize: 11,
          }}
        >
          media index
        </span>
      </div>
      <div
        style={{
          background: T.bgDeep,
          border: `1px solid ${T.borderSoft}`,
          borderRadius: 8,
          padding: "10px 12px",
          display: "flex",
          flexDirection: "column",
          gap: 8,
        }}
      >
        <Asset label="video + voice" sub="assets received" arrived={videoIn && voiceIn} tint={T.blue} />
        <Asset label="stream URL" sub="playable record" arrived={ready} tint={T.orange} />
        <div style={{ marginTop: 4 }}>
          <div
            style={{
              fontFamily: FONT_MONO,
              fontSize: 10,
              color: T.textMuted,
              display: "flex",
              justifyContent: "space-between",
              marginBottom: 4,
            }}
          >
            <span>composing</span>
            <span style={{ color: ready ? T.green : T.orange }}>
              {ready ? "ready" : `${Math.round(composeP * 100)}%`}
            </span>
          </div>
          <div
            style={{
              height: 4,
              borderRadius: 999,
              background: T.borderSoft,
              overflow: "hidden",
            }}
          >
            <div
              style={{
                height: "100%",
                width: `${composeP * 100}%`,
                background: ready ? T.green : T.orange,
                boxShadow: `0 0 10px ${ready ? T.green : T.orange}88`,
              }}
            />
          </div>
        </div>
      </div>
    </div>
  );
}

function Asset({ label, sub, arrived, tint }) {
  return (
    <div
      style={{
        display: "flex",
        alignItems: "center",
        justifyContent: "space-between",
        fontFamily: FONT_MONO,
        fontSize: 11,
        opacity: arrived ? 1 : 0.3,
        transition: "opacity 400ms ease",
      }}
    >
      <span style={{ display: "flex", alignItems: "center", gap: 8 }}>
        <span
          style={{
            width: 8,
            height: 8,
            borderRadius: 2,
            background: arrived ? tint : T.textDim,
            boxShadow: arrived ? `0 0 8px ${tint}aa` : "none",
            transition: "all 400ms",
          }}
        />
        <span style={{ color: T.text }}>{label}</span>
      </span>
      <span style={{ color: T.textMuted }}>{sub}</span>
    </div>
  );
}

function NarrateCard({ t }) {
  const opacity = fade(t, B.SPLIT_START - 200, B.STREAM_OPEN + 600, 350, 350);
  if (opacity <= 0) return null;

  const transcriptIn = t > B.TRANSCRIPT_LAND;
  const scriptReady = t > B.NARRATE_RENDER;
  const voiceReady = t > B.VOICE_FLY;
  const rendering = scriptReady && !voiceReady;

  return (
    <div
      style={{
        position: "absolute",
        left: 88,
        top: 24,
        width: 348,
        height: 176,
        background: T.panel,
        border: `1px solid ${rendering || voiceReady ? T.purple + "55" : T.border}`,
        borderRadius: 12,
        boxShadow: rendering || voiceReady ? `0 0 24px ${T.purple}22` : "none",
        opacity,
        padding: "12px 14px",
        transition: "border-color 400ms, box-shadow 400ms",
      }}
    >
      <div style={{ display: "flex", alignItems: "center", gap: 8, marginBottom: 10 }}>
        <span
          style={{
            fontFamily: FONT_MONO,
            fontWeight: 700,
            fontSize: 12,
            color: T.text,
            letterSpacing: 1.2,
          }}
        >
          NARRATION PATH
        </span>
        <span style={{ color: T.textDim, fontFamily: FONT_MONO, fontSize: 11 }}>·</span>

      </div>
      <div
        style={{
          display: "grid",
          gridTemplateColumns: "1fr 18px 1fr",
          gap: 8,
          alignItems: "stretch",
        }}
      >
        <NarrationMiniPanel
          title="LLM"
          sub="writes script"
          active={transcriptIn && !voiceReady}
          ready={scriptReady}
          tint={T.purple}
          icon={<LlmMark size={22} />}
        >
          <MiniLine tint={scriptReady ? T.green : T.textMuted}>{scriptReady ? "script ready" : transcriptIn ? "writing script" : "waiting"}</MiniLine>
        </NarrationMiniPanel>
        <div
          style={{
            display: "flex",
            alignItems: "center",
            justifyContent: "center",
            color: scriptReady ? T.green : T.textDim,
            fontFamily: FONT_MONO,
            fontSize: 16,
          }}
        >
          →
        </div>
        <NarrationMiniPanel
          title="ElevenLabs"
          sub="voice synthesis"
          active={scriptReady}
          ready={voiceReady}
          tint={T.blue}
          icon={<ElevenMark size={22} />}
        >
          {scriptReady ? <Waveform animated={!voiceReady} /> : <MiniLine tint={T.textMuted}>waiting</MiniLine>}
          {voiceReady ? <MiniLine tint={T.green}>voice ready</MiniLine> : null}
        </NarrationMiniPanel>
      </div>
    </div>
  );
}

function NarrationMiniPanel({ title, sub, active, ready, tint, icon, children }) {
  return (
    <div
      style={{
        background: T.bgDeep,
        border: `1px solid ${active || ready ? tint + "55" : T.borderSoft}`,
        borderRadius: 9,
        padding: "10px 10px 9px",
        minHeight: 104,
        transition: "border-color 400ms ease",
      }}
    >
      <div style={{ display: "flex", alignItems: "center", gap: 8, marginBottom: 8 }}>
        {icon}
        <div style={{ minWidth: 0 }}>
          <div style={{ fontFamily: FONT_MONO, fontSize: 10.5, color: T.text, fontWeight: 700, letterSpacing: 1 }}>
            {title}
          </div>
          <div style={{ fontFamily: FONT_MONO, fontSize: 9.5, color: T.textMuted, marginTop: 2 }}>
            {sub}
          </div>
        </div>
      </div>
      <div style={{ display: "flex", flexDirection: "column", gap: 5 }}>
        {children}
      </div>
    </div>
  );
}

function MiniLine({ children, tint }) {
  return (
    <div style={{ display: "flex", alignItems: "center", gap: 6, fontFamily: FONT_MONO, fontSize: 10.5, color: T.text }}>
      <span style={{ width: 7, height: 7, borderRadius: 2, background: tint, boxShadow: tint === T.textMuted ? "none" : `0 0 8px ${tint}88` }} />
      <span>{children}</span>
    </div>
  );
}

function Waveform({ animated }) {
  const bars = 32;
  return (
    <div style={{ display: "flex", alignItems: "center", gap: 2, marginTop: 6, height: 18 }}>
      {Array.from({ length: bars }).map((_, i) => {
        const h = 4 + (Math.sin(i * 0.7) + 1) * 6 + (i % 4 === 0 ? 4 : 0);
        return (
          <span
            key={i}
            style={{
              width: 2,
              height: h,
              background: T.blue,
              opacity: 0.55 + (i % 3) * 0.15,
              borderRadius: 1,
              animation: animated ? `wf ${800 + i * 33}ms ease-in-out infinite alternate` : "none",
              animationDelay: `${i * 30}ms`,
            }}
          />
        );
      })}
    </div>
  );
}

// flying tokens between scenes
function FlyToken({ t, label, tint, from, to, fromTime, toTime }) {
  if (t < fromTime || t > toTime + 200) return null;
  const p = eInOut(p01(t, fromTime, toTime));
  // straight cubic-ish path (slight arc via control point)
  const cx = (from.x + to.x) / 2;
  const cy = Math.min(from.y, to.y) - 30;
  const x = (1 - p) * (1 - p) * from.x + 2 * (1 - p) * p * cx + p * p * to.x;
  const y = (1 - p) * (1 - p) * from.y + 2 * (1 - p) * p * cy + p * p * to.y;
  const opacity = fade(t, fromTime, toTime + 100, 150, 150);
  return (
    <div
      style={{
        position: "absolute",
        left: x,
        top: y,
        transform: "translate(-50%, -50%)",
        background: T.panel,
        border: `1px solid ${tint}88`,
        boxShadow: `0 0 14px ${tint}66`,
        borderRadius: 999,
        padding: "3px 10px",
        fontFamily: FONT_MONO,
        fontSize: 10.5,
        color: T.text,
        letterSpacing: 0.4,
        opacity,
        display: "flex",
        alignItems: "center",
        gap: 6,
        whiteSpace: "nowrap",
        zIndex: 5,
      }}
    >
      <span
        style={{
          width: 6,
          height: 6,
          borderRadius: 1,
          background: tint,
        }}
      />
      {label}
    </div>
  );
}

// =============================================================
// SCENE 5 — Stream player (final)
// =============================================================
function StreamScene({ t }) {
  const opacity = fade(t, B.STREAM_OPEN, B.END + 100, 400, 0);
  if (opacity <= 0) return null;
  const ready = t > B.STREAM_OPEN + 400;
  const inP = eOut(p01(t, B.STREAM_OPEN, B.STREAM_OPEN + 700));
  return (
    <div
      style={{
        position: "absolute",
        left: 1030,
        top: 80,
        width: 240,
        height: 240,
        opacity: opacity * inP,
        transform: `translateX(${(1 - inP) * 30}px)`,
      }}
    >
      <div
        style={{
          background: T.panel,
          border: `1px solid ${ready ? T.green + "66" : T.borderSoft}`,
          borderRadius: 12,
          padding: 10,
          boxShadow: ready
            ? `0 0 0 4px ${T.green}11, 0 0 32px ${T.green}44`
            : "0 12px 40px rgba(0,0,0,0.5)",
          transition: "border-color 400ms, box-shadow 400ms",
        }}
      >
        <div
          style={{
            position: "relative",
            aspectRatio: "16 / 9",
            background: ready
              ? "linear-gradient(135deg, #0d1f17 0%, #14342a 60%, #0d1f17 100%)"
              : T.bgDeep,
            borderRadius: 8,
            overflow: "hidden",
            border: `1px solid ${ready ? T.green + "55" : T.borderSoft}`,
          }}
        >
          {ready && (
            <div
              style={{
                position: "absolute",
                inset: 0,
                backgroundImage:
                  "repeating-linear-gradient(0deg, rgba(63,185,80,0.04) 0 1px, transparent 1px 3px)",
              }}
            />
          )}
          <div
            style={{
              position: "absolute",
              inset: 0,
              display: "flex",
              alignItems: "center",
              justifyContent: "center",
            }}
          >
            <div
              style={{
                width: 46,
                height: 46,
                borderRadius: 999,
                background: ready ? T.green : T.borderSoft,
                display: "flex",
                alignItems: "center",
                justifyContent: "center",
                boxShadow: ready ? `0 0 24px ${T.green}88` : "none",
                transition: "all 500ms",
              }}
            >
              <span
                style={{
                  width: 0,
                  height: 0,
                  borderLeft: `13px solid ${ready ? T.bg : T.textDim}`,
                  borderTop: "9px solid transparent",
                  borderBottom: "9px solid transparent",
                  marginLeft: 3,
                }}
              />
            </div>
          </div>
          <div
            style={{
              position: "absolute",
              left: 8,
              bottom: 6,
              fontFamily: FONT_MONO,
              fontSize: 10,
              color: ready ? T.green : T.textDim,
              letterSpacing: 0.8,
            }}
          >
            ◉ 00:00 / 00:14
          </div>
          <div
            style={{
              position: "absolute",
              right: 8,
              bottom: 6,
              fontFamily: FONT_MONO,
              fontSize: 10,
              color: ready ? T.green : T.textDim,
              letterSpacing: 0.8,
            }}
          >
            HD
          </div>
        </div>
        <div
          style={{
            marginTop: 10,
            background: T.bgDeep,
            border: `1px solid ${ready ? T.green + "44" : T.borderSoft}`,
            borderRadius: 6,
            padding: "6px 10px",
            display: "flex",
            alignItems: "center",
            justifyContent: "space-between",
            fontFamily: FONT_MONO,
            fontSize: 10.5,
            color: ready ? T.text : T.textMuted,
          }}
        >
          <span>
            stream.videodb.io/run/<span style={{ color: ready ? T.green : T.textMuted }}>a3f9…</span>
          </span>
          <span style={{ color: ready ? T.green : T.textDim }}>⧉</span>
        </div>
        <div
          style={{
            marginTop: 8,
            fontFamily: FONT_MONO,
            fontSize: 10,
            color: T.textMuted,
            display: "flex",
            justifyContent: "space-between",
          }}
        >
          <span>playable evidence</span>
          <span style={{ color: ready ? T.green : T.textMuted }}>
            {ready ? "✓ ready" : "⟂ pending"}
          </span>
        </div>
      </div>
    </div>
  );
}

// =============================================================
// SCENE 6 — Clean final tile state
// =============================================================
const FINAL_TILES = [
  { label: "Modal sandbox", sub: "Agent sandboxing", mark: "modal", tint: T.green, href: "https://modal.com/use-cases/sandboxes" },
  { label: "Pi agent", sub: "AI agent running the task", mark: "pi", tint: T.blue, href: "https://pi.dev/" },
  { label: "LLM", sub: "Writes script", mark: "llm", tint: T.purple, href: "https://openai.com/" },
  { label: "ElevenLabs", sub: "Voiceover generation", mark: "eleven", tint: T.blue, href: "https://elevenlabs.io/" },
  { label: "VideoDB", sub: "Composed media record and stream", mark: "vdb", tint: T.orange, href: "https://videodb.io/" },
];

function FinalTilesScene({ t }) {
  const opacity = fade(t, B.SUMMARY_IN, B.END + 5000, 700, 0);
  if (opacity <= 0) return null;

  return (
    <div
      style={{
        position: "absolute",
        inset: 0,
        opacity,
        background: `linear-gradient(180deg, ${T.bg}f2, ${T.bgDeep}f5)`,
        display: "flex",
        flexDirection: "column",
        alignItems: "center",
        justifyContent: "center",
        gap: 18,
        padding: "28px 44px",
      }}
    >
      <div style={{ width: "100%", maxWidth: 1160 }}>
        <div
          style={{
            fontFamily: FONT_SANS,
            fontSize: 28,
            lineHeight: 1,
            color: T.text,
            fontWeight: 800,
            letterSpacing: -0.5,
            marginBottom: 8,
          }}
        >
          Stack
        </div>
        <div
          style={{
            fontFamily: FONT_MONO,
            fontSize: 10.5,
            color: T.textMuted,
            letterSpacing: 1.2,
            textTransform: "uppercase",
          }}
        >
          The services behind prompt to proof
        </div>
      </div>
      <div
        style={{
          display: "grid",
          gridTemplateColumns: "repeat(5, 1fr)",
          gap: 14,
          width: "100%",
          maxWidth: 1160,
        }}
      >
        {FINAL_TILES.map((node, index) => (
          <FinalTile key={node.label} node={node} index={index} />
        ))}
      </div>
    </div>
  );
}

function FinalTile({ node, index }) {
  return (
    <a
      href={node.href}
      target="_blank"
      rel="noreferrer"
      style={{
        minHeight: 118,
        background: T.panel,
        border: `1px solid ${node.tint}55`,
        borderRadius: 12,
        padding: "18px 18px 16px",
        display: "flex",
        alignItems: "center",
        gap: 15,
        boxShadow: `0 0 0 1px ${T.bgDeep}, 0 18px 44px rgba(0,0,0,0.22)`,
        animation: "fadeUp 420ms ease both",
        animationDelay: `${index * 70}ms`,
        textDecoration: "none",
        transition: "transform 180ms ease, border-color 180ms ease, background 180ms ease",
        cursor: "pointer",
      }}
      onMouseEnter={(e) => {
        e.currentTarget.style.transform = "translateY(-2px)";
        e.currentTarget.style.borderColor = node.tint + "aa";
        e.currentTarget.style.background = T.panel2;
      }}
      onMouseLeave={(e) => {
        e.currentTarget.style.transform = "translateY(0)";
        e.currentTarget.style.borderColor = node.tint + "55";
        e.currentTarget.style.background = T.panel;
      }}
    >
      <div
        style={{
          width: 48,
          height: 48,
          borderRadius: 12,
          background: node.tint + "18",
          border: `1px solid ${node.tint}66`,
          display: "flex",
          alignItems: "center",
          justifyContent: "center",
          color: node.tint,
          fontFamily: FONT_MONO,
          fontSize: 18,
          fontWeight: 800,
          flexShrink: 0,
        }}
      >
        {node.mark === "modal" && <ModalMark size={24} />}
        {node.mark === "pi" && <PiLogoMark size={24} />}
        {node.mark === "vdb" && <VdbMark size={24} />}
        {node.mark === "llm" && <LlmMark size={24} />}
        {node.mark === "eleven" && <ElevenMark size={24} />}
        {!node.mark && node.icon}
      </div>
      <div style={{ minWidth: 0 }}>
        <div
          style={{
            fontFamily: FONT_SANS,
            fontSize: 15,
            lineHeight: 1.1,
            color: T.text,
            fontWeight: 700,
            letterSpacing: -0.1,
          }}
        >
          {node.label}
        </div>
        <div
          style={{
            marginTop: 6,
            fontFamily: FONT_MONO,
            fontSize: 10.5,
            lineHeight: 1.35,
            color: T.textMuted,
            letterSpacing: 0.4,
          }}
        >
          {node.sub}
        </div>
      </div>
    </a>
  );
}

function SummaryNode({ node }) {
  return (
    <div style={{ display: "flex", flexDirection: "column", alignItems: "center", gap: 6, flex: "0 0 auto" }}>
      <div
        style={{
          width: 36,
          height: 36,
          borderRadius: 8,
          background: node.tint + "18",
          border: `1px solid ${node.tint}55`,
          display: "flex",
          alignItems: "center",
          justifyContent: "center",
          color: node.tint,
          fontFamily: FONT_MONO,
          fontSize: 14,
          fontWeight: 700,
        }}
      >
        {node.mark === "modal" && <ModalMark size={18} />}
        {node.mark === "vdb" && <VdbMark size={18} />}
        {node.mark === "narrate" && (
          <div style={{ display: "flex", gap: 2 }}>
            <ElevenMark size={14} />
            <LlmMark size={14} />
          </div>
        )}
        {!node.mark && node.icon}
      </div>
      <div style={{ textAlign: "center" }}>
        <div
          style={{
            fontFamily: FONT_MONO,
            fontSize: 9.5,
            letterSpacing: 1,
            color: T.text,
            fontWeight: 700,
          }}
        >
          {node.label}
        </div>
        <div
          style={{
            fontFamily: FONT_MONO,
            fontSize: 9,
            color: T.textMuted,
            letterSpacing: 0.4,
            marginTop: 1,
          }}
        >
          {node.sub}
        </div>
      </div>
    </div>
  );
}

function SummaryArrow() {
  return (
    <div
      style={{
        flex: 1,
        height: 1,
        background: `repeating-linear-gradient(90deg, ${T.borderSoft} 0 4px, transparent 4px 8px)`,
        position: "relative",
      }}
    >
      <span
        style={{
          position: "absolute",
          right: -4,
          top: -4,
          width: 0,
          height: 0,
          borderLeft: `6px solid ${T.borderSoft}`,
          borderTop: "4px solid transparent",
          borderBottom: "4px solid transparent",
        }}
      />
    </div>
  );
}

function useIsMobileStage() {
  const [isMobile, setIsMobile] = useState(false);
  useEffect(() => {
    const update = () => setIsMobile(window.innerWidth < 640);
    update();
    window.addEventListener("resize", update);
    return () => window.removeEventListener("resize", update);
  }, []);
  return isMobile;
}

function MobileProofStrip() {
  return (
    <section aria-label="Prompt to proof stack" style={{ width: "100%", background: T.bg, padding: "22px 18px 24px" }}>
      <div style={{ display: "grid", gap: 10 }}>
        {FINAL_TILES.map((node, index) => (
          <FinalTile key={node.label} node={node} index={index} />
        ))}
      </div>
    </section>
  );
}

// =============================================================
// MAIN STAGE
// =============================================================
function ProofStrip() {
  const isMobile = useIsMobileStage();
  const t = useTimeline(B.END, 0);
  if (isMobile) return <MobileProofStrip />;

  // token coords (in stage space)
  // sandbox compresses to timeline at y≈195. video token starts mid-timeline (x=660,y=240) → vdb (x=860,y=210)
  // transcript token starts mid-timeline → narrate (x=245,y=115)
  // narration → vdb
  return (
    <section
      aria-label="How a prompt becomes proof"
      style={{
        background: T.bg,
        position: "relative",
        overflow: "hidden",
      }}
    >
      <div
        style={{
          position: "absolute",
          left: "55%",
          top: -80,
          width: 600,
          height: 300,
          background: `radial-gradient(closest-side, ${T.green}11, transparent)`,
          pointerEvents: "none",
        }}
      />
      <div style={{ maxWidth: 1400, margin: "0 auto", padding: "0 40px 32px" }}>
        <ScaledStage designWidth={1320} designHeight={500}>
          <PromptScene t={t} />
          <SandboxScene t={t} />
          <TimelineScene t={t} />
          <NarrateCard t={t} />
          <VideoDbCard t={t} />
          <FlyToken
            t={t}
            label="video.mp4"
            tint={T.green}
            from={{ x: 660, y: 240 }}
            to={{ x: 860, y: 200 }}
            fromTime={B.SPLIT_START}
            toTime={B.VIDEO_LAND}
          />
          <FlyToken
            t={t}
            label="transcript.json"
            tint={T.purple}
            from={{ x: 660, y: 240 }}
            to={{ x: 245, y: 110 }}
            fromTime={B.SPLIT_START}
            toTime={B.TRANSCRIPT_LAND}
          />
          <FlyToken
            t={t}
            label="voiceover.mp3"
            tint={T.blue}
            from={{ x: 350, y: 142 }}
            to={{ x: 860, y: 220 }}
            fromTime={B.VOICE_FLY}
            toTime={B.VOICE_FLY + 1300}
          />
          <StreamScene t={t} />
          <FinalTilesScene t={t} />
        </ScaledStage>
      </div>
    </section>
  );
}

// =============================================================
// ScaledStage — fits a fixed-design canvas to viewport width
// =============================================================
function ScaledStage({ designWidth, designHeight, children }) {
  const wrapRef = useRef(null);
  const [scale, setScale] = useState(1);
  useEffect(() => {
    const el = wrapRef.current;
    if (!el) return;
    const update = () => {
      const w = el.clientWidth;
      setScale(Math.min(1, w / designWidth));
    };
    update();
    const ro = new ResizeObserver(update);
    ro.observe(el);
    return () => ro.disconnect();
  }, [designWidth]);
  return (
    <div
      ref={wrapRef}
      style={{
        position: "relative",
        width: "100%",
        height: designHeight * scale,
        overflow: "visible",
      }}
    >
      <div
        style={{
          position: "absolute",
          top: 0,
          left: 0,
          width: designWidth,
          height: designHeight,
          transform: `scale(${scale})`,
          transformOrigin: "top left",
        }}
      >
        {children}
      </div>
    </div>
  );
}

window.ProofStrip = ProofStrip;
