// scenes.jsx — TBGF Business Exit Trajectory Framework hero video scenes
// 45 seconds total, 1920x1080. Paper-document feel: slow fades, gentle slides.

const COLOURS = {
  bone:    '#FAF8F2',
  azure:   '#1CB4CC',
  navy:    '#0A2E36',
  blue:    '#006FBA',
  mint:    '#ADEBB3',
  slate:   '#6E7E85',
  slate900:'#0A2E36',
  rule:    'rgba(10, 46, 54, 0.14)',
};

const FONT = {
  display: '"Poppins", system-ui, sans-serif',
  body:    '"Poppins", system-ui, sans-serif',
  editorial: '"Roboto Slab", Georgia, serif',
  mono: 'ui-monospace, "JetBrains Mono", monospace',
};

// ────────────────────────────────────────────────────────────────────────────
// Shared helpers

function fadeIn(localTime, start, dur = 0.6, ease = Easing.easeOutCubic) {
  const t = clamp((localTime - start) / dur, 0, 1);
  return ease(t);
}
function fadeOut(localTime, start, dur = 0.6, ease = Easing.easeInCubic) {
  const t = clamp((localTime - start) / dur, 0, 1);
  return 1 - ease(t);
}
function band(localTime, inStart, inDur, outStart, outDur) {
  // returns 0..1 opacity envelope
  if (localTime < inStart) return 0;
  if (localTime < inStart + inDur) return fadeIn(localTime, inStart, inDur);
  if (localTime < outStart) return 1;
  if (localTime < outStart + outDur) return fadeOut(localTime, outStart, outDur);
  return 0;
}

// Lightweight typography token
function H1({ children, style }) {
  return (
    <div style={{
      fontFamily: FONT.display, fontWeight: 700,
      fontSize: 96, lineHeight: 1.05,
      letterSpacing: '-0.025em', color: COLOURS.navy,
      ...style,
    }}>{children}</div>
  );
}
function H2({ children, style }) {
  return (
    <div style={{
      fontFamily: FONT.display, fontWeight: 600,
      fontSize: 64, lineHeight: 1.1,
      letterSpacing: '-0.02em', color: COLOURS.navy,
      ...style,
    }}>{children}</div>
  );
}
function Body({ children, style }) {
  return (
    <div style={{
      fontFamily: FONT.body, fontWeight: 500,
      fontSize: 28, lineHeight: 1.4,
      color: COLOURS.slate, ...style,
    }}>{children}</div>
  );
}
function Eyebrow({ children, style }) {
  return (
    <div style={{
      fontFamily: FONT.display, fontWeight: 600,
      fontSize: 18, lineHeight: 1, textTransform: 'uppercase',
      letterSpacing: '0.22em', color: COLOURS.azure,
      ...style,
    }}>{children}</div>
  );
}

// ────────────────────────────────────────────────────────────────────────────
// SCENE 1 — THE HOOK (0–5s)
// Bone canvas. "You'll sell your business one day." then "The question is, ready or not?"

function SceneHook() {
  return (
    <Sprite start={0} end={5}>
      {({ localTime }) => {
        // Line 1: in 0.6→1.6, hold, fade with whole scene 4.5→5
        const o1 = band(localTime, 0.6, 1.0, 4.5, 0.5);
        const ty1 = (1 - clamp((localTime - 0.6) / 1.0, 0, 1)) * 12;

        // Line 2: in 2.0→3.0, hold, fade 4.5→5
        const o2 = band(localTime, 2.0, 1.0, 4.5, 0.5);
        const ty2 = (1 - clamp((localTime - 2.0) / 1.0, 0, 1)) * 12;

        // Tiny ornamental rule slides in between lines
        const ruleW = clamp((localTime - 1.6) / 0.6, 0, 1) * 64;
        const ruleO = band(localTime, 1.6, 0.6, 4.5, 0.5);

        return (
          <div style={{
            position: 'absolute', inset: 0,
            display: 'flex', flexDirection: 'column',
            alignItems: 'center', justifyContent: 'center',
            paddingBottom: 40,
          }}>
            <H1 style={{
              opacity: o1,
              transform: `translateY(${ty1}px)`,
              textAlign: 'center',
            }}>
              You’ll sell your business one day.
            </H1>

            <div style={{
              width: ruleW, height: 2, background: COLOURS.azure,
              opacity: ruleO, margin: '40px 0 36px',
              transition: 'none',
            }} />

            <H2 style={{
              opacity: o2,
              transform: `translateY(${ty2}px)`,
              color: COLOURS.slate,
              fontWeight: 500,
              fontSize: 48,
              textAlign: 'center',
            }}>
              The question is, ready or not?
            </H2>
          </div>
        );
      }}
    </Sprite>
  );
}

