// Studio — Jacquemus/Hermès register. Cream paper, ink, single saffron accent
// used sparingly. EB Garamond italic. Numbered sections (Hermès), oversized
// italic tail breaking the grid (Jacquemus). One committed layout.
//
// The page is the whole site: the gateway/Labs split was retired and / now
// lands here too (see index.html). Don't reintroduce a Labs link from here.

// ───────── motion primitives ─────────

// Reveal-on-scroll. IntersectionObserver triggers a one-shot fade+lift when the
// element is ~12% in view. Disabled under prefers-reduced-motion.
function Reveal({ children, delay = 0, as: Tag = 'div', style = {} }) {
  const ref = React.useRef(null);
  const [seen, setSeen] = React.useState(false);
  const [reduced, setReduced] = React.useState(false);

  React.useEffect(() => {
    if (typeof window === 'undefined' || !window.matchMedia) return;
    setReduced(window.matchMedia('(prefers-reduced-motion: reduce)').matches);
  }, []);

  React.useEffect(() => {
    const el = ref.current;
    if (!el || seen || reduced) return;
    const io = new IntersectionObserver(([entry]) => {
      if (entry.isIntersecting) { setSeen(true); io.disconnect(); }
    }, { threshold: 0.12, rootMargin: '0px 0px -8% 0px' });
    io.observe(el);
    return () => io.disconnect();
  }, [seen, reduced]);

  const visible = seen || reduced;
  return (
    <Tag
      ref={ref}
      style={{
        opacity: visible ? 1 : 0,
        transform: visible ? 'translateY(0)' : 'translateY(22px)',
        transition: reduced
          ? 'none'
          : `opacity 1200ms cubic-bezier(.2,.7,.3,1) ${delay}ms, transform 1200ms cubic-bezier(.2,.7,.3,1) ${delay}ms`,
        ...style
      }}
    >
      {children}
    </Tag>
  );
}

// ───────── chrome ─────────

function StudioNav() {
  const [hover, setHover] = React.useState(false);
  return (
    <header style={{
      position: 'sticky', top: 0, zIndex: 50, background: PAPER,
      padding: '24px 56px', display: 'flex', justifyContent: 'space-between', alignItems: 'center',
      borderBottom: `1px solid ${RULE_SOFT}`
    }}>
      <a href="/" style={{ display: 'flex', alignItems: 'center', gap: 12, textDecoration: 'none', color: INK }}>
        <Mark size={26} accent={ACCENT_SAFFRON} ink={INK} haze={INK} showAccent={true} />
        <span style={{
          fontFamily: MONO_FF, fontSize: 12, fontWeight: 500,
          letterSpacing: '0.04em', textTransform: 'uppercase', color: INK
        }}>
          generative<span style={{ color: ACCENT_SAFFRON }}>.</span>studio
        </span>
      </a>
      <a
        href={`mailto:${EMAIL_USER}@${EMAIL_DOMAIN}?subject=Studio%20enquiry`}
        onMouseEnter={() => setHover(true)}
        onMouseLeave={() => setHover(false)}
        style={{
          textDecoration: 'none',
          fontFamily: MONO_FF, fontSize: 9, letterSpacing: '0.28em', textTransform: 'uppercase',
          color: hover ? ACCENT_SAFFRON : INK,
          paddingBottom: 4, borderBottom: `1px solid ${hover ? ACCENT_SAFFRON : INK}`,
          transition: 'color 240ms, border-color 240ms'
        }}>
        Write
      </a>
    </header>
  );
}

function Masthead() {
  return (
    <section style={{ padding: '40px 56px 0' }}>
      <div className="gs-rise" style={{
        display: 'grid', gridTemplateColumns: '1fr auto 1fr',
        paddingBottom: 14, borderBottom: `1px solid ${INK}`,
        alignItems: 'baseline', gap: 24
      }}>
        <MonoLabel size={9} color={INK}>Film studio · Capsules for luxury &amp; heritage</MonoLabel>
        <MonoLabel size={9} color={ACCENT_SAFFRON}>№ 001 · MMXXVI</MonoLabel>
        <div style={{ textAlign: 'right' }}>
          <MonoLabel size={9} color={INK}>Netherlands</MonoLabel>
        </div>
      </div>
    </section>
  );
}

