"use client"; import { useEffect, useRef, useState } from "react"; import { motion } from "framer-motion"; import CountUp from "react-countup"; /** * Shared visual-FX primitives for the premium service pages — floating * particles, mouse-tilt cards, an infinite tech belt, scroll-spy counters and * a browser/product mockup frame. Brand-strict (orange/gold on dark). Keep * positions deterministic so client+server markup match (no hydration drift). */ /* Fixed particle field — deterministic so SSR and client agree. */ const DOTS = [ { left: "8%", top: "24%", s: 6, d: 0, dur: 7 }, { left: "18%", top: "68%", s: 4, d: 1.2, dur: 8 }, { left: "32%", top: "16%", s: 5, d: 0.6, dur: 6.5 }, { left: "44%", top: "78%", s: 3, d: 1.8, dur: 9 }, { left: "58%", top: "30%", s: 7, d: 0.3, dur: 7.5 }, { left: "70%", top: "62%", s: 4, d: 1.5, dur: 8.5 }, { left: "82%", top: "22%", s: 5, d: 0.9, dur: 6.8 }, { left: "90%", top: "70%", s: 3, d: 2.1, dur: 9.5 }, { left: "26%", top: "44%", s: 4, d: 1.1, dur: 7.2 }, { left: "64%", top: "48%", s: 5, d: 0.4, dur: 8.1 }, ]; export function Particles({ className = "" }) { return (
); } /* Slow-drifting aurora blobs — a living gradient backdrop for heroes. */ const BLOBS = [ { c: "primary", left: "6%", top: "10%", size: "34rem", dx: 50, dy: -28, dur: 19 }, { c: "accent", left: "60%", top: "2%", size: "30rem", dx: -58, dy: 40, dur: 23 }, { c: "primary", left: "42%", top: "52%", size: "32rem", dx: 32, dy: 30, dur: 27 }, ]; export function Aurora({ className = "" }) { return ( ); } /** Dot-field "wave" backdrop with soft top light beams (AI-agency hero look). */ export function WaveBackdrop({ className = "" }) { return ( ); } /** Canvas dot-wave — a flowing field of dots (sine motion), brighter toward the bottom. The animated "wave" backdrop for heroes. */ export function DotWave({ className = "" }) { const ref = useRef(null); useEffect(() => { const canvas = ref.current; if (!canvas) return; const ctx = canvas.getContext("2d"); let raf = 0; let w = 0; let h = 0; const resize = () => { const dpr = Math.min(window.devicePixelRatio || 1, 2); const rect = canvas.getBoundingClientRect(); w = rect.width; h = rect.height; canvas.width = Math.max(1, Math.floor(w * dpr)); canvas.height = Math.max(1, Math.floor(h * dpr)); ctx.setTransform(dpr, 0, 0, dpr, 0, 0); }; resize(); window.addEventListener("resize", resize); const gap = 26; const draw = (t) => { ctx.clearRect(0, 0, w, h); const time = t * 0.0011; for (let y = 0; y < h + gap; y += gap) { const depth = y / h; // 0 top → 1 bottom for (let x = 0; x < w + gap; x += gap) { const wave = Math.sin(x * 0.011 + time) + Math.sin(y * 0.02 + time * 0.7); const n = (wave + 2) / 4; // 0..1 const radius = 0.5 + n * 1.7; const alpha = (0.05 + n * 0.5) * (0.12 + depth); ctx.beginPath(); ctx.fillStyle = `rgba(245, 245, 246, ${alpha})`; ctx.arc(x, y + wave * 4, radius, 0, Math.PI * 2); ctx.fill(); } } raf = requestAnimationFrame(draw); }; raf = requestAnimationFrame(draw); return () => { cancelAnimationFrame(raf); window.removeEventListener("resize", resize); }; }, []); return ( ); } /** Subtle 3D mouse-tilt + glow-follow wrapper. */ export function TiltCard({ children, className = "", max = 6 }) { const [t, setT] = useState({ rx: 0, ry: 0, gx: "50%", gy: "50%", on: false }); const onMove = (e) => { const r = e.currentTarget.getBoundingClientRect(); const px = (e.clientX - r.left) / r.width - 0.5; const py = (e.clientY - r.top) / r.height - 0.5; setT({ rx: -py * max, ry: px * max, gx: `${((e.clientX - r.left) / r.width) * 100}%`, gy: `${((e.clientY - r.top) / r.height) * 100}%`, on: true, }); }; const reset = () => setT((s) => ({ ...s, rx: 0, ry: 0, on: false })); return (