// v3-scenes.jsx, Cinematic scene composition with voice-call transcripts.

const {
  BRAND, SAT, SF, MONO,
  useReducedMotion, useInView, useViewport, useElementProgress,
  clamp01, easeOutCubic,
  Cortex,
  CortexOverlay, VoiceTranscript, useVoiceTranscript,
  FloatingDialogue, useSpeech,
  SceneMeta, OutcomeTag, SceneImage, AmbientParticles
} = window;

// Orb position per scene, where Lantic's Cortex sits over the cinematic image.
// side = which side of the section the transcript column sits on.
const ORB_POSITIONS = {
  's1': { x: 65, y: 57, size: 150, side: 'left' },
  's2': { x: 36, y: 46, size: 180, side: 'right' },
  's3': { x: 64, y: 48, size: 190, side: 'left' },
  's4': { x: 32, y: 52, size: 170, side: 'right' },
  's5': { x: 50, y: 38, size: 220, side: 'right' },
  's6': { x: 60, y: 50, size: 160, side: 'left' }
};

function useMountedAfter(delay = 60) {
  const [m, setM] = React.useState(false);
  React.useEffect(() => { const t = setTimeout(() => setM(true), delay); return () => clearTimeout(t); }, [delay]);
  return m;
}

// Tiny speaker icon for the audio toggle.
function SoundIcon({ on = false }) {
  return (
    <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round">
      <polygon points="11 5 6 9 2 9 2 15 6 15 11 19 11 5"/>
      {on && <path d="M19.07 4.93a10 10 0 0 1 0 14.14M15.54 8.46a5 5 0 0 1 0 7.07"/>}
      {!on && <line x1="23" y1="9" x2="17" y2="15"/>}
      {!on && <line x1="17" y1="9" x2="23" y2="15"/>}
    </svg>
  );
}

