"use client"; // ============================================================================= // Novarix Networks — Homepage // ============================================================================= // // This file controls the LAYOUT and STYLING of the homepage. // All editable TEXT lives in `/content.ts` at the project root. // // How this file is organised, top to bottom: // 1. Imports + setup // 2. Intro overlay (the animated logo shown on first visit) // 3. Site shell (background gradient + ambient orbs + grid) // 4. Header (logo + navigation) // 5. Hero (big headline + buttons) // 6. Services (three cards under "What we do") // 7. How we engage (three cards under "Working with us") // 8. Contact (the dark contact card) // 9. Footer (company details + copyright) // // Each section is marked with a clear comment header you can search for. // The "use client" line at the top tells Next.js this page runs in the // browser (needed for the animated intro and the mouse-tracking glow). // ============================================================================= import Image from "next/image"; import Link from "next/link"; import { useEffect, useMemo, useState } from "react"; import { site } from "@/content"; import { openCookieBanner } from "@/components/CookieBanner"; // Type for the mouse-pointer position used to move the background glow. type PointerState = { x: number; y: number }; export default function HomePage() { // --------------------------------------------------------------------------- // STATE // --------------------------------------------------------------------------- // showIntro — true while the animated logo intro is playing. // pointer — the mouse position (in % of page width/height). Used by the // soft glow that follows the cursor in the background. // --------------------------------------------------------------------------- const [showIntro, setShowIntro] = useState(false); const [pointer, setPointer] = useState({ x: 50, y: 22 }); // --------------------------------------------------------------------------- // INTRO OVERLAY EFFECT // Plays the animated logo + wordmark the first time someone visits the // site in this browser tab. We remember they've seen it using // sessionStorage so it doesn't replay on every navigation. The intro lasts // ~3.2 seconds, then fades out. // --------------------------------------------------------------------------- useEffect(() => { try { const introSeen = window.sessionStorage.getItem("novarix-intro-seen"); // Only set the "seen" flag if the user has accepted cookies. Without // consent we still play the intro — we just don't remember it played. const consent = window.localStorage.getItem("novarix-cookie-consent"); if (!introSeen) { // Sync once with sessionStorage on first client mount. // eslint-disable-next-line react-hooks/set-state-in-effect setShowIntro(true); if (consent === "ack") { window.sessionStorage.setItem("novarix-intro-seen", "true"); } // The SVG's built-in stroke + fill animation lasts ~3s. // We hold for an extra ~600ms so the CSS fade-out can complete. const timer = window.setTimeout(() => { setShowIntro(false); }, 3600); return () => window.clearTimeout(timer); } } catch { /* storage unavailable — silently skip the intro */ } }, []); // --------------------------------------------------------------------------- // BACKGROUND POSITION // Translates the current mouse pointer into two CSS variables (--mx, --my) // that the .site-shell background gradient reads. Memoised so React doesn't // rebuild the style object on every render. // --------------------------------------------------------------------------- const backgroundStyle = useMemo( () => ({ ["--mx"]: `${pointer.x}%`, ["--my"]: `${pointer.y}%`, }) as React.CSSProperties, [pointer.x, pointer.y] ); return ( <> {/* ===================================================================== INTRO OVERLAY A single self-contained animated SVG of the Novarix wordmark, drawn dead-centre in the viewport. The SVG itself contains all the animation (strokes draw over 2s, fill in over the next 1s — see /public/branding/animated_logo_intro.svg). Hidden after ~3.6s (see the useEffect above + the CSS fade-out timing). ===================================================================== */} {showIntro && (