// ────────────────────────────────────────────────────────────────────────────
// SCENE 2 — THE GAP (5–15s)
// Horizontal timeline with two markers and the gap between them.

function SceneGap() {
  return (
    <Sprite start={5} end={15}>
      {({ localTime }) => {
        const lt = localTime; // 0..10

        // Line draws 0.4→1.6 (left to right)
        const lineP = clamp((lt - 0.4) / 1.2, 0, 1);
        const lineEase = Easing.easeInOutCubic(lineP);

        // Marker A appears 1.6→2.2
        const aO = band(lt, 1.6, 0.6, 9.2, 0.6);
        const aS = 0.85 + 0.15 * Easing.easeOutCubic(clamp((lt - 1.6) / 0.6, 0, 1));

        // Marker B appears 2.8→3.4
        const bO = band(lt, 2.8, 0.6, 9.2, 0.6);
        const bS = 0.85 + 0.15 * Easing.easeOutCubic(clamp((lt - 2.8) / 0.6, 0, 1));

        // Gap band highlights 4.0→4.8
        const gapO = band(lt, 4.0, 0.8, 9.2, 0.6) * 0.85;

        // Caption 5.0→6.0, hold, fade 9.2→9.8
        const capO = band(lt, 5.0, 1.0, 9.2, 0.6);
        const capTY = (1 - clamp((lt - 5.0) / 1.0, 0, 1)) * 10;

        // Eyebrow
        const ebO = band(lt, 0.2, 0.6, 9.2, 0.6);

        // Coordinates
        const cx = 1920 / 2;
        const lineY = 480;
        const lineLeft = 280;
        const lineRight = 1920 - 280;
        const lineFullW = lineRight - lineLeft;
        const aX = lineLeft + lineFullW * 0.22;
        const bX = lineLeft + lineFullW * 0.78;

        return (
          <div style={{ position: 'absolute', inset: 0 }}>
            {/* Eyebrow */}
            <div style={{
              position: 'absolute', left: 0, right: 0, top: 180,
              textAlign: 'center', opacity: ebO,
            }}>
              <Eyebrow>The Gap</Eyebrow>
            </div>

            {/* Timeline */}
            <svg
              width="1920" height="1080"
              style={{ position: 'absolute', inset: 0, pointerEvents: 'none' }}
            >
              {/* Base rule (light) */}
              <line
                x1={lineLeft} y1={lineY} x2={lineRight} y2={lineY}
                stroke={COLOURS.rule} strokeWidth="2"
              />
              {/* Drawn rule (navy) */}
              <line
                x1={lineLeft} y1={lineY}
                x2={lineLeft + lineFullW * lineEase} y2={lineY}
                stroke={COLOURS.navy} strokeWidth="3"
                strokeLinecap="round"
              />
              {/* Tick marks at endpoints */}
              <line x1={lineLeft} y1={lineY - 14} x2={lineLeft} y2={lineY + 14}
                    stroke={COLOURS.navy} strokeWidth="2" opacity={lineEase} />
              <line x1={lineRight} y1={lineY - 14} x2={lineRight} y2={lineY + 14}
                    stroke={COLOURS.navy} strokeWidth="2" opacity={lineEase} />

              {/* Gap highlight band between A and B */}
              <rect
                x={aX} y={lineY - 28}
                width={bX - aX} height={56}
                fill={COLOURS.azure} opacity={gapO * 0.18}
                rx="4"
              />
              {/* Gap rule emphasis */}
              <line
                x1={aX} y1={lineY} x2={bX} y2={lineY}
                stroke={COLOURS.azure} strokeWidth="4" opacity={gapO}
                strokeLinecap="round"
              />

              {/* Marker A dot */}
              <circle cx={aX} cy={lineY} r={14 * aS} fill={COLOURS.navy} opacity={aO} />
              {/* Marker B dot */}
              <circle cx={bX} cy={lineY} r={14 * bS} fill={COLOURS.navy} opacity={bO} />

              {/* Gap label centred */}
              <g opacity={gapO}>
                <text
                  x={(aX + bX) / 2} y={lineY - 50}
                  textAnchor="middle"
                  fontFamily="Poppins" fontWeight="600" fontSize="22"
                  fill={COLOURS.azure} letterSpacing="6"
                >THE GAP</text>
              </g>
            </svg>

            {/* Marker A label */}
            <div style={{
              position: 'absolute', left: aX - 220, top: lineY + 40,
              width: 440, textAlign: 'center', opacity: aO,
              transform: `translateY(${(1 - aO) * 8}px)`,
            }}>
              <div style={{
                fontFamily: FONT.display, fontWeight: 600, fontSize: 22,
                color: COLOURS.slate, letterSpacing: '0.12em', textTransform: 'uppercase',
                marginBottom: 10,
              }}>Owner says</div>
              <div style={{
                fontFamily: FONT.display, fontWeight: 700, fontSize: 40,
                color: COLOURS.navy, letterSpacing: '-0.01em',
              }}>2 years out</div>
            </div>

            {/* Marker B label */}
            <div style={{
              position: 'absolute', left: bX - 240, top: lineY + 40,
              width: 480, textAlign: 'center', opacity: bO,
              transform: `translateY(${(1 - bO) * 8}px)`,
            }}>
              <div style={{
                fontFamily: FONT.display, fontWeight: 600, fontSize: 22,
                color: COLOURS.slate, letterSpacing: '0.12em', textTransform: 'uppercase',
                marginBottom: 10,
              }}>Buyer says</div>
              <div style={{
                fontFamily: FONT.display, fontWeight: 700, fontSize: 40,
                color: COLOURS.navy, letterSpacing: '-0.01em',
              }}>5 years from buyable</div>
            </div>

            {/* Caption */}
            <div style={{
              position: 'absolute', left: 0, right: 0, top: 760,
              textAlign: 'center',
              opacity: capO, transform: `translateY(${capTY}px)`,
            }}>
              <div style={{
                fontFamily: FONT.editorial, fontWeight: 400,
                fontStyle: 'italic',
                fontSize: 44, color: COLOURS.navy,
                letterSpacing: '-0.005em',
              }}>
                Most owners discover the gap too late.
              </div>
            </div>
          </div>
        );
      }}
    </Sprite>
  );
}