function StudioHero() {
  return (
    <section id="top" style={{ padding: '72px 56px 0', position: 'relative' }}>
      <h1 style={{
        margin: 0, fontFamily: SERIF_FF, fontWeight: 400, color: INK,
        fontSize: 'clamp(52px, 8.4vw, 140px)',
        lineHeight: 0.96, letterSpacing: '-0.032em',
        textWrap: 'balance', paddingBottom: '0.18em',
        textAlign: 'center'
      }}>
        <span className="gs-rise gs-d1" style={{ display: 'block', fontStyle: 'normal' }}>
          Cinematic capsules,
        </span>
        <span style={{
          display: 'block', fontStyle: 'italic', color: ACCENT_SAFFRON,
          marginTop: '-0.06em'
        }}>
          <span className="gs-kinetic">for luxury &amp; heritage.</span>
        </span>
      </h1>
    </section>
  );
}

// 16:9 film plate with the existing lazy-loaded Cloudflare Stream iframe.
// Cursor parallax tilt on pointer-fine devices — one of the page's flagship
// motion moments. Disabled under prefers-reduced-motion.
function FilmCut() {
  // The iframe mounts on initial paint with preload=auto so segments warm the
  // cache while the user reads the hero. The thumbnail-poster div sits ON TOP
  // of the iframe and ONLY fades when we explicitly start playback — never on
  // an SDK 'play' event we didn't initiate. Right after the Stream SDK attaches
  // we defensively pause(), since Cloudflare's iframe doesn't always honor
  // autoplay=false in the URL.
  //
  // Three play triggers, one source of truth (hasUserStarted):
  //   1. auto: user has scrolled past 40px AND plate is 25%+ in view → play()
  //   2. manual click on the plate
  //   3. spacebar/enter while focused
  // hasUserStarted flips ONLY in our requestPlay() — never via SDK events —
  // so any phantom play emitted by the player before user intent is harmless.
  const [hasScrolled, setHasScrolled] = React.useState(false);
  const [hasUserStarted, setHasUserStarted] = React.useState(false);
  const [isPlaying, setIsPlaying] = React.useState(false);
  const [reduced, setReduced] = React.useState(false);
  const videoShellRef = React.useRef(null);
  const iframeRef = React.useRef(null);
  const playerRef = React.useRef(null);
  const guardRef = React.useRef(true); // pause until user starts
  const streamUid = '7b75828b46a8ad0edcf4f3b1c8a6bede';

  React.useEffect(() => {
    if (typeof window === 'undefined' || !window.matchMedia) return;
    setReduced(window.matchMedia('(prefers-reduced-motion: reduce)').matches);
  }, []);

  // Attach SDK; defensively pause; guard against any pre-trigger autoplay.
  React.useEffect(() => {
    if (!iframeRef.current) return undefined;
    let cancelled = false;
    let timer = null;
    const attach = () => {
      if (cancelled) return;
      if (typeof window.Stream === 'function') {
        try {
          const p = window.Stream(iframeRef.current);
          p.addEventListener('play', () => {
            // If we haven't given the green light yet, pause immediately —
            // this neutralises Cloudflare's autoplay even if it ignores the URL flag.
            if (guardRef.current) { try { p.pause(); } catch (e) {} return; }
            setIsPlaying(true);
          });
          p.addEventListener('pause', () => setIsPlaying(false));
          playerRef.current = p;
          // Belt-and-braces: pause on first ready, in case a play event fires
          // before our listener is wired.
          try { p.pause(); } catch (e) {}
        } catch (err) {
          // SDK present but threw — togglePlay will no-op until next attach attempt.
        }
      } else {
        timer = setTimeout(attach, 80);
      }
    };
    attach();
    return () => { cancelled = true; if (timer) clearTimeout(timer); };
  }, []);

  // The single sanctioned way to start playback. Drops the guard, flips
  // hasUserStarted (which fades the thumbnail), and asks the player to play.
  const requestPlay = React.useCallback(() => {
    const p = playerRef.current;
    if (!p) return;
    guardRef.current = false;
    setHasUserStarted(true);
    try { p.play(); } catch (e) {}
  }, []);

  const requestPause = React.useCallback(() => {
    const p = playerRef.current;
    if (!p) return;
    try { p.pause(); } catch (e) {}
  }, []);

  // Auto-trigger gate: scrolled past 40px.
  React.useEffect(() => {
    if (hasScrolled || hasUserStarted) return undefined;
    const onScroll = () => { if (window.scrollY > 40) setHasScrolled(true); };
    window.addEventListener('scroll', onScroll, { passive: true });
    return () => window.removeEventListener('scroll', onScroll);
  }, [hasScrolled, hasUserStarted]);

  // Auto-trigger fire: plate is 25%+ in viewport AND we've scrolled.
  React.useEffect(() => {
    if (!videoShellRef.current || hasUserStarted || !hasScrolled) return undefined;
    const observer = new IntersectionObserver((entries) => {
      entries.forEach((entry) => { if (entry.isIntersecting) requestPlay(); });
    }, { threshold: 0.25 });
    observer.observe(videoShellRef.current);
    return () => observer.disconnect();
  }, [hasUserStarted, hasScrolled, requestPlay]);

  const togglePlay = () => {
    if (isPlaying) requestPause();
    else requestPlay();
  };

  const onKey = (e) => {
    if (e.key === ' ' || e.key === 'Enter') {
      e.preventDefault();
      togglePlay();
    }
  };

  const iframeSrc = `https://iframe.videodelivery.net/${streamUid}?autoplay=false&muted=true&loop=true&controls=false&preload=auto`;
  const thumbUrl = `https://videodelivery.net/${streamUid}/thumbnails/thumbnail.jpg?time=7s&height=1080`;

  const onMove = (e) => {
    if (reduced) return;
    const el = videoShellRef.current;
    if (!el) return;
    const rect = el.getBoundingClientRect();
    const px = (e.clientX - rect.left) / rect.width - 0.5;
    const py = (e.clientY - rect.top) / rect.height - 0.5;
    const max = 3.2; // degrees
    el.style.transform = `perspective(1400px) rotateY(${px * max}deg) rotateX(${-py * max}deg) translateY(-2px)`;
  };
  const onLeave = () => {
    const el = videoShellRef.current;
    if (el) el.style.transform = '';
  };

  return (
    <section id="capsule" style={{ padding: '36px 56px 0', position: 'relative' }}>
      <Reveal style={{
        display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', marginBottom: 16
      }}>
        <MonoLabel size={9} color={INK}>A capsule · Convallaria</MonoLabel>
        <MonoLabel size={9} color={INK}>0:30 · Self-initiated</MonoLabel>
      </Reveal>

      <Reveal delay={120}>
        <figure
          ref={videoShellRef}
          className="gs-plate"
          onMouseMove={onMove}
          onMouseLeave={onLeave}
          onClick={togglePlay}
          onKeyDown={onKey}
          role="button"
          tabIndex={0}
          aria-label={isPlaying ? 'Pause Convallaria' : 'Play Convallaria'}
          style={{
            position: 'relative', aspectRatio: '16 / 9', width: '100%',
            margin: 0, overflow: 'hidden', background: '#0a0d10',
            border: `1px solid rgba(14,14,14,0.18)`,
            cursor: 'pointer'
          }}
        >
          <iframe
            ref={iframeRef}
            src={iframeSrc}
            style={{
              position: 'absolute', inset: 0, width: '100%', height: '100%', border: 0,
              // controls=false → nothing to interact with inside the iframe; let
              // every click fall through to the figure's togglePlay handler.
              pointerEvents: 'none'
            }}
            allow="autoplay; encrypted-media; picture-in-picture"
            allowFullScreen
            title="Convallaria — capsule teaser"
          />

          {/* Thumbnail poster — covers the silently-preloading iframe until first play. */}
          <div
            aria-hidden="true"
            style={{
              position: 'absolute', inset: 0, pointerEvents: 'none',
              backgroundImage: `url(${thumbUrl})`,
              backgroundPosition: 'center', backgroundSize: 'cover',
              opacity: hasUserStarted ? 0 : 1,
              transition: 'opacity 600ms cubic-bezier(.2,.7,.3,1)'
            }}
          />

          {/* Centered play arrow — visible whenever paused (over thumbnail before first play, over live frame after a manual pause). */}
          <div
            aria-hidden="true"
            style={{
              position: 'absolute', inset: 0, pointerEvents: 'none',
              display: 'flex', alignItems: 'center', justifyContent: 'center',
              opacity: isPlaying ? 0 : 1,
              transition: 'opacity 280ms cubic-bezier(.2,.7,.3,1)'
            }}
          >
            <div style={{
              width: 84, height: 84, borderRadius: '50%',
              background: 'rgba(241,238,230,0.92)',
              display: 'flex', alignItems: 'center', justifyContent: 'center',
              boxShadow: '0 18px 50px -12px rgba(0,0,0,0.5)',
              backdropFilter: 'blur(6px)', WebkitBackdropFilter: 'blur(6px)'
            }}>
              <svg width={26} height={30} viewBox="0 0 26 30" style={{ marginLeft: 4 }}>
                <polygon points="2,2 26,15 2,28" fill={ACCENT_SAFFRON} />
              </svg>
            </div>
          </div>

          <div style={{
            position: 'absolute', inset: 0, pointerEvents: 'none',
            background: 'linear-gradient(to bottom, rgba(0,0,0,0.20) 0%, rgba(0,0,0,0) 24%, rgba(0,0,0,0) 58%, rgba(0,0,0,0.55) 100%)'
          }} />

          <div style={{ position: 'absolute', top: 20, left: 24, pointerEvents: 'none' }}>
            <MonoLabel size={9} color="rgba(255,255,255,0.62)">0:30 · 16:9</MonoLabel>
          </div>

          <figcaption style={{
            position: 'absolute', left: 24, right: 24, bottom: 22,
            display: 'flex', justifyContent: 'space-between', alignItems: 'flex-end',
            color: PAPER, gap: 16, pointerEvents: 'none'
          }}>
            <div>
              <MonoLabel size={9} color="rgba(255,255,255,0.55)">Fictional explorer yacht · Self-initiated</MonoLabel>
              <div style={{
                marginTop: 6, fontFamily: SERIF_FF, fontStyle: 'italic',
                fontSize: 'clamp(28px, 3vw, 48px)', lineHeight: 0.98, letterSpacing: '-0.018em'
              }}>
                Convallaria
              </div>
            </div>
            <MonoLabel size={9} color="rgba(255,255,255,0.55)">№ 001</MonoLabel>
          </figcaption>
        </figure>
      </Reveal>
    </section>
  );
}

