"use client"; import { useEffect, useState } from "react"; import Link from "next/link"; import Image from "next/image"; import { AnimatePresence, motion } from "framer-motion"; import { useInView } from "react-intersection-observer"; import { ArrowRight, Code, Sparkles, categoryIcons } from "@/components/ui/icons"; import { serviceCategories } from "@/data/services"; /** * Services catalog — a sticky scroll-spy index (left) paired with rich, * elevated service cards (right). The index highlights the category currently * in view and smooth-scrolls to any category on click; on mobile it collapses * to a horizontal quick-jump pill row. Brand-strict: dark surfaces, orange/gold * accents, Google Sans, scroll-reveal matching the home sections. */ const EASE = [0.21, 0.47, 0.32, 0.98]; const container = { hidden: {}, show: { transition: { staggerChildren: 0.07 } } }; const rise = { hidden: { opacity: 0, y: 28 }, show: { opacity: 1, y: 0, transition: { duration: 0.55, ease: EASE } }, }; /* Short social-proof blurbs for the sticky rail. Swap with real client quotes; the full video testimonials live on the home page. */ const REVIEWS = [ { quote: "From whiteboard sketch to a live product in fourteen weeks — and it hasn't missed a beat since.", name: "Priya Sharma", role: "Founder, Fintech startup", metric: "14 wks to launch", }, { quote: "They think like owners — challenged our roadmap where it mattered and shipped exactly what users needed.", name: "Daniel Reyes", role: "Product Lead, SaaS", metric: "2.4× activation", }, { quote: "Our AI assistant now handles half our support volume. Cerkel made the complex feel simple.", name: "Aisha Khan", role: "COO, Logistics platform", metric: "−50% tickets", }, ]; /* One success story per capability area, keyed by category slug. Swap the copy/metrics/images with real case studies; link points to the portfolio for now. Images are existing optimized assets in /public/images/opt. */ const SUCCESS_STORIES = { "game-development": { image: "/images/opt/HeroBanner1.webp", client: "Game studio", industry: "Gaming · Multiplayer Development", result: "Launched a cross-platform multiplayer game to 1M+ players.", summary: "Built in Unity with low-latency netcode and live ops, shipping to mobile and PC from one codebase.", metrics: [ { value: "1M+", label: "players" }, { value: "60 FPS", label: "on mobile" }, { value: "4.7★", label: "store rating" }, ], quote: "They nailed the feel of the game and the netcode held up on launch day. Players noticed — and stayed.", person: { name: "Marcus Hale", role: "Studio Lead · Gaming" }, }, "data-analytics-ai": { image: "/images/opt/HeroBanner3.png", client: "Retail group", industry: "Retail · Data Analytics & AI", result: "Turned scattered data into AI-driven decisions leadership trusts.", summary: "Unified pipelines into a single source of truth, then layered ML forecasting that lifted conversion.", metrics: [ { value: "2.4×", label: "activation" }, { value: "−35%", label: "churn" }, { value: "1", label: "source of truth" }, ], quote: "For the first time, the whole leadership team is looking at the same numbers — and the forecasts are right.", person: { name: "Sara Whitman", role: "CMO · Retail group" }, }, "web-software-development": { image: "/images/opt/HeroBanner1.webp", client: "Fintech startup", industry: "Finance · Web & Software Development", result: "Shipped a production fintech platform in 14 weeks.", summary: "Designed, built and launched the full web and mobile product end to end.", metrics: [ { value: "14 wks", label: "idea to launch" }, { value: "99.9%", label: "uptime" }, { value: "4.8★", label: "app rating" }, ], quote: "Cerkel took us from a whiteboard sketch to a live product in fourteen weeks — and it hasn't missed a beat since.", person: { name: "Priya Sharma", role: "Founder · Fintech startup" }, }, "media-creative": { image: "/images/opt/Pillar1.webp", client: "Consumer brand", industry: "Brand · Media & Creative", result: "Tripled engagement with a full rebrand and launch content.", summary: "Delivered identity, motion system and social creatives, rolled out consistently across every channel.", metrics: [ { value: "3.1×", label: "engagement" }, { value: "+48%", label: "reach" }, { value: "12", label: "channels unified" }, ], quote: "Our brand finally looks the way it should — and the launch content performed better than anything we'd run.", person: { name: "Sara Whitman", role: "CMO · Consumer brand" }, }, }; function Stars({ className = "h-3.5 w-3.5" }) { return ( {Array.from({ length: 5 }).map((_, i) => ( ))} ); } /** Auto-rotating client review card — fills the sticky rail beneath the index. */ function CatalogReview() { const [i, setI] = useState(0); const r = REVIEWS[i]; useEffect(() => { const id = setTimeout(() => setI((p) => (p + 1) % REVIEWS.length), 6000); return () => clearTimeout(id); }, [i]); return (
What clients say
{r.metric}

“{r.quote}”

{r.name.split(" ").map((n) => n[0]).join("")} {r.name} {r.role}
{REVIEWS.map((_, idx) => (
); } /** Smooth, header-offset-aware jump (falls back to native if Lenis is absent). */ function scrollToCategory(e, slug) { e.preventDefault(); const el = document.getElementById(slug); if (!el) return; if (window.lenis) window.lenis.scrollTo(el, { offset: -104 }); else el.scrollIntoView({ behavior: "smooth" }); } /** One catalog block; reports itself active to the index when centered. */ function CategoryBlock({ category, index, onActive }) { const Icon = categoryIcons[category.slug] ?? Code; const no = String(index + 1).padStart(2, "0"); const story = SUCCESS_STORIES[category.slug]; const { ref } = useInView({ rootMargin: "-45% 0px -50% 0px", onChange: (inView) => inView && onActive(index), }); return (
{/* Header */}
{no} / {String(serviceCategories.length).padStart(2, "0")}

{category.title}

{category.description}

{/* Cards */} {category.services.map((s) => ( {/* top accent line + corner sheen on hover */} ))} {/* Success story — image-backed results card + client quote card */} {story && ( {/* Results card (image background) */} Success story

{story.result}

{story.summary}

{story.metrics.map((m) => (
{m.value}
{m.label}
))}
View success story
{/* Quote card */}
{story.quote}
)}
); } export default function ServicesCatalog() { const [active, setActive] = useState(0); return (
{/* Mobile quick-jump pills */}
{serviceCategories.map((c, i) => ( scrollToCategory(e, c.slug)} className={ "shrink-0 rounded-full border px-4 py-2 text-xs font-medium transition-colors duration-300 " + (active === i ? "border-primary/50 bg-primary/10 text-primary" : "border-border bg-surface/60 text-muted-foreground") } > {c.title} ))}
{/* Sticky scroll-spy index (desktop) */} {/* Catalog */}
{serviceCategories.map((c, i) => ( ))}
); }