// ────────────────────────────────────────────────────────────────────────────
// SCENE 3 — THE FRAMEWORK (15–30s)
// Five-stage diagram, left to right. Then "Built by three specialists" + names.

const STAGES = [
  'Entry',
  'Insights Assessment',
  'Diagnostic Report',
  'Program & Specialist Consulting',
  'Sale-Ready',
];

function SceneFramework() {
  return (
    <Sprite start={15} end={30}>
      {({ localTime }) => {
        const lt = localTime; // 0..15

        // Eyebrow + title
        const ebO = band(lt, 0.2, 0.6, 14.0, 1.0);
        const titleO = band(lt, 0.5, 0.8, 14.0, 1.0);

        // Stages reveal sequentially
        const stageStart = 1.6;
        const stagePer   = 1.1;
        const stageOpacities = STAGES.map((_, i) => {
          const s = stageStart + i * stagePer;
          return {
            o: band(lt, s, 0.6, 14.0, 1.0),
            highlight: clamp(1 - (lt - (s + 0.4)) / 0.9, 0, 1) *
                       clamp((lt - s) / 0.3, 0, 1),
            connOpacity: i === 0 ? 0 : band(lt, s - 0.15, 0.5, 14.0, 1.0),
          };
        });

        // Specialists overlay: appears 8.5 → fade out with scene
        const specsO = band(lt, 8.5, 1.0, 14.0, 1.0);

        // Layout for stages (5 cards, centred row)
        const cardW = 296;
        const cardH = 200;
        const gap   = 24;
        const totalW = 5 * cardW + 4 * gap;
        const rowLeft = (1920 - totalW) / 2;
        const rowTop  = 360;

        return (
          <div style={{ position: 'absolute', inset: 0 }}>
            {/* Header */}
            <div style={{ position: 'absolute', top: 150, left: 0, right: 0, textAlign: 'center' }}>
              <div style={{ opacity: ebO, marginBottom: 18 }}>
                <Eyebrow>The Framework</Eyebrow>
              </div>
              <div style={{ opacity: titleO }}>
                <H2 style={{ fontSize: 52, fontWeight: 600 }}>
                  Five stages from where you are to sale-ready.
                </H2>
              </div>
            </div>

            {/* Connector line behind cards */}
            <svg
              width="1920" height="1080"
              style={{ position: 'absolute', inset: 0, pointerEvents: 'none' }}
            >
              {STAGES.slice(0, -1).map((_, i) => {
                const x1 = rowLeft + (i + 1) * cardW + i * gap;
                const x2 = x1 + gap;
                const y  = rowTop + cardH / 2;
                const o  = stageOpacities[i + 1].connOpacity;
                return (
                  <g key={`c${i}`}>
                    <line x1={x1} y1={y} x2={x2} y2={y}
                          stroke={COLOURS.azure} strokeWidth="2" opacity={o} />
                    <polygon
                      points={`${x2 - 6},${y - 5} ${x2},${y} ${x2 - 6},${y + 5}`}
                      fill={COLOURS.azure} opacity={o}
                    />
                  </g>
                );
              })}
            </svg>

            {/* Cards */}
            {STAGES.map((label, i) => {
              const left = rowLeft + i * (cardW + gap);
              const { o, highlight } = stageOpacities[i];
              const ty = (1 - o) * 14;
              const isFinal = i === STAGES.length - 1;
              return (
                <div key={i} style={{
                  position: 'absolute',
                  left, top: rowTop, width: cardW, height: cardH,
                  opacity: o,
                  transform: `translateY(${ty}px)`,
                }}>
                  <div style={{
                    width: '100%', height: '100%',
                    background: COLOURS.bone,
                    border: `1.5px solid ${isFinal ? COLOURS.azure : COLOURS.rule}`,
                    borderRadius: 6,
                    padding: '24px 22px',
                    display: 'flex', flexDirection: 'column',
                    justifyContent: 'space-between',
                    position: 'relative',
                    boxShadow: highlight > 0.01
                      ? `0 0 0 ${4 * highlight}px rgba(28, 180, 204, ${0.18 * highlight})`
                      : 'none',
                  }}>
                    <div style={{
                      fontFamily: FONT.mono,
                      fontSize: 13, fontWeight: 500,
                      color: COLOURS.azure,
                      letterSpacing: '0.18em',
                    }}>
                      STAGE 0{i + 1}
                    </div>
                    <div style={{
                      fontFamily: FONT.display, fontWeight: 700,
                      fontSize: 26, lineHeight: 1.2,
                      color: COLOURS.navy, letterSpacing: '-0.01em',
                    }}>
                      {label}
                    </div>
                    {isFinal && (
                      <div style={{
                        position: 'absolute', top: 18, right: 18,
                        width: 10, height: 10, borderRadius: 5,
                        background: COLOURS.azure,
                      }} />
                    )}
                  </div>
                </div>
              );
            })}

            {/* Specialists overlay */}
            <div style={{
              position: 'absolute', left: 0, right: 0, top: 720,
              textAlign: 'center', opacity: specsO,
              transform: `translateY(${(1 - specsO) * 10}px)`,
            }}>
              <div style={{
                fontFamily: FONT.display, fontWeight: 500,
                fontSize: 26, color: COLOURS.slate,
                letterSpacing: '0.02em', marginBottom: 28,
              }}>
                Built by three specialists.
              </div>
              <div style={{
                display: 'flex', justifyContent: 'center', gap: 80,
              }}>
                {[
                  { name: 'Lyndon Smith',           role: 'Operations & Codification' },
                  { name: 'Joshua Leyenhorst, CPA', role: 'Financials & Tax' },
                  { name: 'Rob Julien',             role: 'Valuation & Exit' },
                ].map((p, i) => {
                  const np = band(lt, 9.0 + i * 0.4, 0.6, 14.0, 1.0);
                  return (
                    <div key={p.name} style={{
                      opacity: np,
                      transform: `translateY(${(1 - np) * 8}px)`,
                      textAlign: 'center',
                    }}>
                      <div style={{
                        fontFamily: FONT.display, fontWeight: 600,
                        fontSize: 26, color: COLOURS.navy,
                        letterSpacing: '-0.005em',
                      }}>{p.name}</div>
                      <div style={{
                        marginTop: 6,
                        fontFamily: FONT.display, fontWeight: 500,
                        fontSize: 18, color: COLOURS.slate,
                        letterSpacing: '0.04em',
                      }}>{p.role}</div>
                    </div>
                  );
                })}
              </div>
            </div>
          </div>
        );
      }}
    </Sprite>
  );
}