// Merged "Intent + Work" — three beats (Brief, The room, Method) under one
// numbered section. Removes the redundancy with the hero/eyebrow.
function StudioWork() {
  return (
    <section id="work" style={{ padding: '120px 56px 0' }}>
      <Reveal style={{
        display: 'grid', gridTemplateColumns: '180px 1fr 1fr',
        columnGap: 40, rowGap: 36, alignItems: 'baseline',
        paddingTop: 22, borderTop: `1px solid ${RULE}`
      }}>
        <MonoLabel size={9} color={INK}>№ 002 · The work</MonoLabel>

        {/* Lede — spans both body columns */}
        <p style={{
          gridColumn: '2 / span 2',
          margin: 0, fontFamily: SERIF_FF, fontWeight: 400,
          fontSize: 'clamp(22px, 2vw, 30px)', lineHeight: 1.42,
          color: INK, textWrap: 'pretty', maxWidth: '52ch'
        }}>
          AI-generated footage as raw material — then cut, graded, and scored by hand into capsules: short pieces, purpose-cut for the channels buyers actually watch.
        </p>

        {/* Empty cell to keep the label column aligned */}
        <div />

        <div>
          <MonoLabel size={9} color={ACCENT_SAFFRON}>The room</MonoLabel>
          <p style={{
            margin: '14px 0 0', fontFamily: SERIF_FF,
            fontSize: 'clamp(18px, 1.5vw, 22px)', lineHeight: 1.5,
            color: INK, textWrap: 'pretty', maxWidth: '32ch'
          }}>
            <em>Convallaria</em> — a fictional explorer yacht named after the lily-of-the-valley. One of a set of capsules, purpose-cut per channel.
          </p>
        </div>

        <div>
          <MonoLabel size={9} color={ACCENT_SAFFRON}>Method</MonoLabel>
          <p style={{
            margin: '14px 0 0', fontFamily: SERIF_FF,
            fontSize: 'clamp(18px, 1.5vw, 22px)', lineHeight: 1.5,
            color: INK, textWrap: 'pretty', maxWidth: '32ch'
          }}>
            Generated, then <em>hand-cut</em>. Speed lives in the workflow; craft lives in the cut. <em>The machine drafts; the edit decides.</em>
          </p>
        </div>
      </Reveal>
    </section>
  );
}

