// HomeMotion.jsx — motion layer for the homepage: staggered reveals, a live engagement // timeline, a global threat-map band, animated section dividers, and a tilt wrapper. // ── Stagger: reveals direct children one after another when scrolled into view const Stagger = ({ children, step = 70, style, className }) => { const ref = React.useRef(null); const [on, setOn] = React.useState(false); React.useEffect(() => { const el = ref.current; if (!el) return; const obs = new IntersectionObserver(([e]) => { if (e.isIntersecting) { setOn(true); obs.disconnect(); } }, { threshold: 0.12 }); obs.observe(el); return () => obs.disconnect(); }, []); return (
{React.Children.map(children, (c, i) => c == null ? c : (
{c}
))}
); }; // ── Tilt: subtle 3D tilt that follows the cursor, with a moving highlight const Tilt = ({ children, max = 4, style }) => { const ref = React.useRef(null); const [t, setT] = React.useState({ rx: 0, ry: 0, gx: 50, gy: 50, on: false }); const onMove = (e) => { const r = ref.current.getBoundingClientRect(); const px = (e.clientX - r.left) / r.width, py = (e.clientY - r.top) / r.height; setT({ rx: (0.5 - py) * max * 2, ry: (px - 0.5) * max * 2, gx: px * 100, gy: py * 100, on: true }); }; const onLeave = () => setT({ rx: 0, ry: 0, gx: 50, gy: 50, on: false }); return (
{children}
); }; // ── SectionEdge with a travelling light const LiveEdge = () => (
); // ── Engagement timeline: a live, looping view of one engagement from scoping to retest const TL_STEPS = [ { d: 'Day 0', t: 'Scoping call', m: '30 minutes. Scope, roles, and objectives agreed.', icon: 'chat' }, { d: 'Day 2', t: 'Fixed-fee proposal', m: 'Statement of work and rules of engagement signed.', icon: 'layers' }, { d: 'Day 4', t: 'Kickoff', m: 'Your tester joins the shared channel. Test accounts ready.', icon: 'user' }, { d: 'Day 5', t: 'Testing begins', m: 'Daily updates. Critical findings disclosed within one hour.', icon: 'target' }, { d: 'Day 14', t: 'Report and readout', m: 'Executive summary and technical report walked through live.', icon: 'code' }, { d: 'Day 41', t: 'Free retest', m: 'Every High and Critical verified fixed. Letter refreshed.', icon: 'check' }, ]; const EngagementTimeline = () => { const ref = React.useRef(null); const [seen, setSeen] = React.useState(false); const [i, setI] = React.useState(0); React.useEffect(() => { const el = ref.current; if (!el) return; const obs = new IntersectionObserver(([e]) => { if (e.isIntersecting) { setSeen(true); obs.disconnect(); } }, { threshold: 0.25 }); obs.observe(el); return () => obs.disconnect(); }, []); React.useEffect(() => { if (!seen) return; const t = setInterval(() => setI(x => (x + 1) % TL_STEPS.length), 2200); return () => clearInterval(t); }, [seen]); const pct = (i / (TL_STEPS.length - 1)) * 100; return (

Timeline

From first call to verified fix

A typical two-week engagement, with the free retest included.

{/* Track */}
{TL_STEPS.map((s, k) => { const active = k === i, done = k < i; return ( ); })}
); }; // ── Global reach band: ThreatMap canvas with three live counters const GlobalBand = () => { const ref = React.useRef(null); const [seen, setSeen] = React.useState(false); React.useEffect(() => { const el = ref.current; if (!el) return; const obs = new IntersectionObserver(([e]) => { if (e.isIntersecting) { setSeen(true); obs.disconnect(); } }, { threshold: 0.2 }); obs.observe(el); return () => obs.disconnect(); }, []); const Counter = ({ to, suffix = '', label }) => { const [v, setV] = React.useState(0); React.useEffect(() => { if (!seen) return; const s = performance.now(); let raf; const tick = (t) => { const p = Math.min(1, (t - s) / 1400); setV(Math.round(to * (1 - Math.pow(1 - p, 3)))); if (p < 1) raf = requestAnimationFrame(tick); }; raf = requestAnimationFrame(tick); return () => cancelAnimationFrame(raf); }, [seen]); return (
{v.toLocaleString()}{suffix}
{label}
); }; return (

The team

Built for how your team works

Engagements are delivered remotely and scheduled around your working hours, with your data handled according to your residency requirements.

{/* Coverage facts drawn from this page (Services, WhyUs, FAQ), not client statistics */}
); }; // ── Floating "book a call" pill that appears after the hero and hides near the contact form const FloatingCta = () => { const [show, setShow] = React.useState(false); React.useEffect(() => { const onScroll = () => { const c = document.getElementById('contact'); const nearContact = c ? c.getBoundingClientRect().top < window.innerHeight : false; setShow(window.scrollY > window.innerHeight * 0.9 && !nearContact); }; onScroll(); window.addEventListener('scroll', onScroll, { passive: true }); return () => window.removeEventListener('scroll', onScroll); }, []); return ( Scoping calls this week Get a quote ); }; Object.assign(window, { Stagger, Tilt, LiveEdge, EngagementTimeline, GlobalBand, FloatingCta });