// ─────────────────────────────────────────────────────────────────
// HeroScene
// ─────────────────────────────────────────────────────────────────
function HeroScene({ scene, headline, onCTA, motionIntensity = 'active', showOrb = true }) {
  const ref = React.useRef(null);
  const mounted = useMountedAfter(60);
  const prog  = useElementProgress(ref);
  const vw = useViewport();
  const reduced = useReducedMotion();
  const motionScale = motionIntensity === 'calm' ? 0.4 : motionIntensity === 'standard' ? 1 : 1.6;
  const [activeSpeaker, setActiveSpeaker] = React.useState(null);
  const orbPos = ORB_POSITIONS[scene.id] || { x: 50, y: 70, size: 140, side: 'right' };
  const isLantSpeaking = activeSpeaker === 'L' || activeSpeaker === 'L2';
  const parallax = (prog - 0.5) * 14 * motionScale;
  const compact = vw < 1024;
  // Audio: real toggle. When enabled, FloatingDialogue plays per-line MP3s
  // declared in v3-data.jsx (line.audio). If no MP3 yet, toggle is silent but state still tracked.
  const [audioEnabled, setAudioEnabled] = React.useState(false);
  const speech = {
    enabled: audioEnabled,
    toggle: () => setAudioEnabled(v => !v),
    speak: () => {},
    ready: true,
  };

  // Lazy-start the transcript ~1.0s after mount.
  const [startTranscript, setStartTranscript] = React.useState(false);
  React.useEffect(() => {
    if (!mounted) return;
    const t = setTimeout(() => setStartTranscript(true), 1000);
    return () => clearTimeout(t);
  }, [mounted]);

  return (
    <section ref={ref} id="hero" data-screen-label="hero" style={{
      position: 'relative', width: '100%', minHeight: '100vh', overflow: 'hidden',
      background: BRAND.canvasDeep,
      display: 'flex', flexDirection: compact ? 'column' : 'row',
    }}>
      {/* LEFT COLUMN, headline / copy / CTA */}
      <div style={{
        flex: compact ? '0 0 auto' : '1 1 46%',
        padding: compact ? '92px 24px 36px' : '120px 48px 90px 64px',
        display: 'flex', flexDirection: 'column', justifyContent: 'center',
        position: 'relative', zIndex: 5,
        background: BRAND.canvasDeep,
        minHeight: compact ? 'auto' : '100vh',
      }}>
        {/* Soft giant LANTIC watermark, registers the brand at-a-glance, especially on mobile */}
        <div aria-hidden style={{
          position: 'absolute',
          left: compact ? '50%' : '-6%',
          bottom: compact ? '-2%' : '-8%',
          transform: compact ? 'translateX(-50%)' : 'none',
          fontFamily: SAT,
          fontWeight: 700,
          fontSize: compact ? 'clamp(120px, 38vw, 200px)' : 'clamp(180px, 18vw, 320px)',
          letterSpacing: compact ? -6 : -12,
          lineHeight: 0.85,
          color: BRAND.ink,
          opacity: 0.035,
          pointerEvents: 'none',
          userSelect: 'none',
          whiteSpace: 'nowrap',
          zIndex: 0,
        }}>Lantic</div>

        <div style={{ position: 'relative', zIndex: 1 }}>
        {/* eyebrow pill */}
        <div style={{
          fontFamily: MONO, fontSize: 11, color: BRAND.skyMist,
          letterSpacing: '0.28em', fontWeight: 600, textTransform: 'uppercase',
          marginBottom: 28, alignSelf: 'flex-start',
          display: 'inline-flex', alignItems: 'center', gap: 10,
          padding: '7px 13px 7px 11px', borderRadius: 16,
          background: 'rgba(56,189,248,.10)', border: '1px solid rgba(56,189,248,.22)',
          backdropFilter: 'blur(14px)', WebkitBackdropFilter: 'blur(14px)',
        }}>
          <span style={{
            width: 7, height: 7, borderRadius: 4, background: BRAND.skyLight,
            boxShadow: `0 0 10px ${BRAND.skyLight}`,
            animation: reduced ? 'none' : 'v3-tick-dot 1.6s ease-in-out infinite',
          }}/>
          <span>{headline.eyebrow}</span>
        </div>

        <h1 style={{
          fontFamily: SAT, fontWeight: 600,
          fontSize: compact ? 'clamp(38px, 7vw, 56px)' : 'clamp(46px, 4.2vw, 74px)',
          letterSpacing: compact ? -2 : -2.8, lineHeight: 0.98,
          margin: 0, color: BRAND.ink,
          textWrap: 'balance',
        }}>
          <span style={{ display: 'block' }}>{headline.h1Top}</span>
          {headline.h1Mid && <span style={{
            display: 'block',
            background: `linear-gradient(110deg, ${BRAND.skyMist} 0%, ${BRAND.skyLight} 45%, ${BRAND.skyMist} 100%)`,
            WebkitBackgroundClip: 'text', WebkitTextFillColor: 'transparent',
            backgroundClip: 'text', color: 'transparent',
            fontStyle: 'italic', fontWeight: 500,
          }}>{headline.h1Mid}</span>}
          {headline.h1Bot && <span style={{ display: 'block' }}>{headline.h1Bot}</span>}
        </h1>

        <div style={{
          marginTop: compact ? 22 : 28,
          fontFamily: SF, fontSize: compact ? 17 : 20, lineHeight: 1.45, fontWeight: 500,
          color: BRAND.ink, letterSpacing: -0.2,
          maxWidth: 540,
          textWrap: 'pretty',
        }}>
          {(() => {
            // Render the intro with "Lantic" called out — matches the wordmark vocabulary
            // and gives the brand name a second moment of presence in the hero.
            const parts = (headline.intro || '').split(/(Lantic)/g);
            return parts.map((p, i) => p === 'Lantic'
              ? <span key={i} style={{
                  fontFamily: SAT, fontWeight: 700, letterSpacing: -0.4,
                  background: `linear-gradient(110deg, ${BRAND.skyMist} 0%, ${BRAND.skyLight} 50%, ${BRAND.skyMist} 100%)`,
                  WebkitBackgroundClip: 'text', WebkitTextFillColor: 'transparent',
                  backgroundClip: 'text', color: 'transparent',
                }}>{p}</span>
              : <React.Fragment key={i}>{p}</React.Fragment>);
          })()}
        </div>

        <div style={{
          marginTop: 14,
          fontFamily: SF, fontSize: compact ? 14.5 : 15.5, lineHeight: 1.55,
          color: BRAND.sub, letterSpacing: -0.1,
          maxWidth: 520,
          textWrap: 'pretty',
        }}>{headline.sub}</div>

        <div style={{
          marginTop: 32,
          display: 'flex', gap: 14, alignItems: 'center', flexWrap: 'wrap',
        }}>
          <button onClick={onCTA} style={{
            height: 50, padding: '0 24px', borderRadius: 26,
            background: `linear-gradient(135deg, ${BRAND.skyLight} 0%, ${BRAND.skyDeep} 100%)`,
            color: '#FFFFFF', border: '1px solid rgba(255,255,255,.18)',
            fontSize: 15.5, fontWeight: 600, letterSpacing: -0.15,
            cursor: 'pointer',
            boxShadow: `0 12px 40px ${BRAND.skyDark}88, inset 0 1px 0 rgba(255,255,255,.2)`,
          }}>Join the waitlist</button>
          <a href="#s2" onClick={(e) => {
            e.preventDefault();
            document.getElementById('s2')?.scrollIntoView({ behavior: 'smooth', block: 'start' });
          }} style={{
            display: 'inline-flex', alignItems: 'center', gap: 10,
            height: 50, padding: '0 18px',
            fontSize: 14.5, color: BRAND.sub, fontWeight: 500, letterSpacing: -0.1,
          }}>
            <span>See a day with Lantic</span>
            <span style={{ fontSize: 18 }}>↓</span>
          </a>
        </div>
        </div>
      </div>

      {/* RIGHT COLUMN, cinematic image + cortex + floating speech */}
      <div style={{
        flex: compact ? '0 0 auto' : '1 1 54%',
        minHeight: compact ? '86vh' : '100vh',
        position: 'relative', overflow: 'hidden',
        background: BRAND.canvasDeep,
      }}>
        <SceneImage src={scene.image.src} video={scene.video?.src} alt={scene.image.alt}
          parallax={parallax} motionScale={motionScale}
          objectFit="cover" objectPosition="50% 50%"/>
        {/* edge fade so the picture blends into the canvas instead of looking like a pasted rectangle */}
        <div aria-hidden style={{
          position: 'absolute', inset: 0, pointerEvents: 'none', zIndex: 1,
          background: compact
            ? `linear-gradient(180deg, ${BRAND.canvasDeep} 0%, transparent 14%, transparent 86%, ${BRAND.canvasDeep} 100%)`
            : `linear-gradient(90deg, ${BRAND.canvasDeep} 0%, transparent 18%, transparent 100%), linear-gradient(180deg, ${BRAND.canvasDeep} 0%, transparent 10%, transparent 90%, ${BRAND.canvasDeep} 100%)`,
        }}/>
        <AmbientParticles density={compact ? 6 : 14} intensity={motionScale * 0.6}/>

        {/* Canonical Cortex orb. On mobile it sits over the phone on the table
            (lower-right), where Lantic is actually living, off his face and hand. */}
        {showOrb && (
          <CortexOverlay
            x={compact ? 72 : orbPos.x}
            y={compact ? 56 : orbPos.y}
            size={compact ? Math.round(orbPos.size * 0.7) : orbPos.size}
            speaking={isLantSpeaking}/>
        )}

        {/* scene chip cluster, top-right of image area — pushed below the fixed nav so it never collides with the waitlist banner */}
        <div style={{
          position: 'absolute', top: compact ? 24 : 96, right: 24, zIndex: 5,
          display: 'flex', alignItems: 'center', gap: 8, flexWrap: 'wrap',
          justifyContent: 'flex-end',
          maxWidth: 'calc(100% - 48px)',
        }}>
          <div style={{
            display: 'inline-flex', alignItems: 'center', gap: 10,
            padding: '6px 12px', borderRadius: 14,
            background: 'rgba(5,11,23,.55)',
            border: '1px solid rgba(255,255,255,.08)',
            backdropFilter: 'blur(14px)', WebkitBackdropFilter: 'blur(14px)',
            fontFamily: MONO, fontSize: 10, color: BRAND.skyMist,
            letterSpacing: '0.24em', fontWeight: 600, textTransform: 'uppercase',
          }}>
            <span>{scene.time}</span>
          </div>
          {/* Persona pin — names the protagonist + trade so it lands as a real builder */}
          {(scene.protagonist || scene.personaTag) && (
            <div style={{
              display: 'inline-flex', alignItems: 'center', gap: 8,
              padding: '6px 12px', borderRadius: 14,
              background: 'rgba(56,189,248,.10)',
              border: '1px solid rgba(56,189,248,.26)',
              backdropFilter: 'blur(14px)', WebkitBackdropFilter: 'blur(14px)',
              fontFamily: MONO, fontSize: 10, color: BRAND.skyMist,
              letterSpacing: '0.24em', fontWeight: 600, textTransform: 'uppercase',
            }}>
              {scene.protagonist && <span style={{ color: BRAND.ink }}>{scene.protagonist}</span>}
              {scene.protagonist && scene.personaTag && (
                <span style={{ color: BRAND.dim }}>·</span>
              )}
              {scene.personaTag && <span>{scene.personaTag}</span>}
            </div>
          )}
        </div>

        {/* Floating dialogue, Lantic near the orb, builder near his head */}
        <FloatingDialogue scene={scene} start={startTranscript}
          onActiveSpeakerChange={setActiveSpeaker} compact={compact}
          speak={speech.speak} audioEnabled={audioEnabled}/>
      </div>
    </section>
  );
}