function StudioPartners() {
  return (
    <section id="partners" style={{ padding: '88px 56px 0' }}>
      <Reveal style={{
        display: 'grid', gridTemplateColumns: '180px 1fr',
        columnGap: 40, alignItems: 'center',
        paddingTop: 22, borderTop: `1px solid ${RULE}`
      }}>
        <MonoLabel size={9} color={INK}>№ 003 · In partnership with</MonoLabel>
        <a
          href="https://www.linkedin.com/company/eternal-blue-superyacht-consultancy/?originalSubdomain=ae"
          target="_blank"
          rel="noopener noreferrer"
          aria-label="Eternal Blue on LinkedIn"
          style={{
            display: 'inline-flex', alignItems: 'center', gap: 22,
            textDecoration: 'none', color: INK, alignSelf: 'start'
          }}>
          <img
            src="assets/eternal-blue.jpg"
            alt="Eternal Blue"
            width={120}
            height={120}
            style={{
              display: 'block', height: 96, width: 'auto',
              mixBlendMode: 'multiply', filter: 'contrast(1.05)'
            }}
          />
        </a>
      </Reveal>
    </section>
  );
}

function StudioContact() {
  return (
    <section id="contact" style={{ padding: '120px 56px 0' }}>
      <Reveal style={{
        display: 'flex', justifyContent: 'space-between', alignItems: 'baseline',
        paddingBottom: 18, borderBottom: `1px solid ${INK}`
      }}>
        <MonoLabel size={9} color={INK}>№ 004 · Write to the studio</MonoLabel>
        <MonoLabel size={9} color={INK}>Reply within 48h</MonoLabel>
      </Reveal>
      <Reveal delay={140}>
        <a
          href={`mailto:${EMAIL_USER}@${EMAIL_DOMAIN}?subject=Studio%20enquiry`}
          style={{
            display: 'block', marginTop: 36, color: INK, textDecoration: 'none',
            fontFamily: SERIF_FF, fontStyle: 'italic', fontWeight: 400,
            fontSize: 'clamp(48px, 8vw, 132px)', lineHeight: 0.98,
            letterSpacing: '-0.028em', textWrap: 'balance', paddingBottom: '0.16em'
          }}>
          {EMAIL_USER}<span style={{ color: ACCENT_SAFFRON, fontStyle: 'normal' }}>@</span>{EMAIL_DOMAIN}
        </a>
      </Reveal>
    </section>
  );
}

function StudioFooter() {
  return (
    <footer style={{
      marginTop: 80, padding: '28px 56px 36px', borderTop: `1px solid ${RULE_SOFT}`,
      display: 'flex', justifyContent: 'space-between', alignItems: 'center'
    }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
        <Mark size={14} accent={ACCENT_SAFFRON} ink={INK} haze={INK} showAccent={true} />
        <MonoLabel size={9}>generative.studio · MMXXVI · NL</MonoLabel>
      </div>
      <MonoLabel size={9}>© 2026</MonoLabel>
    </footer>
  );
}

function StudioPage() {
  return (
    <div style={{ background: PAPER, color: INK, minHeight: '100vh', position: 'relative', overflow: 'hidden' }}>
      <StudioNav />
      <Masthead />
      <StudioHero />
      <FilmCut />
      <StudioWork />
      <StudioPartners />
      <StudioContact />
      <StudioFooter />
    </div>
  );
}

const rootStudio = ReactDOM.createRoot(document.getElementById('root'));
rootStudio.render(<Responsive Mobile={MobileStudio} Desktop={StudioPage} />);