// ────────────────────────────────────────────────────────────────────────────
// SCENE 4 — THE PAYOFF (30–40s)
// Five service pillars stack in, then the closing line.

const PILLARS = [
  'Systems & Operations',
  'Financials & Tax',
  'Valuation & Exit',
  'Human Capital',
  'Sales & Marketing',
];

function ScenePayoff() {
  return (
    <Sprite start={30} end={40}>
      {({ localTime }) => {
        const lt = localTime; // 0..10

        const ebO = band(lt, 0.2, 0.6, 9.2, 0.8);

        const pillarBase = 0.8;
        const pillarPer  = 0.85;

        // Closing line 5.6 → 9.2
        const closeO = band(lt, 5.6, 1.0, 9.2, 0.8);
        const closeTY = (1 - clamp((lt - 5.6) / 1.0, 0, 1)) * 12;

        const listLeft = 280;
        const listTop  = 260;
        const rowH = 78;

        return (
          <div style={{ position: 'absolute', inset: 0 }}>
            <div style={{
              position: 'absolute', top: 160, left: listLeft,
              opacity: ebO,
            }}>
              <Eyebrow>The Payoff</Eyebrow>
            </div>

            {/* Pillars list */}
            <div style={{
              position: 'absolute', left: listLeft, top: listTop,
            }}>
              {PILLARS.map((p, i) => {
                const s = pillarBase + i * pillarPer;
                const o = band(lt, s, 0.5, 9.2, 0.8);
                const tx = (1 - clamp((lt - s) / 0.5, 0, 1)) * 24;
                return (
                  <div key={p} style={{
                    display: 'flex', alignItems: 'center',
                    height: rowH,
                    opacity: o,
                    transform: `translateX(${tx}px)`,
                    borderBottom: `1px solid ${COLOURS.rule}`,
                  }}>
                    <div style={{
                      fontFamily: FONT.mono, fontWeight: 500,
                      fontSize: 18, color: COLOURS.azure,
                      letterSpacing: '0.16em', width: 80,
                    }}>0{i + 1}</div>
                    <div style={{
                      fontFamily: FONT.display, fontWeight: 600,
                      fontSize: 44, color: COLOURS.navy,
                      letterSpacing: '-0.015em',
                    }}>{p}</div>
                  </div>
                );
              })}
            </div>

            {/* Closing line, right-aligned column */}
            <div style={{
              position: 'absolute',
              right: 200, top: listTop + 24,
              width: 640,
              opacity: closeO,
              transform: `translateY(${closeTY}px)`,
            }}>
              <div style={{
                width: 56, height: 2, background: COLOURS.azure,
                marginBottom: 32,
              }} />
              <div style={{
                fontFamily: FONT.display, fontWeight: 500,
                fontSize: 34, lineHeight: 1.35,
                color: COLOURS.navy, letterSpacing: '-0.005em',
              }}>
                Codify what makes your business work.
                <br/>
                <span style={{ color: COLOURS.slate }}>Make yourself redundant.</span>
                <br/>
                Then sell from a position of strength.
              </div>
            </div>
          </div>
        );
      }}
    </Sprite>
  );
}