// ─────────────────────────────────────────────────────────────────
// CinematicScene, generic scene body for 2..6.
// ─────────────────────────────────────────────────────────────────
function CinematicScene({ scene, motionIntensity = 'active', showCortex = true }) {
  const ref = React.useRef(null);
  const inView = useInView(ref, 0.25);
  const prog  = useElementProgress(ref);
  const vw = useViewport();
  const reduced = useReducedMotion();
  const motionScale = motionIntensity === 'calm' ? 0.4 : motionIntensity === 'standard' ? 1 : 1.6;
  const [activeSpeaker, setActiveSpeaker] = React.useState(null);
  const orbPos = ORB_POSITIONS[scene.id] || { x: 60, y: 50, size: 180, side: 'right' };
  const dialogueSide = orbPos.side;
  const isLantSpeaking = activeSpeaker === 'L' || activeSpeaker === 'L2';
  const parallax = (prog - 0.5) * 16 * (motionScale * 0.7);

  // Track when the section becomes "centered" enough to start the voice playback.
  const [transcriptStarted, setTranscriptStarted] = React.useState(false);
  React.useEffect(() => {
    if (inView && !transcriptStarted) {
      const t = setTimeout(() => setTranscriptStarted(true), 700);
      return () => clearTimeout(t);
    }
  }, [inView, transcriptStarted]);

  const compact = vw < 820;

  return (
    <section ref={ref} id={scene.id} data-screen-label={`scene-${scene.n}`} style={{
      position: 'relative', width: '100%',
      minHeight: compact ? '700px' : '100vh',
      overflow: 'hidden', background: BRAND.canvasDeep
    }}>
      <SceneImage src={scene.image.src} video={scene.video?.src} alt={scene.image.alt}
        parallax={parallax} motionScale={motionScale}/>
      <AmbientParticles density={compact ? 6 : 14} intensity={motionScale * 0.5}/>

      {showCortex && (
        <CortexOverlay x={orbPos.x} y={orbPos.y} size={orbPos.size}
          speaking={isLantSpeaking} dimmed={scene.id === 's6'}/>
      )}

      <SceneMeta n={scene.n} time={scene.time}
        persona={scene.persona} location={scene.location}
        visible={inView}/>

      {/* transcript column */}
      <div style={{
        position: 'absolute',
        top: compact ? 'auto' : '50%',
        bottom: compact ? '110px' : 'auto',
        [dialogueSide]: compact ? 24 : 60,
        transform: compact ? 'none' : 'translateY(-50%)',
        width: compact ? 'calc(100% - 48px)' : 'min(520px, 34vw)',
        zIndex: 6, pointerEvents: 'none'
      }}>
        <div style={{
          fontFamily: MONO, fontSize: 10.5, color: BRAND.skyMist,
          letterSpacing: '0.24em', fontWeight: 600, textTransform: 'uppercase',
          marginBottom: 16
          }}>
          <span style={{
            display: 'inline-block', width: 6, height: 6, borderRadius: 4,
            background: BRAND.skyLight, marginRight: 8,
            boxShadow: `0 0 8px ${BRAND.skyLight}`,
            animation: 'v3-tick-dot 1.4s ease-in-out infinite',
            verticalAlign: 'middle'
          }}/>
          Live · {scene.eyebrow}
        </div>
        <VoiceTranscript lines={scene.dialogue} start={transcriptStarted}
          onActiveSpeakerChange={setActiveSpeaker} compact={compact}/>
      </div>

      <OutcomeTag text={scene.outcome} visible={transcriptStarted && inView}/>

      {scene.closingLine && (
        <div style={{
          position: 'absolute',
          left: '50%', top: '36%', transform: 'translate(-50%, -50%)',
          textAlign: 'center', maxWidth: 760, padding: '0 24px',
          opacity: transcriptStarted ? 1 : 0, zIndex: 7, pointerEvents: 'none'
        }}>
          <div style={{
            fontFamily: SAT, fontWeight: 500, letterSpacing: -2,
            fontSize: compact ? 38 : 64, lineHeight: 1.05,
            color: BRAND.ink, textShadow: '0 4px 30px rgba(0,0,0,.6)'
          }}>
            <em style={{ fontWeight: 400, fontStyle: 'italic', color: BRAND.skyMist }}>{scene.closingLine.top}</em>
            <br/>
            <span>{scene.closingLine.bottom}</span>
          </div>
        </div>
      )}
    </section>
  );
}

