// HpBubbles — fixed full-viewport animated background. // Three particle types layered for depth: // 1) Rising bubbles — large soft circles that drift upward // 2) Twinkling dots — tiny static dots that breathe in/out // 3) Shooting stars — occasional diagonal coral streaks // // Pure CSS animation — no JS loop, no canvas. Hidden when prefers-reduced-motion. function HpBubbles() { // Bubbles — randomized but stable (computed once, never re-rendered) const bubbles = React.useMemo(() => { const arr = []; const count = 14; for (let i = 0; i < count; i++) { arr.push({ x: Math.round((i * 7.3 + 5) % 95), // horizontal % (spread) size: 36 + ((i * 17) % 110), // 36–146px duration: 14 + ((i * 3) % 14), // 14–28s delay: -((i * 1.7) % 18), // negative = mid-cycle sway: ((i * 11) % 10) - 5, // -5 to 5 tint: i % 3, // 0 coral, 1 warm, 2 cool }); } return arr; }, []); // Twinkling micro-dots const dots = React.useMemo(() => { const arr = []; const count = 36; for (let i = 0; i < count; i++) { arr.push({ x: Math.round((i * 13.7 + 3) % 100), y: Math.round((i * 19.3 + 7) % 100), size: 2 + ((i * 5) % 4), // 2–6px duration: 2.4 + ((i * 0.3) % 3), // 2.4–5.4s delay: -((i * 0.7) % 4), tint: i % 4, // 4 tints }); } return arr; }, []); // Shooting stars (rare diagonal streaks) const stars = React.useMemo(() => ([ { x: 12, y: 18, duration: 9, delay: -2 }, { x: 70, y: 35, duration: 11, delay: -5 }, { x: 40, y: 60, duration: 13, delay: -8 }, ]), []); return ( ); } window.HpBubbles = HpBubbles;