// Tatava Studio, Hero variants + cinematic video backdrop // Loads after site-data.js. Exports to window at the bottom. const { useRef, useEffect, useState } = React; const TD = window.TATAVA_DATA; /* ------------------------------------------------------------ FadeLoopVideo, seamless manual loop with fade in/out. rAF monitors currentTime/duration; fades opacity over 0.5s at both ends; on `ended` waits 100ms, resets, replays. ------------------------------------------------------------ */ function FadeLoopVideo({ src, fallback, className, style }) { const videoRef = useRef(null); const vsrc = useDeferredVideoSrc(src); useEffect(() => { if (!vsrc) return undefined; const video = videoRef.current; if (!video) return; let raf; const FADE = 0.5; const tick = () => { const d = video.duration; if (d && !isNaN(d)) { const t = video.currentTime; let opacity = 1; if (t < FADE) opacity = t / FADE;else if (t > d - FADE) opacity = Math.max(0, (d - t) / FADE); video.style.opacity = opacity.toFixed(3); } raf = requestAnimationFrame(tick); }; const onEnded = () => { video.style.opacity = "0"; setTimeout(() => { video.currentTime = 0; const p = video.play(); if (p && p.catch) p.catch(() => {}); }, 100); }; video.addEventListener("ended", onEnded); const p = video.play(); if (p && p.catch) p.catch(() => {}); raf = requestAnimationFrame(tick); return () => { cancelAnimationFrame(raf); video.removeEventListener("ended", onEnded); }; }, [vsrc]); return (
{fallback ? : null} {vsrc ? : null}
); } /* defer video fetch until the page has finished loading, keeps first paint fast and the load event unblocked */ function useDeferredVideoSrc(src) { const [vsrc, setVsrc] = React.useState( document.readyState === "complete" ? src : null ); React.useEffect(() => { if (vsrc) return undefined; const arm = () => setVsrc(src); if (document.readyState === "complete") { arm(); return undefined; } window.addEventListener("load", arm); return () => window.removeEventListener("load", arm); }, [src]); return vsrc; } /* ------------------------------------------------------------ Headline, one orange italic word per brand pattern. twoLine=true breaks on h.line1 / h.pre2 for cinematic hero. ------------------------------------------------------------ */ function Headline({ variant, className, copy, twoLine, anchor }) { const h = copy || TD.headlines[variant] || TD.headlines.racing; const props = { className: "headline " + (className || "") }; if (anchor) props["data-comment-anchor"] = anchor; if (twoLine && h.line1) { return (

{h.line1}
{h.pre2}{h.hl}{h.post}

); } return (

{h.pre}{h.hl}{h.post}

); } function HeroCtas({ delayClass }) { return (
Book a session Book a free 15-min call
); } function HeroBadges({ delayClass }) { return (
{TD.trustBadges.map((b) => {b} )}
); } /* ------------------------------------------------------------ Variant A, Cinematic: full-bleed video low in the frame, cream scrims top + bottom, centered serif headline. ------------------------------------------------------------ */ function HeroCinematic({ headline, showVideo }) { return (
{showVideo ? : A calm mindfulness class }
{TD.eyebrow}

{TD.subhead}

Consultation By Appointment Only

); } /* ------------------------------------------------------------ Variant B, Editorial split: brand's two-column rhythm, video living inside the tilted embossed-poster frame. ------------------------------------------------------------ */ function HeroSplit({ headline, showVideo }) { return (
{TD.eyebrow}

{TD.subhead}

Consultation By Appointment Only

{showVideo ? : A calm mindfulness class }
Accepting new clients
); } /* ------------------------------------------------------------ Variant C, Poster band: centered copy on cream, then the video as a wide embossed-poster band beneath. ------------------------------------------------------------ */ function HeroPosterBand({ headline, showVideo }) { return (
{TD.eyebrow}

{TD.subhead}

Consultation By Appointment Only

{showVideo ? : A calm mindfulness class }
In person in Delhi ยท Online anywhere
); } Object.assign(window, { FadeLoopVideo, Headline, HeroCtas, HeroBadges, HeroCinematic, HeroSplit, HeroPosterBand, useDeferredVideoSrc });