// ─────────────────────────────────────────────────────────────────
// StatementStrip, short typographic moment between scenes.
// ─────────────────────────────────────────────────────────────────
function StatementStrip({ children, eyebrow, sub }) {
  const ref = React.useRef(null);
  const inView = useInView(ref, 0.3);
  const vw = useViewport();
  const phone = vw < 640;
  return (
    <section ref={ref} style={{
      position: 'relative', minHeight: phone ? 'auto' : '60vh', padding: phone ? '84px 20px' : '120px 32px',
      display: 'flex', flexDirection: 'column', justifyContent: 'center', alignItems: 'center',
      textAlign: 'center', background: BRAND.canvasDeep
    }}>
      {eyebrow && (
        <div style={{
          fontFamily: MONO, fontSize: 11, color: BRAND.skyMist,
          letterSpacing: '0.28em', fontWeight: 600, textTransform: 'uppercase',
          marginBottom: 30
          }}>{eyebrow}</div>
      )}
      <div style={{
        fontFamily: SAT, fontWeight: 500, fontSize: 'clamp(36px, 5.4vw, 72px)',
        letterSpacing: -2.4, lineHeight: 1.04, color: BRAND.ink,
        maxWidth: 1080, textWrap: 'balance'
        }}>{children}</div>
      {sub && (
        <div style={{
          marginTop: 32,
          fontFamily: SF, fontSize: 'clamp(17px, 1.6vw, 21px)', fontWeight: 400,
          lineHeight: 1.55, letterSpacing: -0.2, color: BRAND.sub,
          maxWidth: 680, textWrap: 'pretty'
        }}>{sub}</div>
      )}
    </section>
  );
}

