"use client"; import { useEffect, useLayoutEffect, useRef, useState, type CSSProperties, type ReactNode } from "react"; import "./tideline-cta.css"; /** * Tideline CTA * A closing section that shows how full the event is. As it scrolls into * view a tide rises to the real share of seats taken, rolling at the surface, * and every word inverts exactly along the wave. The button floats on the * waterline like a buoy, so the way in sits right where the room runs out. */ type Props = { eyebrow?: string; headline: ReactNode; sub?: ReactNode; /** 0–1: how full it is. */ taken: number; action: string; href?: string; details?: string[]; theme?: "paper" | "night"; motion?: "full" | "reduced"; className?: string; }; export function TidelineCta({ eyebrow, headline, sub, taken, action, href = "#", details = [], theme = "night", motion = "full", className = "" }: Props) { const root = useRef(null); const [h, setH] = useState(0); const [seen, setSeen] = useState(false); const pct = Math.round(taken * 100); useLayoutEffect(() => { const el = root.current!; const read = () => setH(el.offsetHeight); read(); const ro = new ResizeObserver(read); ro.observe(el); return () => ro.disconnect(); }, []); // Rise once, when most of the section is on screen. useEffect(() => { const el = root.current!; const io = new IntersectionObserver(([e]) => { if (e.isIntersecting) { setSeen(true); io.disconnect(); } }, { threshold: 0.35 }); io.observe(el); return () => io.disconnect(); }, []); const face = (
{eyebrow &&

{eyebrow}

}

{headline}

{sub &&

{sub}

}

{pct}% of seats taken

{details.length > 0 && ( )}
); return (
{face}
); }