diff --git a/public/images/hero/iphone-chrome.svg b/public/images/hero/iphone-chrome.svg index a5d9087..a2495ce 100644 --- a/public/images/hero/iphone-chrome.svg +++ b/public/images/hero/iphone-chrome.svg @@ -8,9 +8,7 @@ - - - + diff --git a/public/images/hero/iphone-frame.svg b/public/images/hero/iphone-frame.svg index 70b767f..6aa8deb 100644 --- a/public/images/hero/iphone-frame.svg +++ b/public/images/hero/iphone-frame.svg @@ -1,16 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + - - - + diff --git a/src/app/globals.css b/src/app/globals.css index 8a81543..911385d 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -573,6 +573,48 @@ body { } } +/* ─── AI Commerce ambient decoration ─── */ +/* Very slow, very low-contrast drift. Meant to be felt, never watched. + Transform-only so it stays on the compositor. */ +@keyframes ai-orb-drift-a { + 0%, 100% { + transform: translate3d(0, 0, 0) scale(1); + } + 50% { + transform: translate3d(28px, -22px, 0) scale(1.06); + } +} + +@keyframes ai-orb-drift-b { + 0%, 100% { + transform: translate3d(0, 0, 0) scale(1); + } + 50% { + transform: translate3d(-34px, 18px, 0) scale(1.05); + } +} + +@keyframes ai-mote-float { + 0%, 100% { + transform: translate3d(0, 0, 0); + } + 50% { + transform: translate3d(6px, -18px, 0); + } +} + +.ai-orb-a { + animation: ai-orb-drift-a 22s ease-in-out infinite; +} + +.ai-orb-b { + animation: ai-orb-drift-b 27s ease-in-out infinite; +} + +.ai-mote { + animation: ai-mote-float 14s ease-in-out infinite; +} + /* ─── Footer Layout & Sizing System ─── */ .footer-container { box-sizing: border-box; diff --git a/src/app/merchants/page.tsx b/src/app/merchants/page.tsx index 44e1895..393823c 100644 --- a/src/app/merchants/page.tsx +++ b/src/app/merchants/page.tsx @@ -3,6 +3,7 @@ import Link from "next/link"; import { MaterialIcon } from "@/components/ui/MaterialIcon"; import { PremiumPageShell } from "@/components/common/PremiumPageShell"; import { MerchantsHero } from "@/components/heroes/MerchantsHero"; +import { HowItWorks } from "@/components/home/HowItWorks"; import { FAQAccordion } from "@/components/ui/FAQAccordion"; import { AnimatedSection } from "@/components/animations/AnimatedSection"; import { AnimatedGrid, AnimatedCard } from "@/components/animations/AnimatedGrid"; @@ -159,6 +160,7 @@ export default function MerchantsPage() { return ( + {/* ─── Merchant Benefits Grid ─── */}
diff --git a/src/app/page.tsx b/src/app/page.tsx index 8340932..a7297dc 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -1,15 +1,15 @@ import type { Metadata } from "next"; import { PremiumPageShell } from "@/components/common/PremiumPageShell"; import { Hero } from "@/components/home/Hero"; +import { WhyNearleDifferent } from "@/components/home/WhyNearleDifferent"; +import { AICommerceIntro } from "@/components/home/AICommerceIntro"; import { VoiceCommerceExperience } from "@/components/home/VoiceCommerceExperience"; -import { StoreJourney } from "@/components/home/experience/StoreJourney"; import { ServiceCategories } from "@/components/home/ServiceCategories"; import { WhyNearle } from "@/components/home/WhyNearle"; import { HowItWorks } from "@/components/home/HowItWorks"; import { HyperlocalFeatures } from "@/components/home/HyperlocalFeatures"; import { BusinessSection } from "@/components/home/BusinessSection"; import { WhyAICommerceWins } from "@/components/home/WhyAICommerceWins"; -import { AICommerceTeaser } from "@/components/home/AICommerceTeaser"; import { StoreQRSection } from "@/components/home/StoreQRSection"; export const metadata: Metadata = { @@ -29,15 +29,15 @@ export default function HomePage() { return ( + + - - + + - - ); diff --git a/src/app/platform/page.tsx b/src/app/platform/page.tsx index 73ace34..91befb8 100644 --- a/src/app/platform/page.tsx +++ b/src/app/platform/page.tsx @@ -1,6 +1,7 @@ import type { Metadata } from "next"; import { PremiumPageShell } from "@/components/common/PremiumPageShell"; import { PlatformHero } from "@/components/platform/PlatformHero"; +import { CorePrinciples } from "@/components/home/CorePrinciples"; import { PlatformArchitecture } from "@/components/platform/PlatformArchitecture"; import { ProductFeatureGrid } from "@/components/platform/ProductFeatureGrid"; import { ProductLLMWorkflow } from "@/components/platform/ProductLLMWorkflow"; @@ -54,7 +55,8 @@ export default function PlatformPage() { body="Join the neighbourhood stores already running on MerchantOS — with an AI catalog by ProductLLM and a growing base of local shoppers on ConsumerOS." primary={{ href: "/businesses", icon: "storefront", label: "For Business" }} secondary={{ href: "/why-nearle", icon: "auto_awesome", label: "Why AI Commerce" }} - /> + /> +
); } diff --git a/src/app/why-nearle/page.tsx b/src/app/why-nearle/page.tsx index 6bed0fd..c2cc3a0 100644 --- a/src/app/why-nearle/page.tsx +++ b/src/app/why-nearle/page.tsx @@ -14,11 +14,11 @@ import { PullQuote } from "@/components/ui/PullQuote"; import { AICommerceCTA } from "@/components/why-nearle/AICommerceCTA"; export const metadata: Metadata = { - title: "What is AI Commerce?", + title: "What is AI Commerce", description: "AI Commerce starts where quick commerce stops. Nearle digitizes neighbourhood stores with AI, digital storefronts, and ordering — instead of replacing them. Learn how AI Commerce works.", openGraph: { - title: "What is AI Commerce? | Nearle", + title: "What is AI Commerce | Nearle", description: "Neighbourhood stores already have trust, customers, and location. Nearle adds AI, a digital storefront, inventory, and ordering. This is AI Commerce.", url: "https://nearle.in/why-nearle", diff --git a/src/components/home/AICommerceIntro.tsx b/src/components/home/AICommerceIntro.tsx new file mode 100644 index 0000000..edc6222 --- /dev/null +++ b/src/components/home/AICommerceIntro.tsx @@ -0,0 +1,243 @@ +"use client"; + +import { motion, useReducedMotion } from "framer-motion"; +import { MaterialIcon } from "@/components/ui/MaterialIcon"; +import { Spotlight } from "@/components/ui/Spotlight"; +import { fadeUp, staggerContainer, staggerCards, cardReveal, viewport } from "@/lib/animations"; + +const STEPS = [ + { + step: "01", + title: "Natural Intent", + desc: "Tell Nearle what you need in plain Tamil or English. AI understands local store products, brands, and quantities without manual searching.", + icon: "psychology", + badge: "Voice & Text AI", + iconBg: "bg-primary/10 text-primary border-primary/20", + badgeStyle: "bg-primary/10 text-primary border-primary/20", + }, + { + step: "02", + title: "Live Local Discovery", + desc: "AI instantly checks live stock and pricing at verified neighbourhood stores right around your street to find exact matches.", + icon: "storefront", + badge: "Real-Time Stock", + iconBg: "bg-secondary/10 text-secondary border-secondary/20", + badgeStyle: "bg-secondary/10 text-secondary border-secondary/20", + }, + { + step: "03", + title: "Instant Fulfillment", + desc: "Confirms your order, alerts the local shopkeeper to pack, and dispatches a Nearle rider for fast doorstep delivery — all in 1 chat.", + icon: "bolt", + badge: "1-Tap Fulfillment", + iconBg: "bg-[#7C3AED]/10 text-[#7C3AED] border-[#7C3AED]/20", + badgeStyle: "bg-[#7C3AED]/10 text-[#7C3AED] border-[#7C3AED]/20", + }, +]; + +const HIGHLIGHTS = [ + { + title: "Zero App Switching", + sub: "Everything in 1 conversation", + icon: "forum", + iconColor: "bg-primary/10 text-primary", + }, + { + title: "Verified Merchants", + sub: "Trusted neighbourhood shops", + icon: "verified_user", + iconColor: "bg-secondary/10 text-secondary", + }, + { + title: "Live Inventory", + sub: "Real-time store stock", + icon: "inventory_2", + iconColor: "bg-blue-600/10 text-blue-600", + }, + { + title: "Fast Rider Delivery", + sub: "Direct doorstep fulfillment", + icon: "local_shipping", + iconColor: "bg-[#7C3AED]/10 text-[#7C3AED]", + }, +]; + +export function AICommerceIntro() { + const reduce = useReducedMotion(); + + return ( +
+
+ {/* Section Header */} + + + Nearle AI Engine + + + + Neighbourhood Shopping, Reimagined by AI + + + + Instead of searching across multiple apps and comparing items manually, simply tell Nearle what you need. AI handles discovery, stock checking, and ordering — all in one conversation. + + + + {/* Feature Showcase Banner */} + + +
+
+
+ + Conversational Commerce +
+

+ Talk to Nearle AI like you speak to your local shopkeeper +

+

+ Nearle connects natural consumer intent directly to verified local merchant inventory. You ask, AI discovers nearby availability, confirms with the merchant, and dispatches delivery. +

+
+ +
+
+
+ +
+
+

Step 1 Intent

+

Natural Voice & Text Query

+
+
+ +
+
+ +
+
+

Step 2 Match

+

Live Local Shop Scan

+
+
+ +
+
+ +
+
+

Step 3 Deliver

+

Shopkeeper Pack & Rider Delivery

+
+
+
+
+
+
+ + {/* 3 Step Cards Grid */} + + {STEPS.map((step) => ( + +
+
+ + + + + {step.step} + +
+ +
+ {step.badge} +
+ +

+ {step.title} +

+ +

+ {step.desc} +

+
+
+ ))} +
+ + {/* 4 Feature Highlights Grid */} + + {HIGHLIGHTS.map((item) => ( + +
+ +
+
+

+ {item.title} +

+

+ {item.sub} +

+
+
+ ))} +
+
+ + ); +} + + diff --git a/src/components/home/AICommerceTeaser.tsx b/src/components/home/AICommerceTeaser.tsx deleted file mode 100644 index 1fbce61..0000000 --- a/src/components/home/AICommerceTeaser.tsx +++ /dev/null @@ -1,126 +0,0 @@ -"use client"; - -import Link from "next/link"; -import { motion, useReducedMotion } from "framer-motion"; -import { MaterialIcon } from "@/components/ui/MaterialIcon"; -import { fadeUp, staggerContainer, staggerCards, viewport, viewport20 } from "@/lib/animations"; - -const EASE = [0.22, 1, 0.36, 1] as [number, number, number, number]; - -const ROWS = [ - { traditional: "Manual discovery", nearle: "AI discovery" }, - { traditional: "Walk into stores", nearle: "Search nearby instantly" }, - { traditional: "Limited visibility", nearle: "Every local merchant discoverable" }, - { traditional: "Static catalogue", nearle: "AI-organized catalogue" }, -]; - -const rowVariant = { - hidden: { opacity: 0, y: 14 }, - visible: { opacity: 1, y: 0, transition: { duration: 0.45, ease: EASE } }, -}; - -// Priority 4: a compact teaser contrasting traditional commerce with Nearle's -// AI commerce. The full seven-row comparison lives on /why-nearle. -export function AICommerceTeaser() { - const reduce = useReducedMotion(); - - return ( -
-
- - - The Shift - - - Traditional commerce, reimagined by AI - - - -
- {/* Column headers */} -
- - Traditional Commerce - - - Nearle AI Commerce - -
- - - {ROWS.map((row) => ( - - {/* Traditional side */} -
- - - - - {row.traditional} - -
- - {/* Nearle side */} -
- - - - - {row.nearle} - -
-
- ))} -
- - - - Learn More - - - -
-
-
- ); -} diff --git a/src/components/home/CommerceEvolution.tsx b/src/components/home/CommerceEvolution.tsx new file mode 100644 index 0000000..e9e7c26 --- /dev/null +++ b/src/components/home/CommerceEvolution.tsx @@ -0,0 +1,304 @@ +"use client"; + +import { motion, useReducedMotion } from "framer-motion"; +import { MaterialIcon } from "@/components/ui/MaterialIcon"; +import { Spotlight } from "@/components/ui/Spotlight"; +import BorderGlow from "@/components/ui/BorderGlow"; +import { fadeUp, staggerContainer, staggerCards, cardReveal, viewport } from "@/lib/animations"; + +const EASE = [0.22, 1, 0.36, 1] as [number, number, number, number]; + +// BorderGlow config for the highlighted AI Commerce card. `glowColor` is an HSL +// triplet (the component parses "h s l"), so #A855F7 — the middle of the Nearle +// purple family — becomes "271 91 65". The hex values drive the mesh border. +const GLOW = { + backgroundColor: "#FFFFFF", + glowColor: "271 91 65", + colors: ["#7C3AED", "#A855F7", "#C084FC"], + borderRadius: 28, + edgeSensitivity: 28, + glowRadius: 34, + glowIntensity: 0.85, + coneSpread: 22, + animated: true, +} as const; + +type Era = { + step: string; + title: string; + icon: string; + strengths: string[]; + limits: string[]; +}; + +const ERAS: Era[] = [ + { + step: "01", + title: "Traditional Retail", + icon: "storefront", + strengths: ["Local trust", "Personal relationships", "Community presence"], + limits: ["No digital discovery", "Manual operations"], + }, + { + step: "02", + title: "E-Commerce", + icon: "public", + strengths: ["Massive product catalog", "Nationwide delivery", "Digital convenience"], + limits: ["Endless searching", "Generic recommendations", "No local connection"], + }, + { + step: "03", + title: "Quick Commerce", + icon: "bolt", + strengths: ["Fast delivery", "Instant convenience"], + limits: ["Dark store dependency", "High operational cost", "Local merchants excluded"], + }, +]; + +const AI_POINTS = [ + { icon: "psychology", label: "Understands customer intent" }, + { icon: "travel_explore", label: "AI-powered discovery" }, + { icon: "inventory_2", label: "Real-time inventory" }, + { icon: "auto_awesome", label: "Intelligent recommendations" }, + { icon: "storefront", label: "Merchant-first commerce" }, + { icon: "eco", label: "Sustainable local ecosystem" }, +]; + +export function CommerceEvolution() { + const reduce = useReducedMotion(); + + return ( +
+ {/* Ambient mesh — same violet family as the rest of the AI story */} +
+ ); +} diff --git a/src/components/home/CorePrinciples.tsx b/src/components/home/CorePrinciples.tsx new file mode 100644 index 0000000..c5ce123 --- /dev/null +++ b/src/components/home/CorePrinciples.tsx @@ -0,0 +1,352 @@ +"use client"; + +import { motion, useReducedMotion } from "framer-motion"; +import { MaterialIcon } from "@/components/ui/MaterialIcon"; +import { Spotlight } from "@/components/ui/Spotlight"; +import { fadeUp, staggerContainer, staggerSlow, viewport } from "@/lib/animations"; + +// 1. Trust Graphic (Emerald Shield & Checkmark) +function TrustGraphic({ reduce = false }: { reduce?: boolean }) { + return ( +
+ + + + + + + + + + + +
+ ); +} + +// 2. AI Graphic (Purple Sparkles Cluster) +function AIGraphic({ reduce = false }: { reduce?: boolean }) { + return ( +
+ + + + + + +
+ ); +} + +// 3. Merchant First Graphic (Golden Storefront & Canopy) +function MerchantGraphic({ reduce = false }: { reduce?: boolean }) { + return ( +
+ + + + + + + + + + + + + + +
+ ); +} + +// 4. Local Graphic (Sky Pin & Radar Pulse) +function LocalGraphic({ reduce = false }: { reduce?: boolean }) { + return ( +
+ + + + + + + + + + + + +
+ ); +} + +const CARD_MOTES = [ + { left: "20%", top: "35%", size: 4, duration: 4.5, delay: 0 }, + { left: "75%", top: "60%", size: 3, duration: 5.5, delay: 0.8 }, +]; + +const PRINCIPLES = [ + { + word: "Trust", + icon: "verified_user", + line: "Local relationships cannot be replaced.", + badgeStyle: "bg-emerald-500/15 border-emerald-500/30 text-emerald-400", + dotColor: "bg-emerald-400", + spotlightColor: "rgba(52,211,153,0.18)", + renderGraphic: (reduce: boolean) => , + }, + { + word: "AI", + icon: "psychology", + line: "Removes complexity instead of adding more choices.", + badgeStyle: "bg-[#7C3AED]/20 border-[#7C3AED]/40 text-[#C084FC]", + dotColor: "bg-[#C084FC]", + spotlightColor: "rgba(168,85,247,0.20)", + renderGraphic: (reduce: boolean) => , + }, + { + word: "Merchant First", + icon: "storefront", + line: "Technology should empower neighbourhood businesses.", + badgeStyle: "bg-amber-500/15 border-amber-500/30 text-amber-400", + dotColor: "bg-amber-400", + spotlightColor: "rgba(251,191,36,0.18)", + renderGraphic: (reduce: boolean) => , + }, + { + word: "Local", + icon: "near_me", + line: "Every recommendation starts with nearby trusted merchants.", + badgeStyle: "bg-sky-500/15 border-sky-500/30 text-sky-400", + dotColor: "bg-sky-400", + spotlightColor: "rgba(56,189,248,0.18)", + renderGraphic: (reduce: boolean) => , + }, +]; + +export function CorePrinciples() { + const reduce = useReducedMotion(); + + return ( +
+
+
+ {/* Ambient purple wash */} +
+ ); +} diff --git a/src/components/home/Hero.tsx b/src/components/home/Hero.tsx index 3451dc5..9e05e63 100644 --- a/src/components/home/Hero.tsx +++ b/src/components/home/Hero.tsx @@ -2,8 +2,10 @@ import { Fragment, useRef, type MouseEvent } from "react"; import Image from "next/image"; +import Link from "next/link"; import { motion, useReducedMotion, useMotionValue, useSpring, useTransform } from "framer-motion"; import { MaterialIcon } from "@/components/ui/MaterialIcon"; +import { MagneticButton } from "@/components/ui/MagneticButton"; import { HeroLogo } from "@/components/heroes/HeroLogo"; import { viewport } from "@/lib/animations"; @@ -26,7 +28,7 @@ const badgeVariant = { const lineStagger = { hidden: {}, - visible: { transition: { staggerChildren: 0.15, delayChildren: 1.05 } }, + visible: { transition: { staggerChildren: 0.13, delayChildren: 1.0 } }, }; const lineReveal = { @@ -36,7 +38,12 @@ const lineReveal = { const descVariant = { hidden: { opacity: 0, y: 30 }, - visible: { opacity: 1, y: 0, transition: { duration: 0.6, delay: 1.25, ease: EASE } }, + visible: { opacity: 1, y: 0, transition: { duration: 0.6, delay: 1.4, ease: EASE } }, +}; + +const ctaVariant = { + hidden: { opacity: 0, y: 22 }, + visible: { opacity: 1, y: 0, transition: { duration: 0.55, delay: 1.6, ease: EASE } }, }; const statStagger = { @@ -106,49 +113,88 @@ export function Hero() { transition={{ duration: 1.2, ease: "easeOut" }} /> -
+
-
- + {/* `compact` logo spacing: this hero now carries CTAs and the evolution + strip inside it, the same reason BrandsHero uses it. */} +
+ {/* Badge */} Welcome to Nearle - {/* H1: line-by-line reveal */} + {/* H1: line-by-line reveal. Two lines, with the closing word + highlighted in the Nearle purple. */} -
- + + Everything Local. - -
-
- + + + + Everything Near. - -
+ +
{/* Description */} - - Discover verified local stores, exclusive offers, fast delivery, and a better way to shop within your neighbourhood. - +

+ Discover verified local stores, exclusive offers, fast delivery, and a + better way to shop within your neighbourhood. +

+ + + {/* CTAs */} + + + + + Explore AI Commerce + + + + + + See How Nearle Works + + +
diff --git a/src/components/home/HowItWorks.tsx b/src/components/home/HowItWorks.tsx index d21b49a..c70ce08 100644 --- a/src/components/home/HowItWorks.tsx +++ b/src/components/home/HowItWorks.tsx @@ -3,8 +3,37 @@ import Image from "next/image"; import { motion } from "framer-motion"; import { MaterialIcon } from "@/components/ui/MaterialIcon"; -import { fadeUp, scaleIn, slideInLeft, viewport } from "@/lib/animations"; -import { MerchantJourney } from "@/components/home/merchant/MerchantJourney"; +import { + fadeUp, + scaleIn, + staggerContainer, + slideInLeft, + viewport, +} from "@/lib/animations"; + +const STEPS = [ + { + num: "01", + icon: "storefront", + title: "Get Online", + desc: "Introduce your business to your Neighbourhood. Compete with online businesses through your offline store.", + visual: "store", + }, + { + num: "02", + icon: "campaign", + title: "Get Noticed", + desc: "Your products get published to Nearle customers in your neighbourhood through the app. Customers search based on location, products, discounts, and promos.", + visual: "phone", + }, + { + num: "03", + icon: "auto_awesome", + title: "Get Simplified", + desc: "Delight the community with a personalized online experience. Unlock revenue opportunities and marketing strategies that help your business grow further.", + visual: "bag", + }, +]; function OrdersCard() { return ( @@ -80,9 +109,169 @@ function GrowthPill() { ); } +function PhoneMapVisual() { + return ( +
+
+ + {/* REALISTIC MOBILE DEVICE FRAME */} +
+ + {/* Hardware Buttons */} +
+
+
+
+ + {/* Inner Black Bezel */} +
+ + {/* Inner Screen */} +
+ + {/* Dynamic Island */} +
+
+
+
+
+ + {/* Status Bar */} +
+ 9:41 +
+ {/* Signal */} +
+
+
+
+
+
+ {/* Wifi */} + + + + + {/* Battery */} +
+
+
+
+
+
+ + {/* Map Visual Content */} +
+ + + {[ + ["left-[17%] top-[30%]", "bg-primary"], + ["right-[16%] top-[28%]", "bg-[#006D37]"], + ["left-[20%] bottom-[33%]", "bg-[#006D37]"], + ["right-[18%] bottom-[32%]", "bg-primary"], + ["right-[35%] top-[20%]", "bg-primary"], + ].map(([position, color]) => ( +
+
+
+
+
+ ))} + +
+
+
+
+
+
+ +
+

Your Store

+
+ + + 4.8 + + Open + 0.8 km +
+
+
+
+
+
+ Offers +
+
+ Shop +
+
+
+ ); +} + +function StepVisual({ type }: { type: string }) { + if (type === "store") { + return ( +
+
+ 3D local shop storefront with purple awning and now online board +
+
+ ); + } + + if (type === "phone") { + return ( +
+ +
+ ); + } + + return ( +
+
+ {["Offers & Discounts", "Loyal Customers", "Repeat Orders"].map((chip) => ( +
+ {chip} +
+ ))} +
+
+ Nearle grocery bag filled with vegetables and packaged products +
+
+ ); +} + export function HowItWorks() { return ( - <>
{/* HERO AREA */}
@@ -147,32 +336,62 @@ export function HowItWorks() {
-
- {/* MERCHANT JOURNEY — self-contained cinematic showcase (auto-plays in - place; no sticky pin, so no empty scroll-track). */} -
+ {/* CARDS SECTION */} +
- Merchant Journey + How It Works

- From your shelf to a growing business + Build Your Neighbourhood Brand

- Eight steps, powered by AI. Join once, and Nearle turns your shelf into a - discoverable storefront while you stay at the centre of every order. + Three simple milestones to scale your retail reach from offline streets straight into neighbourhood homes.

- -
- + + {STEPS.map((step) => ( + + + {step.num} + +
+ +
+
+

+ {step.title} +

+

+ {step.desc} +

+
+
+ +
+
+ ))} +
+
+ ); } diff --git a/src/components/home/VoiceCommerceExperience.tsx b/src/components/home/VoiceCommerceExperience.tsx index a638ca4..a37798a 100644 --- a/src/components/home/VoiceCommerceExperience.tsx +++ b/src/components/home/VoiceCommerceExperience.tsx @@ -1,7 +1,8 @@ "use client"; +import { useRef } from "react"; import Link from "next/link"; -import { motion } from "framer-motion"; +import { motion, useReducedMotion, useScroll, useTransform } from "framer-motion"; import { MaterialIcon } from "@/components/ui/MaterialIcon"; import { PhoneStage } from "@/components/home/voice/PhoneStage"; import { FloatingRequestCards } from "@/components/home/voice/FloatingRequestCards"; @@ -11,171 +12,183 @@ import { viewport } from "@/lib/animations"; const EASE = [0.22, 1, 0.36, 1] as [number, number, number, number]; const EASE_OUT = [0.16, 1, 0.3, 1] as [number, number, number, number]; -const FEATURE_CHIPS = [ - { emoji: "🎤", label: "Voice Shopping" }, - { emoji: "🧠", label: "Natural Language AI" }, - { emoji: "🏪", label: "Local Merchant Discovery" }, - { emoji: "⚡", label: "Real-Time Availability" }, -]; - -const badgeVariant = { - hidden: { opacity: 0, y: 20 }, - visible: { opacity: 1, y: 0, transition: { duration: 0.6, ease: EASE } }, -}; - -const lineStagger = { +const headStagger = { hidden: {}, - visible: { transition: { staggerChildren: 0.14, delayChildren: 0.12 } }, + visible: { transition: { staggerChildren: 0.14 } }, }; const lineReveal = { - hidden: { y: 48, opacity: 0, filter: "blur(8px)" }, - visible: { y: 0, opacity: 1, filter: "blur(0px)", transition: { duration: 0.85, ease: EASE_OUT } }, + hidden: { y: 44, opacity: 0, filter: "blur(10px)" }, + visible: { y: 0, opacity: 1, filter: "blur(0px)", transition: { duration: 0.9, ease: EASE_OUT } }, }; const descVariant = { - hidden: { opacity: 0, y: 22 }, - visible: { opacity: 1, y: 0, transition: { duration: 0.6, delay: 0.42, ease: EASE } }, -}; - -const chipStagger = { - hidden: {}, - visible: { transition: { staggerChildren: 0.07, delayChildren: 0.56 } }, -}; - -const chipItem = { - hidden: { opacity: 0, y: 12 }, - visible: { opacity: 1, y: 0, transition: { duration: 0.45, ease: EASE } }, -}; - -const ctaVariant = { - hidden: { opacity: 0, y: 16 }, - visible: { opacity: 1, y: 0, transition: { duration: 0.6, delay: 0.86, ease: EASE } }, + hidden: { opacity: 0, y: 20, filter: "blur(8px)" }, + visible: { + opacity: 1, + y: 0, + filter: "blur(0px)", + transition: { duration: 0.95, delay: 0.34, ease: EASE_OUT }, + }, }; const phoneVariant = { - hidden: { opacity: 0, y: 40, scale: 0.96 }, - visible: { opacity: 1, y: 0, scale: 1, transition: { duration: 1.05, delay: 0.15, ease: EASE_OUT } }, + hidden: { opacity: 0, y: 56, scale: 0.955 }, + visible: { + opacity: 1, + y: 0, + scale: 1, + transition: { duration: 1.15, delay: 0.46, ease: EASE_OUT }, + }, }; -// The homepage's product showcase: a live Nearle app running inside the phone, -// so a visitor can watch a spoken request turn into a delivered order without -// installing anything. The Hero above introduces Nearle — this shows the work. +const captionVariant = { + hidden: { opacity: 0, y: 14 }, + visible: { opacity: 1, y: 0, transition: { duration: 0.8, delay: 1.05, ease: EASE } }, +}; + +const glowVariant = { + hidden: { opacity: 0, scale: 0.88 }, + visible: { opacity: 1, scale: 1, transition: { duration: 1.7, ease: EASE } }, +}; + +// The homepage's product moment: one large floating device, centred, running a +// real Nearle request end to end — spoken words, AI reasoning, a nearby +// merchant, the order, the rider, the doorstep. The copy above it is +// deliberately two lines; everything on this canvas exists to hold the eye on +// the phone. export function VoiceCommerceExperience() { + const sectionRef = useRef(null); + const reduced = useReducedMotion(); + + // Soft parallax: the device drifts against the page as the section passes, + // which reads as depth rather than as movement. + const { scrollYProgress } = useScroll({ + target: sectionRef, + offset: ["start end", "end start"], + }); + const phoneY = useTransform(scrollYProgress, [0, 1], [34, -34]); + const auraY = useTransform(scrollYProgress, [0, 1], [-26, 26]); + return ( - // Explicit padding rather than the shared .section rhythm: the cards that - // float above and below the phone need more room than 88px to breathe.
- {/* Voice waves sit behind everything, centred on the phone side */} - - + {/* ─── Ambient canvas ─── */} +
); diff --git a/src/components/home/WhyAICommerceWins.tsx b/src/components/home/WhyAICommerceWins.tsx index 5f35ced..33540d7 100644 --- a/src/components/home/WhyAICommerceWins.tsx +++ b/src/components/home/WhyAICommerceWins.tsx @@ -1,46 +1,32 @@ "use client"; import Link from "next/link"; -import { motion, useReducedMotion } from "framer-motion"; +import { motion } from "framer-motion"; import { MaterialIcon } from "@/components/ui/MaterialIcon"; import { fadeUp, fadeIn, staggerContainer, viewport } from "@/lib/animations"; const CARDS = [ { - title: "Understands your intent", - desc: "Reads natural language and knows what you actually need.", - icon: "psychology", + title: "Neighbourhood Trust", + desc: "Every order is fulfilled by a real local shop your street already knows — not an anonymous warehouse.", + icon: "handshake", color: "bg-primary/5 text-primary border-primary/10", }, { - title: "Finds matching products", - desc: "Maps your intent to real items on your store’s shelves.", - icon: "inventory_2", + title: "AI-Powered Catalog", + desc: "ProductLLM turns a shelf into a live, shoppable catalog in minutes — so any store can go online without the busywork.", + icon: "auto_awesome", color: "bg-secondary/5 text-secondary border-secondary/10", }, { - title: "Recommends alternatives", - desc: "Out of stock? It suggests the closest match in the store.", - icon: "autorenew", + title: "Offline-First Commerce", + desc: "Billing and inventory keep working even when the network drops. Built for how neighbourhood stores really run.", + icon: "wifi_off", color: "bg-[#de96f9]/10 text-primary border-[#de96f9]/20", }, - { - title: "Checks availability", - desc: "Confirms what’s in stock before you place the order.", - icon: "storefront", - color: "bg-secondary/5 text-secondary border-secondary/10", - }, - { - title: "Helps you shop faster", - desc: "Fewer taps — everyday essentials in just seconds.", - icon: "bolt", - color: "bg-primary/5 text-primary border-primary/10", - }, ]; export function WhyAICommerceWins() { - const reduce = useReducedMotion(); - return (
@@ -52,43 +38,39 @@ export function WhyAICommerceWins() { viewport={viewport} > - The Assistant + AI Commerce

- What Nearle AI Does + Why AI Commerce Wins

- The store stays the hero. Nearle AI is the quiet assistant that helps you - find what you need inside it — faster. + Nearle isn’t another delivery app. It’s the AI layer that brings + neighbourhood stores online — without replacing them.

- {CARDS.map((card, i) => ( + {CARDS.map((card) => ( - - - -

+

+ +
+

{card.title}

-

+

{card.desc}

diff --git a/src/components/home/WhyNearleDifferent.tsx b/src/components/home/WhyNearleDifferent.tsx new file mode 100644 index 0000000..4569a80 --- /dev/null +++ b/src/components/home/WhyNearleDifferent.tsx @@ -0,0 +1,174 @@ +"use client"; + +import { motion, useReducedMotion } from "framer-motion"; +import { MaterialIcon } from "@/components/ui/MaterialIcon"; +import { Spotlight } from "@/components/ui/Spotlight"; +import { + fadeUp, + slideInLeftSubtle, + slideInRight, + staggerContainer, + staggerCards, + viewport, +} from "@/lib/animations"; + +const TRADITIONAL = [ + { icon: "hub", text: "Platform owns discovery" }, + { icon: "visibility_off", text: "Merchant becomes invisible" }, + { icon: "search", text: "Endless searching" }, + { icon: "groups", text: "Customer belongs to platform" }, +]; + +const NEARLE = [ + { icon: "psychology", text: "AI understands intent" }, + { icon: "storefront", text: "Merchant stays at the center" }, + { icon: "near_me", text: "Customers discover nearby stores naturally" }, + { icon: "handshake", text: "Technology empowers merchants instead of replacing them" }, +]; + +export function WhyNearleDifferent() { + const reduce = useReducedMotion(); + + return ( +
+
+ + + The Difference + + + Why Nearle Is Different + + + Two ways to bring shopping online. One puts the platform in the middle — the other keeps + the shop you already trust there. + + + +
+ {/* Traditional commerce */} + +
+
+ + + +
+

+ Today +

+

+ Traditional Commerce +

+
+
+ + + {TRADITIONAL.map((item) => ( + + + + + + {item.text} + + + ))} + +
+
+ + {/* Nearle AI Commerce — highlighted */} + + +
+ + + +
+

+ Nearle +

+

+ Nearle AI Commerce +

+
+
+ + + {NEARLE.map((item) => ( + + + + + + {item.text} + + + ))} + +
+
+
+
+
+ ); +} diff --git a/src/components/home/experience/StoreCanvas.tsx b/src/components/home/experience/StoreCanvas.tsx deleted file mode 100644 index 74e6082..0000000 --- a/src/components/home/experience/StoreCanvas.tsx +++ /dev/null @@ -1,314 +0,0 @@ -"use client"; - -import { motion, AnimatePresence } from "framer-motion"; -import { MaterialIcon } from "@/components/ui/MaterialIcon"; -import { AIThinking } from "./AIThinking"; -import { - AI_STEPS, - FULFILMENT_STEPS, - type JourneyStage, - type StoreJourney, -} from "@/hooks/useStoreJourney"; - -const screenEase = [0.22, 1, 0.36, 1] as [number, number, number, number]; -// Slow, smooth screen changes (Apple/Linear-style) instead of snappy cuts. -const screenMotion = { - initial: { opacity: 0, y: 14, scale: 0.985 }, - animate: { opacity: 1, y: 0, scale: 1 }, - exit: { opacity: 0, y: -12, scale: 0.99 }, - transition: { duration: 0.65, ease: screenEase }, -}; - -// Which visual screen a stage maps to (enter-store + search share one screen so -// the transition into typing stays seamless; fulfilment + done share the flow). -function screenKey(stage: JourneyStage): string { - if (stage === "enter-store" || stage === "search") return "storefront"; - if (stage === "done") return "fulfilment"; - return stage; -} - -// The device frame whose inner screen swaps as the journey advances. -export function StoreCanvas({ journey }: { journey: StoreJourney }) { - const { - stage, - stores, - store, - intent, - recommendation, - typed, - thinkingStep, - fulfilStep, - reduced, - selectStore, - } = journey; - - return ( -
- {/* Ambient brand glow */} - {/* Chapter rail — filling line, active beat highlighted, clickable */} -
-
+
+
-
    +
      {steps.map((s, i) => { const active = i === index; const done = i < index; return ( -
    1. +
{/* Controls — manual stepping + replay once the arc has played */} -
+
@@ -140,9 +140,9 @@ export function MerchantJourney() { exit={{ opacity: 0 }} type="button" onClick={replay} - className="ml-1 inline-flex items-center gap-2 rounded-full bg-primary px-4 py-2.5 text-sm font-black text-white transition-colors hover:bg-primary-container" + className="ml-2 inline-flex items-center gap-2 rounded-full bg-primary px-5 py-2.5 text-sm font-bold text-white shadow-md transition-all hover:bg-primary-container hover:shadow-lg" > - + Replay )} diff --git a/src/components/home/merchant/MerchantPhone.tsx b/src/components/home/merchant/MerchantPhone.tsx index aadeaf6..a67db19 100644 --- a/src/components/home/merchant/MerchantPhone.tsx +++ b/src/components/home/merchant/MerchantPhone.tsx @@ -3,233 +3,322 @@ import { motion, AnimatePresence } from "framer-motion"; import { MaterialIcon } from "@/components/ui/MaterialIcon"; import type { MerchantStep, MerchantStageId } from "@/hooks/useMerchantJourney"; +import { useRealTimeClock } from "@/hooks/useRealTimeClock"; const EASE = [0.22, 1, 0.36, 1] as [number, number, number, number]; -const screen = { - initial: { opacity: 0, y: 12 }, - animate: { opacity: 1, y: 0 }, - exit: { opacity: 0, y: -12 }, - transition: { duration: 0.55, ease: EASE }, +const screenVariant = { + initial: { opacity: 0, y: 6, scale: 0.98 }, + animate: { opacity: 1, y: 0, scale: 1 }, + exit: { opacity: 0, y: -6, scale: 0.98 }, + transition: { duration: 0.35, ease: EASE }, }; // The merchant-side companion device. Its screen mirrors the active stage, so // the illustration and the "real app" always tell the same beat of the story. export function MerchantPhone({ step, reduced }: { step: MerchantStep; reduced: boolean }) { + const liveTime = useRealTimeClock(); + return ( -
+
+ {/* Ambient background glow */}