// ─────────────────────────────────────────────────────────────────
// PromiseLines, typographic intermission.
// ─────────────────────────────────────────────────────────────────
function PromiseLines() {
  const ref = React.useRef(null);
  const inView = useInView(ref, 0.25);
  const vw = useViewport();
  const phone = vw < 640;
  const lines = [
    'Lantic tells you.',
    'Lantic reminds you.',
    'Lantic nudges you.',
    'Lantic plans your day.',
    'Lantic talks to your team’s Lantics.',
    'Lantic gives you your evenings back.',
  ];
  return (
    <section ref={ref} style={{
      position: 'relative', padding: phone ? '100px 20px' : '160px 32px',
      background: BRAND.canvasDeep, overflow: 'hidden'
    }}>
      <div style={{
        position: 'absolute', inset: 0,
        background: `radial-gradient(ellipse 50% 60% at 50% 50%, ${BRAND.skyDark}22 0%, transparent 60%)`
      }}/>
      <div style={{
        fontFamily: MONO, fontSize: 11, color: BRAND.skyMist,
        letterSpacing: '0.28em', fontWeight: 600, textTransform: 'uppercase',
        textAlign: 'center', marginBottom: phone ? 44 : 64, position: 'relative'
      }}>The proactive promise</div>
      <div style={{
        display: 'flex', flexDirection: 'column', alignItems: 'flex-start', gap: 6,
        position: 'relative', width: 'fit-content', maxWidth: '100%', margin: '0 auto'
      }}>
        {lines.map((line, i) => (
          <div key={i} style={{
            fontFamily: SAT, fontWeight: 500,
            fontSize: 'clamp(28px, 4vw, 56px)', letterSpacing: -1.8, lineHeight: 1.08,
            color: i === lines.length - 1 ? BRAND.ink : BRAND.sub,
            textAlign: 'left'
          }}>
            {i === lines.length - 1 ? (
              <span style={{
                background: `linear-gradient(110deg, ${BRAND.skyMist} 0%, ${BRAND.skyLight} 50%, ${BRAND.ink} 100%)`,
                WebkitBackgroundClip: 'text', WebkitTextFillColor: 'transparent',
                fontStyle: 'italic'
              }}>{line}</span>
            ) : line}
          </div>
        ))}
      </div>
    </section>
  );
}