// ────────────────────────────────────────────────────────────────────────────
// SCENE 5 — THE CLOSE (40–45s)
// Logo, "Ready. Aim. Fire.", URL. End on bone-white for clean loop.

function SceneClose() {
  return (
    <Sprite start={40} end={45}>
      {({ localTime }) => {
        const lt = localTime; // 0..5

        // Logo fades in 0.4 → 1.4
        const logoO = band(lt, 0.4, 1.0, 4.4, 0.6);

        // "Ready. Aim. Fire." reveals word by word
        const r1 = band(lt, 1.6, 0.5, 4.4, 0.6);
        const r2 = band(lt, 2.1, 0.5, 4.4, 0.6);
        const r3 = band(lt, 2.6, 0.5, 4.4, 0.6);

        // URL 3.2 → 3.9
        const urlO = band(lt, 3.2, 0.7, 4.4, 0.6);

        // Subtle azure underline rule from 1.2
        const ruleW = clamp((lt - 1.2) / 0.8, 0, 1) * 120;
        const ruleO = band(lt, 1.2, 0.8, 4.4, 0.6);

        return (
          <div style={{
            position: 'absolute', inset: 0,
            display: 'flex', flexDirection: 'column',
            alignItems: 'center', justifyContent: 'center',
          }}>
            {/* TBGF wordmark (placeholder) */}
            <div style={{
              opacity: logoO,
              transform: `translateY(${(1 - logoO) * 6}px)`,
              display: 'flex', alignItems: 'center', gap: 18,
              marginBottom: 56,
            }}>
              <div style={{
                width: 18, height: 18,
                background: COLOURS.azure,
                borderRadius: 3,
              }} />
              <div style={{
                fontFamily: FONT.display, fontWeight: 700,
                fontSize: 32, color: COLOURS.navy,
                letterSpacing: '0.18em',
              }}>
                THE BUSINESS GROWTH FACTOR
              </div>
            </div>

            {/* Rule */}
            <div style={{
              width: ruleW, height: 2, background: COLOURS.azure,
              opacity: ruleO, marginBottom: 56,
            }} />

            {/* Ready. Aim. Fire. */}
            <div style={{
              display: 'flex', gap: 28,
              fontFamily: FONT.display, fontWeight: 700,
              fontSize: 120, lineHeight: 1,
              color: COLOURS.navy, letterSpacing: '-0.03em',
            }}>
              <span style={{
                opacity: r1,
                transform: `translateY(${(1 - r1) * 12}px)`,
              }}>Ready.</span>
              <span style={{
                opacity: r2,
                transform: `translateY(${(1 - r2) * 12}px)`,
              }}>Aim.</span>
              <span style={{
                opacity: r3,
                transform: `translateY(${(1 - r3) * 12}px)`,
                color: COLOURS.azure,
              }}>Fire.</span>
            </div>

            {/* URL */}
            <div style={{
              marginTop: 72,
              opacity: urlO,
              transform: `translateY(${(1 - urlO) * 6}px)`,
              fontFamily: FONT.mono, fontWeight: 500,
              fontSize: 22, color: COLOURS.slate,
              letterSpacing: '0.08em',
            }}>
              business-exit-trajectory.thebusinessgrowthfactor.com
            </div>
          </div>
        );
      }}
    </Sprite>
  );
}

