/* Shared chrome for all Padre Studios pages. * Components on window: Backdrop, Header, Footer, Modal, Eyebrow, PageShell, * SkipLink, useViewport. * * Backdrop variants: * hero — rainy street photo + rain canvas + vignette (Landing only) * quiet — flat dark surface with subtle grain (interior pages) */ /* ---------- useViewport ---------- * * Single source of truth for responsive breakpoints. Returns a stable object * that updates only when the bucket changes — avoids re-renders on every px. */ function useViewport() { const compute = () => { if (typeof window === "undefined") { return { width: 1200, isMobile: false, isTablet: false, isDesktop: true }; } const w = window.innerWidth; return { width: w, isMobile: w < 720, isTablet: w >= 720 && w < 1024, isDesktop: w >= 1024, }; }; const [vp, setVp] = React.useState(compute); React.useEffect(() => { let raf = 0; const onResize = () => { cancelAnimationFrame(raf); raf = requestAnimationFrame(() => { const next = compute(); setVp((prev) => prev.isMobile === next.isMobile && prev.isTablet === next.isTablet && prev.isDesktop === next.isDesktop ? prev : next ); }); }; window.addEventListener("resize", onResize); return () => { cancelAnimationFrame(raf); window.removeEventListener("resize", onResize); }; }, []); return vp; } /* ---------- SkipLink (a11y) ---------- */ const skipLinkStyles = { base: { position: "absolute", left: 16, top: -40, background: "var(--fg)", color: "var(--bg)", padding: "10px 14px", borderRadius: 8, fontFamily: "inherit", fontSize: 13, fontWeight: 500, textDecoration: "none", zIndex: 1000, transition: "top 160ms ease", }, }; function SkipLink() { return ( (e.currentTarget.style.top = "16px")} onBlur={(e) => (e.currentTarget.style.top = "-40px")} > Skip to content ); } /* ---------- Backdrop ---------- */ const backdropStyles = { wrap: { position: "absolute", inset: 0, zIndex: 0, overflow: "hidden", background: "var(--bg)", }, img: { position: "absolute", inset: 0, width: "100%", height: "100%", objectFit: "cover", objectPosition: "center bottom", }, vignetteHero: { position: "absolute", inset: 0, background: "linear-gradient(180deg, color-mix(in oklch, var(--bg-deep) 55%, transparent) 0%, color-mix(in oklch, var(--bg-deep) 18%, transparent) 22%, transparent 42%, color-mix(in oklch, var(--bg-deep) 55%, transparent) 72%, color-mix(in oklch, var(--bg-deep) 95%, transparent) 100%), radial-gradient(110% 70% at 65% 38%, transparent 0%, color-mix(in oklch, var(--bg-deep) 35%, transparent) 65%, color-mix(in oklch, var(--bg-deep) 80%, transparent) 100%)", }, quiet: { position: "absolute", inset: 0, background: "radial-gradient(80% 60% at 50% 0%, color-mix(in oklch, var(--fg) 4%, transparent) 0%, transparent 60%), var(--bg-deep)", }, grain: { position: "absolute", inset: 0, opacity: 0.35, mixBlendMode: "overlay", backgroundImage: "repeating-linear-gradient(0deg, color-mix(in oklch, var(--fg) 3%, transparent) 0 1px, transparent 1px 3px)", pointerEvents: "none", }, }; function Backdrop({ variant = "hero", parallaxY = 0 }) { const { isMobile } = useViewport(); if (variant === "hero") { return (