Object.assign(window, { CinematicScene, HeroScene, StatementStrip, PromiseLines, ImagineLine });

// ─────────────────────────────────────────────────────────────────
// ImagineLine — the "free mind-time" emotional beat as its own section.
// ─────────────────────────────────────────────────────────────────
function ImagineLine() {
  const ref = React.useRef(null);
  const inView = useInView(ref, 0.3);
  const vw = useViewport();
  const phone = vw < 640;
  return (
    <section ref={ref} style={{
      position: 'relative', padding: phone ? '108px 22px' : '170px 32px',
      background: BRAND.canvasDeep, overflow: 'hidden',
      display: 'flex', justifyContent: 'center'
    }}>
      <div aria-hidden style={{
        position: 'absolute', inset: 0,
        background: `radial-gradient(ellipse 46% 56% at 50% 46%, ${BRAND.skyDark}26 0%, transparent 62%)`
      }}/>
      <div style={{
        position: 'relative', textAlign: 'center', maxWidth: 820,
        opacity: inView ? 1 : 0, transform: inView ? 'none' : 'translateY(18px)',
        transition: 'opacity 900ms cubic-bezier(.22,1,.36,1), transform 900ms cubic-bezier(.22,1,.36,1)'
      }}>
        <div style={{
          fontFamily: SAT, fontWeight: 500, letterSpacing: -2,
          fontSize: phone ? 40 : 'clamp(48px, 5.6vw, 76px)', lineHeight: 1.04, color: BRAND.ink
        }}>
          <em style={{ fontWeight: 400, fontStyle: 'italic', color: BRAND.skyMist }}>Imagine free mind-time.</em>
        </div>
        <div style={{
          marginTop: phone ? 18 : 24,
          fontFamily: SAT, fontWeight: 500, letterSpacing: -1,
          fontSize: phone ? 22 : 'clamp(26px, 2.6vw, 34px)', lineHeight: 1.25, color: BRAND.sub,
          textWrap: 'balance'
        }}>
          Lantic gives you back the one thing money can’t buy.
        </div>
      </div>
    </section>
  );
}
