"use client"; import { useEffect, useRef, type ElementType, type ReactNode, type HTMLAttributes } from "react"; type Variant = "up" | "left" | "right" | "scale"; /** * Scroll-triggered reveal. Uses a single IntersectionObserver (no deps). * Pairs with the `.reveal` / `.is-visible` rules in globals.css. * * CUSTOMIZATION HOOK — MOTION: * variant → direction of entrance * delay → stagger (ms), applied as transition-delay */ export default function Reveal({ children, variant = "up", delay = 0, as: Tag = "div", className = "", style, ...rest }: HTMLAttributes & { children: ReactNode; variant?: Variant; delay?: number; as?: ElementType; className?: string; }) { const ref = useRef(null); useEffect(() => { const el = ref.current; if (!el) return; const io = new IntersectionObserver( (entries) => { entries.forEach((entry) => { if (entry.isIntersecting) { entry.target.classList.add("is-visible"); io.unobserve(entry.target); } }); }, { threshold: 0.12, rootMargin: "0px 0px -8% 0px" } ); io.observe(el); return () => io.disconnect(); }, []); const combinedStyle = delay ? { ...style, transitionDelay: `${delay}ms` } : style; return ( {children} ); }