// ────────────────────────────────────────────────────────────────────────────
// Subtle paper-texture overlay — flat noise feel, very faint
function PaperGrain() {
  return (
    <div
      aria-hidden
      style={{
        position: 'absolute', inset: 0,
        pointerEvents: 'none',
        opacity: 0.04,
        mixBlendMode: 'multiply',
        backgroundImage:
          "url(\"data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='240' height='240'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 0  0 0 0 0 0  0 0 0 0 0  0 0 0 0.6 0'/></filter><rect width='100%' height='100%' filter='url(%23n)'/></svg>\")",
      }}
    />
  );
}

// Tiny scene-ticker, top-right — discreet brand tag
function CornerTag() {
  return (
    <div style={{
      position: 'absolute', top: 56, left: 80,
      display: 'flex', alignItems: 'center', gap: 12,
      pointerEvents: 'none',
    }}>
      <div style={{ width: 8, height: 8, background: COLOURS.azure, borderRadius: 2 }} />
      <div style={{
        fontFamily: FONT.mono, fontSize: 13,
        color: COLOURS.slate, letterSpacing: '0.18em',
      }}>
        TBGF / BUSINESS EXIT TRAJECTORY
      </div>
    </div>
  );
}

function Timecode() {
  const time = useTime();
  const total = 45;
  return (
    <div style={{
      position: 'absolute', top: 56, right: 80,
      fontFamily: FONT.mono, fontSize: 13,
      color: COLOURS.slate, letterSpacing: '0.18em',
      pointerEvents: 'none',
    }}>
      {String(Math.floor(time)).padStart(2, '0')}
      <span style={{ opacity: 0.5 }}> / {total}s</span>
    </div>
  );
}

// ────────────────────────────────────────────────────────────────────────────
// Root scene container

function HeroVideo() {
  return (
    <React.Fragment>
      <SceneHook />
      <SceneGap />
      <SceneFramework />
      <ScenePayoff />
      <SceneClose />

      {/* Persistent chrome */}
      <CornerTag />
      <Timecode />
      <PaperGrain />
    </React.Fragment>
  );
}

window.HeroVideo = HeroVideo;
