all hero section add image

This commit is contained in:
2026-06-30 16:59:52 +05:30
parent 545a6097eb
commit 61ab517a21
15 changed files with 494 additions and 420 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 755 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 509 KiB

BIN
public/contact page1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 MiB

BIN
public/contact.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 MiB

BIN
public/images/business1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 MiB

BIN
public/images/home1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 MiB

BIN
public/images/people1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 MiB

View File

@@ -1,15 +1,11 @@
"use client"; "use client";
import Link from "next/link"; import Image from "next/image";
import { motion } from "framer-motion"; import { motion } from "framer-motion";
import { HeroVisualCollage } from "@/components/layout/HeroVisualCollage";
import { FeatureStatsRow } from "@/components/ui/FeatureStatsRow"; import { FeatureStatsRow } from "@/components/ui/FeatureStatsRow";
import type { Variants } from "framer-motion";
import { import {
fadeInSlow, fadeInSlow,
fadeUp,
staggerSlow, staggerSlow,
viewport,
} from "@/lib/animations"; } from "@/lib/animations";
const HERO_STATS = [ const HERO_STATS = [
@@ -19,15 +15,6 @@ const HERO_STATS = [
{ title: "Coimbatore & Beyond", icon: "location_city", desc: "Growing neighbourhood reach" }, { title: "Coimbatore & Beyond", icon: "location_city", desc: "Growing neighbourhood reach" },
]; ];
const COLLAGE_CARDS = [
{ text: "Local First", icon: "store" },
{ text: "Trusted Network", icon: "verified" },
{ text: "Connected Communities", icon: "groups" },
];
// Choreography: deliberate, slow-stagger sequence — thoughtful and purposeful
// badge fades in (opacity only) → h1 sweeps from left → p fades up → CTAs fade up
// The collage scales up softly, reinforcing the "built carefully" feeling
const badgeVariant = fadeInSlow; const badgeVariant = fadeInSlow;
const titleVariant = { const titleVariant = {
hidden: { opacity: 0, x: -30 }, hidden: { opacity: 0, x: -30 },
@@ -45,103 +32,56 @@ const descVariant = {
transition: { duration: 0.6, ease: [0.22, 1, 0.36, 1] as [number, number, number, number] }, transition: { duration: 0.6, ease: [0.22, 1, 0.36, 1] as [number, number, number, number] },
}, },
}; };
const ctaVariant = fadeUp;
const collageVariant = {
hidden: { opacity: 0, scale: 0.92 },
visible: {
opacity: 1,
scale: 1,
transition: { duration: 0.95, ease: [0.22, 1, 0.36, 1] as [number, number, number, number], delay: 0.2 },
},
};
// Trust-feeling card variant: no spring bounce, deliberate easing
const trustCardVariant: Variants = {
hidden: { opacity: 0, y: 20 },
visible: {
opacity: 1,
y: 0,
transition: { duration: 0.7, ease: [0.22, 1, 0.36, 1] as [number, number, number, number] },
},
};
export function AboutHero() { export function AboutHero() {
return ( return (
<section className="w-full flex flex-col pt-6 md:pt-10 select-none bg-gradient-to-br from-white via-[#FEFCFF] to-[#F4ECFA]"> <section className="w-full flex flex-col select-none bg-white">
<div className="border-b border-[#6330D6]/10"> <div className="relative overflow-hidden border-b border-[#6330D6]/10 bg-[#FAF8FC]">
<div className="grid grid-cols-1 lg:grid-cols-[45%_55%] items-center gap-10 lg:gap-6 px-6 md:px-12 lg:px-16 pb-12 max-w-[1600px] mx-auto"> <Image
src="/about.png"
alt=""
fill
sizes="100vw"
className="absolute inset-0 z-0 h-full w-full object-cover object-[68%_center] md:object-[64%_center] xl:object-center"
priority
aria-hidden="true"
/>
<div className="relative z-10 flex min-h-[560px] items-center justify-center px-6 pt-20 pb-10 sm:min-h-[580px] sm:px-8 sm:pt-24 md:min-h-[610px] md:px-12 md:py-20 lg:min-h-[650px] lg:px-16 lg:py-24 xl:min-h-[680px] max-w-[1600px] mx-auto">
{/* Left Column: slow, deliberate stagger — thoughtful pacing */}
<motion.div <motion.div
className="flex flex-col text-left max-w-xl" className="flex flex-col items-center text-center w-full max-w-[780px] relative z-20"
variants={staggerSlow} variants={staggerSlow}
initial="hidden" initial="hidden"
animate="visible" animate="visible"
> >
<motion.span <motion.span
variants={badgeVariant} variants={badgeVariant}
className="inline-flex items-center gap-1.5 px-3 py-1 rounded-full text-xs font-black tracking-widest bg-[#6330D6]/10 text-[#6330D6] uppercase mb-6 w-fit" className="inline-flex items-center gap-1.5 px-3 py-1 rounded-full text-xs font-black tracking-widest bg-white/15 backdrop-blur-[8px] border border-white/20 text-white uppercase mb-6 w-fit [text-shadow:0_2px_6px_rgba(0,0,0,0.35),0_8px_24px_rgba(0,0,0,0.25)]"
> >
About Nearle About Nearle
</motion.span> </motion.span>
<motion.h1 <motion.h1
variants={titleVariant} variants={titleVariant}
className="font-display text-4xl sm:text-5xl lg:text-[48px] xl:text-[54px] font-black text-[#16001D] leading-[1.1] tracking-tight" className="font-display text-4xl sm:text-5xl lg:text-[48px] xl:text-[54px] font-black text-white leading-[1.1] tracking-tight [text-shadow:0_2px_6px_rgba(0,0,0,0.35),0_8px_24px_rgba(0,0,0,0.25)]"
> >
Built for Every Built for Every
<br /> <br />
<span className="text-[#6330D6]">Neighbourhood.</span> <span className="text-white">Neighbourhood.</span>
</motion.h1> </motion.h1>
<motion.p <motion.p
variants={descVariant} variants={descVariant}
className="text-sm md:text-base text-[#5E5866] font-bold mt-6 leading-relaxed" className="text-sm md:text-base font-bold mt-6 leading-[1.75] text-white/96 [text-shadow:0_1px_4px_rgba(0,0,0,0.45)]"
> >
Nearle is India&apos;s first hyper-local managed &ldquo;Neighbourhood living platform&rdquo; which brings all the amenities and requirements of residents to their fingertips. Nearle is India&apos;s first hyper-local managed &ldquo;Neighbourhood living platform&rdquo; which brings all the amenities and requirements of residents to their fingertips.
</motion.p> </motion.p>
<motion.div
variants={ctaVariant}
className="hidden md:flex md:flex-row md:gap-3.5 mt-8"
>
<a
href="#story-section"
className="bg-[#6330D6] hover:bg-[#5225b8] text-white font-black px-8 py-3.5 rounded-xl text-sm md:text-base text-center shadow-md hover:shadow-lg transition-all duration-200 active:scale-[0.98]"
>
Our Story
</a>
<Link
href="/contact"
className="border-2 border-[#6330D6]/20 hover:border-[#6330D6]/40 text-[#6330D6] font-black px-8 py-3.5 rounded-xl text-sm md:text-base text-center transition-all duration-200 hover:bg-[#6330D6]/5 active:scale-[0.98]"
>
Join Our Journey
</Link>
</motion.div>
</motion.div>
{/* Right Column: soft scale-up — gentle and community-first */}
<motion.div
className="w-full"
variants={collageVariant}
initial="hidden"
animate="visible"
>
<HeroVisualCollage
centerImage="/nearlenewlogo.png"
leftImage="/Nearle Business.png"
rightImage="/nearle people.png"
glassCards={COLLAGE_CARDS}
isPhoneCenter={false}
cardVariant={trustCardVariant}
/>
</motion.div> </motion.div>
</div> </div>
</div> </div>
<div className="bg-[#FAF7FD] border-b border-[#6330D6]/10"> <div className="bg-[#FAF7FD] border-b border-[#6330D6]/10">
<div className="px-6 md:px-12 lg:px-16 max-w-[1600px] mx-auto"> <div className="px-6 sm:px-10 max-w-[1600px] mx-auto">
<FeatureStatsRow items={HERO_STATS} /> <FeatureStatsRow items={HERO_STATS} />
</div> </div>
</div> </div>

View File

@@ -1,16 +1,12 @@
"use client"; "use client";
import Link from "next/link"; import Image from "next/image";
import { motion } from "framer-motion"; import { motion } from "framer-motion";
import { HeroVisualCollage } from "@/components/layout/HeroVisualCollage";
import { FeatureStatsRow } from "@/components/ui/FeatureStatsRow"; import { FeatureStatsRow } from "@/components/ui/FeatureStatsRow";
import { import {
slideInLeftSubtle, slideInLeftSubtle,
fadeUp,
fadeIn, fadeIn,
scaleIn,
staggerContainer, staggerContainer,
viewport,
} from "@/lib/animations"; } from "@/lib/animations";
const HERO_BENEFITS = [ const HERO_BENEFITS = [
@@ -20,13 +16,6 @@ const HERO_BENEFITS = [
{ title: "Local Delivery Support", icon: "local_shipping", desc: "Deliver fast & verified" }, { title: "Local Delivery Support", icon: "local_shipping", desc: "Deliver fast & verified" },
]; ];
const COLLAGE_CARDS = [
{ text: "Nearby Customers", icon: "people" },
{ text: "Orders & Offers", icon: "local_offer" },
{ text: "Local Delivery Support", icon: "local_shipping" },
];
// Choreography: badge slides left → title fades up → description fades in (opacity only) → CTAs scale in
const badgeVariant = slideInLeftSubtle; const badgeVariant = slideInLeftSubtle;
const titleVariant = { const titleVariant = {
hidden: { opacity: 0, y: 28 }, hidden: { opacity: 0, y: 28 },
@@ -37,17 +26,27 @@ const titleVariant = {
}, },
}; };
const descVariant = fadeIn; const descVariant = fadeIn;
const ctaVariant = scaleIn;
export function BusinessHero() { export function BusinessHero() {
return ( return (
<section className="w-full flex flex-col pt-6 md:pt-10 select-none bg-gradient-to-br from-white via-[#FEFCFF] to-[#F4ECFA]"> <section className="w-full flex flex-col select-none bg-white">
<div className="border-b border-[#6330D6]/10"> <div className="relative overflow-hidden border-b border-[#6330D6]/10 bg-[#FAF8FC]">
<div className="grid grid-cols-1 lg:grid-cols-[45%_55%] items-center gap-10 lg:gap-6 px-6 md:px-12 lg:px-16 pb-12 max-w-[1600px] mx-auto"> <Image
src="/images/business1.png"
alt=""
fill
sizes="100vw"
className="absolute inset-0 z-0 h-full w-full object-cover object-[62%_center] md:object-[58%_center] xl:object-center"
priority
aria-hidden="true"
/>
<div className="absolute inset-0 z-[1] bg-[linear-gradient(180deg,rgba(250,248,252,0.85)_0%,rgba(250,248,252,0.68)_28%,rgba(250,248,252,0.38)_58%,rgba(250,248,252,0.10)_100%)] md:bg-[radial-gradient(ellipse_72%_88%_at_50%_42%,rgba(250,248,252,0.72)_0%,rgba(250,248,252,0.50)_38%,rgba(250,248,252,0.18)_65%,rgba(250,248,252,0.04)_100%)]" />
<div className="relative z-10 flex min-h-[560px] items-center justify-center px-6 pt-20 pb-10 sm:min-h-[580px] sm:px-8 sm:pt-24 md:min-h-[610px] md:px-12 md:py-20 lg:min-h-[650px] lg:px-16 lg:py-24 xl:min-h-[680px] xl:px-8 max-w-[1600px] mx-auto">
{/* Left Column: animated with unique stagger */} {/* Left Column: animated with unique stagger */}
<motion.div <motion.div
className="flex flex-col text-left max-w-xl" className="flex flex-col items-center text-center w-full max-w-[780px] relative z-20"
variants={staggerContainer} variants={staggerContainer}
initial="hidden" initial="hidden"
animate="visible" animate="visible"
@@ -70,51 +69,16 @@ export function BusinessHero() {
<motion.p <motion.p
variants={descVariant} variants={descVariant}
className="text-sm md:text-base text-[#5E5866] font-bold mt-6 leading-relaxed" className="text-sm md:text-base text-[#16001D] font-bold mt-6 leading-relaxed [text-shadow:0_1px_2px_rgba(255,255,255,0.55)]"
> >
Get discovered by nearby customers, manage orders, and build repeat business from one simple platform. Get discovered by nearby customers, manage orders, and build repeat business from one simple platform.
</motion.p> </motion.p>
<motion.div
variants={ctaVariant}
className="hidden md:flex md:flex-row md:gap-3.5 mt-8"
>
<Link
href="/contact"
className="bg-[#6330D6] hover:bg-[#5225b8] text-white font-black px-8 py-3.5 rounded-xl text-sm md:text-base text-center shadow-md hover:shadow-lg transition-all duration-200 active:scale-[0.98]"
>
List Your Store
</Link>
<Link
href="/contact"
className="border-2 border-[#6330D6]/20 hover:border-[#6330D6]/40 text-[#6330D6] font-black px-8 py-3.5 rounded-xl text-sm md:text-base text-center transition-all duration-200 hover:bg-[#6330D6]/5 active:scale-[0.98]"
>
Explore Solutions
</Link>
</motion.div>
</motion.div>
{/* Right Column: subtle fade-in — HeroVisualCollage internal animations choreograph each element */}
<motion.div
className="w-full"
variants={fadeIn}
initial="hidden"
animate="visible"
transition={{ delay: 0.2 }}
>
<HeroVisualCollage
centerImage="/nearlenewlogo.png"
leftImage="/images/cat-daily-essentials.png"
rightImage="/Nearle Business.png"
glassCards={COLLAGE_CARDS}
isPhoneCenter={false}
/>
</motion.div> </motion.div>
</div> </div>
</div> </div>
<div className="bg-[#FAF7FD] border-b border-[#6330D6]/10"> <div className="bg-[#FAF7FD] border-b border-[#6330D6]/10">
<div className="px-6 md:px-12 lg:px-16 max-w-[1600px] mx-auto"> <div className="px-6 sm:px-10 max-w-[1600px] mx-auto">
<FeatureStatsRow items={HERO_BENEFITS} /> <FeatureStatsRow items={HERO_BENEFITS} />
</div> </div>
</div> </div>

View File

@@ -0,0 +1,295 @@
"use client";
import { motion, useReducedMotion } from "framer-motion";
import { MaterialIcon } from "@/components/ui/MaterialIcon";
// ─── Floating feature card ───────────────────────────────────────────────────
type CardData = { icon: string; title: string; desc: string };
const CARDS: CardData[] = [
{ icon: "verified", title: "Verified Visibility", desc: "Get discovered by nearby shoppers" },
{ icon: "people", title: "More Customers", desc: "Build trust and attract local customers" },
{ icon: "trending_up", title: "Grow Faster", desc: "Increase repeat business" },
];
function FloatingCard({
card, className, entryDelay, floatDelay, floatDist,
}: { card: CardData; className: string; entryDelay: number; floatDelay: number; floatDist: number }) {
const reduce = useReducedMotion();
return (
<motion.div
className={`absolute z-30 ${className}`}
initial={{ opacity: 0, y: 14, scale: 0.92 }}
whileInView={{ opacity: 1, y: 0, scale: 1 }}
viewport={{ once: true, margin: "-30px" }}
transition={{ duration: 0.5, delay: entryDelay, ease: [0.22, 1, 0.36, 1] }}
>
<motion.div
animate={reduce ? {} : { y: [0, floatDist, 0] }}
transition={{ duration: 3.8, repeat: Infinity, ease: "easeInOut", delay: floatDelay }}
className="bg-white/95 backdrop-blur-xl border border-white/80 shadow-[0_8px_28px_rgba(99,48,214,0.13),0_2px_8px_rgba(0,0,0,0.06)] rounded-[14px] px-3.5 py-2.5 flex items-center gap-2.5 w-max"
>
<div className="w-7 h-7 rounded-full bg-[#6330D6]/10 text-[#6330D6] flex items-center justify-center shrink-0">
<MaterialIcon icon={card.icon} size={15} />
</div>
<div>
<div className="text-[12.5px] font-extrabold text-[#16001D] leading-tight">{card.title}</div>
<div className="text-[11px] font-semibold text-[#5E5866] mt-[2px] leading-tight">{card.desc}</div>
</div>
</motion.div>
</motion.div>
);
}
// ─── Phone screen UI (React + Tailwind, no image) ────────────────────────────
function PhoneScreen() {
return (
<div className="w-full h-full flex flex-col bg-[#F6F2FF] overflow-hidden text-[#16001D]">
{/* Header */}
<div className="flex items-center justify-between px-3 pt-2 pb-1.5 bg-white border-b border-[#6330D6]/8 shrink-0">
<div className="flex items-center gap-1">
<div className="w-[18px] h-[18px] rounded-full bg-[#6330D6] flex items-center justify-center shrink-0">
<span className="text-white font-black leading-none" style={{ fontSize: 9 }}>n</span>
</div>
<span className="font-black tracking-tight" style={{ fontSize: 10 }}>nearle</span>
<span className="font-bold text-[#6330D6] bg-[#6330D6]/10 rounded-full leading-none px-1 py-[2px]" style={{ fontSize: 6 }}>BIZ</span>
</div>
<div className="flex items-center gap-1">
<div className="w-[18px] h-[18px] rounded-full bg-[#F0EBF9] flex items-center justify-center">
<MaterialIcon icon="notifications" size={10} className="text-[#6330D6]" />
</div>
<div className="w-[18px] h-[18px] rounded-full bg-[#6330D6] flex items-center justify-center">
<span className="text-white font-black" style={{ fontSize: 7 }}>M</span>
</div>
</div>
</div>
{/* Scrollable content */}
<div className="flex-1 flex flex-col gap-1.5 px-2.5 pt-2 pb-1 overflow-hidden">
{/* Search bar */}
<div className="flex items-center gap-1.5 bg-white rounded-lg px-2 py-[5px] border border-[#6330D6]/10 shrink-0">
<MaterialIcon icon="search" size={9} className="text-[#9B8BB0] shrink-0" />
<span className="text-[#9B8BB0] font-medium" style={{ fontSize: 8 }}>Search shops, offers</span>
</div>
{/* Analytics strip */}
<div className="grid grid-cols-3 gap-1 shrink-0">
{[
{ val: "₹2.4k", label: "Revenue", color: "text-[#6330D6]" },
{ val: "38", label: "Orders", color: "text-[#16001D]" },
{ val: "↑12%", label: "Growth", color: "text-[#16a34a]" },
].map(s => (
<div key={s.label} className="bg-white rounded-lg p-[5px] border border-[#6330D6]/8 flex flex-col gap-[1px]">
<span className={`font-black leading-none ${s.color}`} style={{ fontSize: 10 }}>{s.val}</span>
<span className="font-semibold text-[#5E5866] leading-none" style={{ fontSize: 6.5 }}>{s.label}</span>
</div>
))}
</div>
{/* Featured store card */}
<div className="bg-white rounded-xl overflow-hidden border border-[#6330D6]/8 shadow-[0_2px_8px_rgba(99,48,214,0.07)] shrink-0">
<div className="h-[38px] bg-gradient-to-r from-[#5225b8] to-[#7C3AED] flex items-center px-2.5 gap-1.5">
<div className="w-6 h-6 rounded-lg bg-white/20 flex items-center justify-center shrink-0">
<MaterialIcon icon="storefront" size={12} className="text-white" />
</div>
<div className="flex-1 min-w-0">
<div className="text-white font-black truncate" style={{ fontSize: 8 }}>Green Valley Mart</div>
<div className="flex items-center gap-[3px]">
<MaterialIcon icon="star" size={7} fill className="text-[#FCD34D]" />
<span className="text-white/80 font-medium" style={{ fontSize: 6.5 }}>4.8 · 0.3 km away</span>
</div>
</div>
<div className="flex items-center gap-[2px] bg-[#16a34a]/25 rounded-full px-1.5 py-[2px] shrink-0">
<MaterialIcon icon="verified" size={7} fill className="text-[#4ade80]" />
<span className="text-[#4ade80] font-bold" style={{ fontSize: 6.5 }}>Verified</span>
</div>
</div>
<div className="px-2.5 py-1.5 flex items-center justify-between">
<span className="text-[#5E5866] font-medium" style={{ fontSize: 7 }}>Visitors today</span>
<span className="text-[#6330D6] font-black" style={{ fontSize: 8 }}>124 customers</span>
</div>
</div>
{/* Quick actions */}
<div className="shrink-0">
<div className="font-black mb-1" style={{ fontSize: 8 }}>Quick Actions</div>
<div className="grid grid-cols-4 gap-1">
{[
{ icon: "add_box", label: "Add Item" },
{ icon: "local_offer", label: "Offers" },
{ icon: "analytics", label: "Stats" },
{ icon: "chat", label: "Chat" },
].map(a => (
<div key={a.label} className="flex flex-col items-center gap-[3px]">
<div className="w-7 h-7 rounded-xl bg-[#6330D6]/8 flex items-center justify-center">
<MaterialIcon icon={a.icon} size={13} className="text-[#6330D6]" />
</div>
<span className="text-[#5E5866] font-semibold text-center" style={{ fontSize: 6 }}>{a.label}</span>
</div>
))}
</div>
</div>
{/* Active offers */}
<div className="shrink-0">
<div className="font-black mb-1" style={{ fontSize: 8 }}>Active Offers</div>
<div className="flex gap-1.5">
<div className="flex-1 bg-gradient-to-br from-[#6330D6]/12 to-[#6330D6]/5 rounded-lg p-2 border border-[#6330D6]/15">
<div className="font-black text-[#6330D6]" style={{ fontSize: 10 }}>20% OFF</div>
<div className="text-[#5E5866] font-medium" style={{ fontSize: 6.5 }}>Groceries</div>
</div>
<div className="flex-1 bg-gradient-to-br from-[#f59e0b]/12 to-[#f59e0b]/5 rounded-lg p-2 border border-[#f59e0b]/15">
<div className="font-black text-[#d97706]" style={{ fontSize: 10 }}>15% OFF</div>
<div className="text-[#5E5866] font-medium" style={{ fontSize: 6.5 }}>Daily items</div>
</div>
</div>
</div>
{/* Latest order */}
<div className="bg-white rounded-lg px-2 py-1.5 border border-[#6330D6]/8 flex items-center gap-1.5 shrink-0">
<div className="w-6 h-6 rounded-lg bg-[#6330D6]/10 flex items-center justify-center shrink-0">
<MaterialIcon icon="package_2" size={12} className="text-[#6330D6]" />
</div>
<div className="flex-1 min-w-0">
<div className="font-black" style={{ fontSize: 8 }}>Order #1042</div>
<div className="text-[#5E5866] font-medium truncate" style={{ fontSize: 6.5 }}>340 · 2 items · Preparing</div>
</div>
<div className="w-1.5 h-1.5 rounded-full bg-[#f59e0b] animate-pulse shrink-0" />
</div>
</div>
{/* Bottom navigation */}
<div className="flex items-center justify-around px-1 py-[5px] bg-white border-t border-[#6330D6]/8 shrink-0">
{[
{ icon: "home", active: true },
{ icon: "bar_chart", active: false },
{ icon: "shopping_bag", active: false },
{ icon: "group", active: false },
{ icon: "settings", active: false },
].map(tab => (
<div key={tab.icon} className="flex flex-col items-center gap-[2px]">
<MaterialIcon
icon={tab.icon}
size={14}
fill={tab.active}
className={tab.active ? "text-[#6330D6]" : "text-[#9B8BB0]"}
/>
{tab.active && <div className="w-3 h-[2px] rounded-full bg-[#6330D6]" />}
</div>
))}
</div>
</div>
);
}
// ─── Main visual component ────────────────────────────────────────────────────
export function BusinessHeroVisual() {
const reduce = useReducedMotion();
return (
<div className="relative w-full h-[440px] sm:h-[500px] lg:h-[540px] xl:h-[600px] max-w-[560px] xl:max-w-none mx-auto xl:mx-0 flex items-center justify-center select-none">
{/* Soft radial glows — centred on phone */}
<div className="absolute inset-0 pointer-events-none" aria-hidden>
<div className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-[400px] h-[400px] xl:w-[500px] xl:h-[500px] rounded-full bg-[#7C3AED]/[0.08] blur-[80px]" />
<div className="absolute top-[42%] left-1/2 -translate-x-1/2 -translate-y-1/2 w-[220px] h-[220px] xl:w-[320px] xl:h-[320px] rounded-full bg-[#6330D6]/[0.11] blur-[45px]" />
</div>
{/* Dotted pattern — top-right */}
<div className="absolute top-0 right-0 w-36 h-36 pointer-events-none opacity-20" aria-hidden>
<svg className="w-full h-full text-[#6330D6]" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
<defs>
<pattern id="biz-dots-tr" x="0" y="0" width="14" height="14" patternUnits="userSpaceOnUse">
<circle cx="2" cy="2" r="1.2" opacity="0.45" />
</pattern>
</defs>
<rect width="100%" height="100%" fill="url(#biz-dots-tr)" />
</svg>
</div>
{/* Dotted pattern — bottom-left */}
<div className="absolute bottom-6 left-2 w-24 h-24 pointer-events-none opacity-15" aria-hidden>
<svg className="w-full h-full text-[#6330D6]" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
<defs>
<pattern id="biz-dots-bl" x="0" y="0" width="14" height="14" patternUnits="userSpaceOnUse">
<circle cx="2" cy="2" r="1.2" opacity="0.45" />
</pattern>
</defs>
<rect width="100%" height="100%" fill="url(#biz-dots-bl)" />
</svg>
</div>
{/* ── Phone mockup ─────────────────────────────────────────────────── */}
<motion.div
className="relative z-20"
initial={{ opacity: 0, scale: 0.88 }}
animate={{ opacity: 1, scale: 1 }}
transition={{ duration: 0.7, ease: [0.22, 1, 0.36, 1] }}
style={{ rotate: 6 }}
>
<motion.div
animate={reduce ? {} : { y: [0, -11, 0] }}
transition={{ duration: 4.5, repeat: Infinity, ease: "easeInOut", delay: 0.7 }}
>
{/* Outer bezel */}
<div
className="relative rounded-[34px] sm:rounded-[38px] xl:rounded-[46px] border-[7px] sm:border-[8px] xl:border-[9px] border-[#1d0d30] bg-[#1d0d30] overflow-hidden"
style={{
width: "clamp(164px, 22vw, 280px)",
height: "clamp(328px, 44vw, 560px)",
boxShadow: "0 32px 72px rgba(99,48,214,0.30), 0 10px 28px rgba(0,0,0,0.28)",
}}
>
{/* Screen */}
<div className="absolute inset-0">
<PhoneScreen />
</div>
{/* Dynamic island */}
<div className="absolute top-2.5 left-1/2 -translate-x-1/2 bg-[#0a0515] rounded-full z-20"
style={{ width: "clamp(50px, 6.5vw, 74px)", height: "clamp(17px, 2.2vw, 25px)" }}
/>
{/* Screen glare */}
<div className="absolute inset-0 bg-gradient-to-br from-white/[0.04] via-transparent to-transparent pointer-events-none z-10" />
</div>
</motion.div>
</motion.div>
{/* ── Floating cards ────────────────────────────────────────────────── */}
{/* Card 1 — Verified Visibility · top-right */}
<FloatingCard
card={CARDS[0]}
className="top-[5%] right-[2%] sm:right-[0%] xl:top-[4%] xl:right-[2%]"
entryDelay={0.55}
floatDelay={0}
floatDist={-7}
/>
{/* Card 2 — More Customers · bottom-left */}
<FloatingCard
card={CARDS[1]}
className="bottom-[9%] left-[1%] sm:left-[0%] xl:bottom-[6%] xl:left-[3%]"
entryDelay={0.75}
floatDelay={0.9}
floatDist={-8}
/>
{/* Card 3 — Grow Faster · mid-right */}
<FloatingCard
card={CARDS[2]}
className="top-[43%] right-[1%] sm:right-[0%] xl:top-[44%] xl:right-[3%]"
entryDelay={0.95}
floatDelay={1.7}
floatDist={-6}
/>
</div>
);
}

View File

@@ -1,5 +1,6 @@
"use client"; "use client";
import Image from "next/image";
import { motion } from "framer-motion"; import { motion } from "framer-motion";
import { MaterialIcon } from "@/components/ui/MaterialIcon"; import { MaterialIcon } from "@/components/ui/MaterialIcon";
import { ContactForm } from "@/components/contact/ContactForm"; import { ContactForm } from "@/components/contact/ContactForm";
@@ -52,10 +53,21 @@ const infoStagger = {
export function ContactHero() { export function ContactHero() {
return ( return (
<section className="relative border-b border-[#6330D6]/10 px-4 py-10 md:px-6 md:py-12 lg:px-8 lg:py-14 xl:px-10 xl:py-16 2xl:px-12 2xl:py-20"> <section className="relative overflow-hidden border-b border-[#6330D6]/10 bg-[#FAF8FC] px-4 py-10 md:px-6 md:py-12 lg:px-8 lg:py-14 xl:px-10 xl:py-16 2xl:px-12 2xl:py-20">
<Image
src="/contact page1.png"
alt=""
fill
sizes="100vw"
className="absolute inset-0 z-0 h-full w-full object-cover object-[62%_center] md:object-center"
priority
aria-hidden="true"
/>
<div className="absolute inset-0 z-[1] bg-[linear-gradient(180deg,rgba(250,248,252,0.97)_0%,rgba(250,248,252,0.92)_42%,rgba(250,248,252,0.76)_100%)] md:bg-[linear-gradient(90deg,rgba(250,248,252,0.96)_0%,rgba(250,248,252,0.88)_42%,rgba(250,248,252,0.58)_72%,rgba(250,248,252,0.32)_100%)]" />
<div className="absolute inset-0 z-[1] bg-[linear-gradient(180deg,rgba(255,255,255,0.08)_0%,rgba(255,255,255,0)_58%,rgba(255,255,255,0.72)_100%)]" />
{/* Decorative map grid — not animated so it stays subtle */} {/* Decorative map grid — not animated so it stays subtle */}
<div className="absolute left-[5%] top-[10%] w-[400px] h-[300px] opacity-[0.04] select-none pointer-events-none -z-10"> <div className="absolute left-[5%] top-[10%] w-[400px] h-[300px] opacity-[0.04] select-none pointer-events-none z-[2]">
<svg className="w-full h-full text-[#6330D6]" stroke="currentColor" fill="none" strokeWidth="1.5" viewBox="0 0 400 300"> <svg className="w-full h-full text-[#6330D6]" stroke="currentColor" fill="none" strokeWidth="1.5" viewBox="0 0 400 300">
<path d="M0,50 L400,50 M0,130 L400,130 M0,210 L400,210 M80,0 L80,300 M200,0 L200,300 M320,0 L320,300" /> <path d="M0,50 L400,50 M0,130 L400,130 M0,210 L400,210 M80,0 L80,300 M200,0 L200,300 M320,0 L320,300" />
<path d="M 80,130 C 120,90 160,170 200,130 C 240,90 280,170 320,130" strokeDasharray="3,3" /> <path d="M 80,130 C 120,90 160,170 200,130 C 240,90 280,170 320,130" strokeDasharray="3,3" />
@@ -66,12 +78,12 @@ export function ContactHero() {
</svg> </svg>
</div> </div>
<div className="relative z-10 mx-auto w-full max-w-[1520px]"> <div className="relative z-[3] mx-auto w-full max-w-[1520px]">
<div className="grid grid-cols-1 items-start gap-10 lg:grid-cols-[1.2fr_0.8fr] lg:gap-12 xl:gap-16"> <div className="grid grid-cols-1 items-start gap-10 lg:grid-cols-[1.2fr_0.8fr] lg:gap-12 xl:gap-16">
{/* Left Column — Contact Info: sequential stagger from top */} {/* Left Column — Contact Info: sequential stagger from top */}
<motion.div <motion.div
className="w-full max-w-[760px] py-6 md:py-8 lg:py-10 relative z-10 text-[#16001D]" className="flex flex-col items-center text-center w-full max-w-[760px] py-6 md:py-8 lg:py-10 relative z-10 text-[#16001D]"
variants={staggerContainer} variants={staggerContainer}
initial="hidden" initial="hidden"
animate="visible" animate="visible"
@@ -93,14 +105,14 @@ export function ContactHero() {
<motion.p <motion.p
variants={fadeUp} variants={fadeUp}
className="mt-6 max-w-[620px] text-sm font-bold leading-8 text-[#5E5866] md:text-base xl:text-lg" className="mt-6 max-w-[620px] text-sm font-bold leading-8 text-[#16001D] md:text-base xl:text-lg [text-shadow:0_1px_2px_rgba(255,255,255,0.55)]"
> >
Whether you are a customer, local store owner, or delivery partner, our team is here to help you get started with Nearle. Whether you are a customer, local store owner, or delivery partner, our team is here to help you get started with Nearle.
</motion.p> </motion.p>
{/* Info rows: each row staggers in from left */} {/* Info rows: each row staggers in from left */}
<motion.div <motion.div
className="mt-8 border-t border-[#6330D6]/10" className="mt-8 border-t border-[#6330D6]/10 w-full"
variants={infoStagger} variants={infoStagger}
initial="hidden" initial="hidden"
animate="visible" animate="visible"

View File

@@ -1,15 +1,12 @@
"use client"; "use client";
import Link from "next/link"; import Image from "next/image";
import { motion } from "framer-motion"; import { motion } from "framer-motion";
import { HeroVisualCollage } from "@/components/layout/HeroVisualCollage";
import { FeatureStatsRow } from "@/components/ui/FeatureStatsRow"; import { FeatureStatsRow } from "@/components/ui/FeatureStatsRow";
import { import {
scaleInSpring, scaleInSpring,
fadeUpStrong, fadeUpStrong,
fadeUp, fadeUp,
slideInLeftSubtle,
fadeIn,
staggerFast, staggerFast,
} from "@/lib/animations"; } from "@/lib/animations";
@@ -20,28 +17,29 @@ const HERO_STATS = [
{ title: "Trusted Platform", icon: "star", desc: "Loved by local shoppers" }, { title: "Trusted Platform", icon: "star", desc: "Loved by local shoppers" },
]; ];
const COLLAGE_CARDS = [
{ text: "Discover Nearby", icon: "explore" },
{ text: "Save Favourites", icon: "favorite" },
{ text: "Order Anytime", icon: "shopping_bag" },
];
// Choreography: badge bounces in (spring) → h1 strong fade-up → p subtle up → CTAs slide from left
// Fast stagger (0.07) gives a snappy, energetic feel — phone/fast/mobile-first vibe
const badgeVariant = scaleInSpring; const badgeVariant = scaleInSpring;
const titleVariant = fadeUpStrong; const titleVariant = fadeUpStrong;
const descVariant = fadeUp; const descVariant = fadeUp;
const ctaVariant = slideInLeftSubtle;
export function PeopleHero() { export function PeopleHero() {
return ( return (
<section className="w-full flex flex-col pt-6 md:pt-10 select-none bg-gradient-to-br from-white via-[#FEFCFF] to-[#F4ECFA]"> <section className="w-full flex flex-col select-none bg-white">
<div className="border-b border-[#6330D6]/10"> <div className="relative overflow-hidden border-b border-[#6330D6]/10 bg-[#FAF8FC]">
<div className="grid grid-cols-1 lg:grid-cols-[45%_55%] items-center gap-10 lg:gap-6 px-6 md:px-12 lg:px-16 pb-12 max-w-[1600px] mx-auto"> <Image
src="/images/people1.png"
alt=""
fill
sizes="100vw"
className="absolute inset-0 z-0 h-full w-full object-cover object-[68%_center] md:object-[62%_center] xl:object-center"
priority
aria-hidden="true"
/>
<div className="absolute inset-0 z-[1] bg-[linear-gradient(180deg,rgba(250,248,252,0.85)_0%,rgba(250,248,252,0.68)_28%,rgba(250,248,252,0.38)_58%,rgba(250,248,252,0.10)_100%)] md:bg-[radial-gradient(ellipse_72%_88%_at_50%_42%,rgba(250,248,252,0.72)_0%,rgba(250,248,252,0.50)_38%,rgba(250,248,252,0.18)_65%,rgba(250,248,252,0.04)_100%)]" />
<div className="relative z-10 flex min-h-[560px] items-center justify-center px-6 pt-20 pb-10 sm:min-h-[580px] sm:px-8 sm:pt-24 md:min-h-[610px] md:px-12 md:py-20 lg:min-h-[650px] lg:px-16 lg:py-24 xl:min-h-[680px] max-w-[1600px] mx-auto">
{/* Left Column: snappy fast-stagger sequence */}
<motion.div <motion.div
className="flex flex-col text-left max-w-xl" className="flex flex-col items-center text-center w-full max-w-[780px] relative z-20"
variants={staggerFast} variants={staggerFast}
initial="hidden" initial="hidden"
animate="visible" animate="visible"
@@ -64,51 +62,16 @@ export function PeopleHero() {
<motion.p <motion.p
variants={descVariant} variants={descVariant}
className="text-sm md:text-base text-[#5E5866] font-bold mt-6 leading-relaxed" className="text-sm md:text-base text-[#16001D] font-bold mt-6 leading-relaxed [text-shadow:0_1px_2px_rgba(255,255,255,0.55)]"
> >
Discover verified local stores, save your favorite merchants, and order everyday items with superfast local fulfillment. Discover verified local stores, save your favorite merchants, and order everyday items with superfast local fulfillment.
</motion.p> </motion.p>
<motion.div
variants={ctaVariant}
className="hidden md:flex md:flex-row md:gap-3.5 mt-8"
>
<a
href="#download-section"
className="bg-[#6330D6] hover:bg-[#5225b8] text-white font-black px-8 py-3.5 rounded-xl text-sm md:text-base text-center shadow-md hover:shadow-lg transition-all duration-200 active:scale-[0.98]"
>
Get the App
</a>
<Link
href="/"
className="border-2 border-[#6330D6]/20 hover:border-[#6330D6]/40 text-[#6330D6] font-black px-8 py-3.5 rounded-xl text-sm md:text-base text-center transition-all duration-200 hover:bg-[#6330D6]/5 active:scale-[0.98]"
>
Explore Stores
</Link>
</motion.div>
</motion.div>
{/* Right Column: subtle fade — HeroVisualCollage's internal animations handle phone, images, badges individually */}
<motion.div
className="w-full"
variants={fadeIn}
initial="hidden"
animate="visible"
transition={{ delay: 0.15 }}
>
<HeroVisualCollage
centerImage="/images/app-mockup.png"
leftImage="/images/cat-hot-food.png"
rightImage="/images/cat-health-wellness.png"
glassCards={COLLAGE_CARDS}
isPhoneCenter={true}
/>
</motion.div> </motion.div>
</div> </div>
</div> </div>
<div className="bg-[#FAF7FD] border-b border-[#6330D6]/10"> <div className="bg-[#FAF7FD] border-b border-[#6330D6]/10">
<div className="px-6 md:px-12 lg:px-16 max-w-[1600px] mx-auto"> <div className="px-6 sm:px-10 max-w-[1600px] mx-auto">
<FeatureStatsRow items={HERO_STATS} /> <FeatureStatsRow items={HERO_STATS} />
</div> </div>
</div> </div>

View File

@@ -1,8 +1,8 @@
"use client"; "use client";
import Link from "next/link"; import { Fragment } from "react";
import Image from "next/image"; import Image from "next/image";
import { motion, useReducedMotion } from "framer-motion"; import { motion } from "framer-motion";
import { MaterialIcon } from "@/components/ui/MaterialIcon"; import { MaterialIcon } from "@/components/ui/MaterialIcon";
import { viewport } from "@/lib/animations"; import { viewport } from "@/lib/animations";
@@ -15,7 +15,6 @@ const PROOF_ITEMS = [
{ label: "Trusted", text: "Local Platform", icon: "star" }, { label: "Trusted", text: "Local Platform", icon: "star" },
]; ];
// Left column: badge → line1 mask-reveal → line2 mask-reveal → desc → primary CTA → secondary CTA
const heroStagger = { const heroStagger = {
hidden: {}, hidden: {},
visible: { transition: { staggerChildren: 0.12, delayChildren: 0.05 } }, visible: { transition: { staggerChildren: 0.12, delayChildren: 0.05 } },
@@ -43,21 +42,6 @@ const descVariant = {
visible: { opacity: 1, y: 0, transition: { duration: 0.55, ease: EASE } }, visible: { opacity: 1, y: 0, transition: { duration: 0.55, ease: EASE } },
}; };
const primaryCtaVariant = {
hidden: { opacity: 0, y: 14, scale: 0.97 },
visible: { opacity: 1, y: 0, scale: 1, transition: { duration: 0.45, ease: EASE } },
};
const secondaryCtaVariant = {
hidden: { opacity: 0, x: -14 },
visible: { opacity: 1, x: 0, transition: { duration: 0.4, ease: EASE } },
};
const logoReveal = {
hidden: { opacity: 0, scale: 0.88, y: 20 },
visible: { opacity: 1, scale: 1, y: 0, transition: { duration: 0.75, ease: EASE, delay: 0.15 } },
};
const statStagger = { const statStagger = {
hidden: {}, hidden: {},
visible: { transition: { staggerChildren: 0.08 } }, visible: { transition: { staggerChildren: 0.08 } },
@@ -69,175 +53,102 @@ const statItem = {
}; };
export function Hero() { export function Hero() {
const reducedMotion = useReducedMotion();
return ( return (
<section className="relative overflow-hidden bg-gradient-to-b from-[#FAF8FC] to-[#FFFFFF] select-none w-full"> <section className="bg-white select-none w-full">
{/* ─── DECORATIONS (BEHIND CONTENT) ─── */} <div className="relative overflow-hidden bg-[#FAF8FC]">
<Image
src="/images/home1.png"
alt=""
fill
sizes="100vw"
className="absolute inset-0 z-0 h-full w-full object-cover object-[62%_center] md:object-[58%_center] xl:object-center"
priority
aria-hidden="true"
/>
<div className="absolute inset-0 z-[1] bg-[linear-gradient(180deg,rgba(250,248,252,0.85)_0%,rgba(250,248,252,0.68)_28%,rgba(250,248,252,0.38)_58%,rgba(250,248,252,0.10)_100%)] md:bg-[radial-gradient(ellipse_72%_88%_at_50%_42%,rgba(250,248,252,0.72)_0%,rgba(250,248,252,0.50)_38%,rgba(250,248,252,0.18)_65%,rgba(250,248,252,0.04)_100%)]" />
{/* 1. Large pale lavender partial circle (top-left) */} <div className="page-container relative z-10 flex min-h-[560px] items-center justify-center px-6 pt-20 pb-10 sm:min-h-[580px] sm:px-8 sm:pt-24 md:min-h-[610px] md:py-20 lg:min-h-[650px] lg:py-24 xl:min-h-[680px]">
<motion.div
className="hidden md:block absolute top-[-100px] left-[-100px] w-[350px] h-[350px] rounded-full border-[1.5px] border-[#6D28D9]/15 bg-[#6D28D9]/5 opacity-[0.55] z-0 pointer-events-none"
animate={{ y: [0, -14, 0] }}
transition={{ duration: 14, repeat: Infinity, ease: "easeInOut" }}
/>
{/* 4. Dotted pattern (between left text and right collage) */}
<div className="hidden lg:block absolute left-[41%] top-[25%] w-48 h-48 opacity-[0.35] z-0 pointer-events-none">
<svg className="w-full h-full text-[#6D28D9]" fill="currentColor">
<pattern id="hero-decor-dots" x="0" y="0" width="16" height="16" patternUnits="userSpaceOnUse">
<circle cx="2" cy="2" r="1.5" />
</pattern>
<rect width="100%" height="100%" fill="url(#hero-decor-dots)" />
</svg>
</div>
{/* 6. Large partial purple circle (bottom-right corner) */}
<motion.div
className="absolute bottom-[-100px] right-[-100px] w-[200px] h-[200px] rounded-full bg-[#7C3AED]/80 z-0 pointer-events-none"
animate={{ y: [0, 12, 0] }}
transition={{ duration: 12, repeat: Infinity, ease: "easeInOut" }}
/>
{/* ─── TWO-COLUMN CONTENT GRID ─── */}
<div className="page-container relative grid min-h-[650px] grid-cols-1 lg:grid-cols-[0.92fr_1.08fr] items-center py-16 md:py-20 lg:py-24 z-10 gap-12 lg:gap-6">
{/* LEFT COLUMN: Editorial Typography & Copy */}
<motion.div
className="flex flex-col text-left max-w-xl z-20 relative"
variants={heroStagger}
initial="hidden"
animate="visible"
>
{/* Badge */}
<motion.span
variants={badgeVariant}
className="inline-flex items-center gap-1.5 px-3 py-1 rounded-full text-xs font-black tracking-widest bg-[#6D28D9]/10 text-[#6D28D9] uppercase mb-6 w-fit"
>
Welcome to Nearle
</motion.span>
{/* H1: line-by-line mask reveal */}
<motion.div variants={lineStagger} className="font-display text-4xl sm:text-5xl lg:text-[68px] xl:text-[76px] font-black text-[#16001D] tracking-[-0.05em]">
<div className="overflow-hidden pb-1">
<motion.div variants={lineReveal} className="leading-[0.95]">
Everything Local.
</motion.div>
</div>
<div className="overflow-hidden pb-1">
<motion.div variants={lineReveal} className="leading-[0.95]">
Everything <span className="text-[#6D28D9]">Near.</span>
</motion.div>
</div>
</motion.div>
{/* Description */}
<motion.p
variants={descVariant}
className="max-w-[480px] text-base md:text-lg text-[#6D6172] leading-relaxed font-bold mt-6"
>
Discover verified local stores, exclusive offers, fast delivery, and a better way to shop within your neighbourhood.
</motion.p>
{/* CTAs: primary scales in, secondary slides from left */}
<div className="hidden md:flex md:flex-row md:gap-3.5 mt-8">
<motion.div
variants={primaryCtaVariant}
whileHover={{ scale: 1.03, transition: { duration: 0.2, ease: EASE } }}
whileTap={{ scale: 0.97, transition: { duration: 0.1 } }}
>
<Link
href="/people"
className="bg-[#6D28D9] hover:bg-[#5225b8] text-white font-black px-5 sm:px-8 py-3.5 rounded-xl text-sm md:text-base text-center shadow-md hover:shadow-lg transition-colors duration-200 block"
>
Explore Stores
</Link>
</motion.div>
<motion.div
variants={secondaryCtaVariant}
whileHover={{ scale: 1.03, transition: { duration: 0.2, ease: EASE } }}
whileTap={{ scale: 0.97, transition: { duration: 0.1 } }}
>
<Link
href="/people#download-section"
className="border-2 border-[#6D28D9]/20 hover:border-[#6D28D9]/40 text-[#6D28D9] font-black px-5 sm:px-8 py-3.5 rounded-xl text-sm md:text-base text-center transition-colors duration-200 hover:bg-[#6D28D9]/5 block"
>
Get the App
</Link>
</motion.div>
</div>
</motion.div>
{/* RIGHT COLUMN: Nearle brand logo composition */}
<div className="w-full z-20 flex items-center justify-center py-4 lg:py-0">
<motion.div <motion.div
className="relative flex items-center justify-center" className="relative z-20 flex w-full max-w-[780px] flex-col items-center text-center"
variants={logoReveal} variants={heroStagger}
initial="hidden" initial="hidden"
animate="visible" animate="visible"
> >
{/* Atmospheric glow — elliptical, not circular, fades naturally */} {/* Badge */}
<div <motion.span
className="absolute pointer-events-none" variants={badgeVariant}
style={{ className="inline-flex items-center gap-1.5 px-3 py-1 rounded-full text-xs font-black tracking-widest bg-[#6D28D9]/10 text-[#6D28D9] uppercase mb-6 w-fit"
width: '160%',
height: '160%',
top: '-30%',
left: '-30%',
background: 'radial-gradient(ellipse 60% 50% at 50% 53%, rgba(109,40,217,0.15) 0%, rgba(109,40,217,0.05) 48%, transparent 75%)',
}}
/>
{/* Logo with slow float and grounding shadow */}
<motion.div
animate={!reducedMotion ? { y: [0, -16, 0] } : {}}
transition={{ duration: 11, repeat: Infinity, ease: "easeInOut", delay: 0.8 }}
> >
<Image Welcome to Nearle
src="/nearlenewlogo.png" </motion.span>
alt="Nearle Your Neighbourhood Commerce Platform"
width={480}
height={480}
className="relative z-10 w-[200px] sm:w-[260px] lg:w-[400px] xl:w-[460px] h-auto object-contain select-none"
style={{ filter: 'drop-shadow(0 28px 52px rgba(109,40,217,0.22)) drop-shadow(0 4px 10px rgba(22,0,29,0.06))' }}
priority
/>
</motion.div>
</motion.div>
</div>
{/* H1: line-by-line mask reveal */}
<motion.div variants={lineStagger} className="font-display text-[34px] sm:text-5xl lg:text-[68px] xl:text-[76px] font-black text-[#16001D] tracking-[-0.05em]">
<div className="overflow-hidden pb-1">
<motion.div variants={lineReveal} className="leading-[0.95]">
Everything Local.
</motion.div>
</div>
<div className="overflow-hidden pb-1">
<motion.div variants={lineReveal} className="leading-[0.95]">
Everything <span className="text-[#6D28D9]">Near.</span>
</motion.div>
</div>
</motion.div>
{/* Description */}
<motion.p
variants={descVariant}
className="max-w-[520px] text-base md:text-lg text-[#16001D] leading-relaxed font-bold mt-6 [text-shadow:0_1px_2px_rgba(255,255,255,0.55)]"
>
Discover verified local stores, exclusive offers, fast delivery, and a better way to shop within your neighbourhood.
</motion.p>
</motion.div>
</div>
</div> </div>
{/* ─── BOTTOM PROOF STATS ROW ─── */} {/* ─── BOTTOM PROOF STATS ROW ─── */}
<div className="border-t border-[#EEE7F4]/80 bg-white"> <div className="border-t border-[#EEE7F4]/80 bg-white">
<motion.div <div className="px-6 sm:px-10 max-w-[1600px] mx-auto py-6 md:py-8 lg:py-10">
className="page-container py-8 grid grid-cols-2 md:grid-cols-4 gap-8 md:gap-4 relative z-20" <motion.div
variants={statStagger} className="bg-white rounded-[32px] border border-[#E9D8FD] shadow-[0_10px_35px_rgba(124,58,237,0.08),0_2px_8px_rgba(124,58,237,0.05)] px-6 py-6 md:px-8 md:py-7 lg:px-12 lg:py-8"
initial="hidden" variants={statStagger}
whileInView="visible" initial="hidden"
viewport={viewport} whileInView="visible"
> viewport={viewport}
{PROOF_ITEMS.map((item, idx) => ( >
<motion.div key={item.label} variants={statItem} className="flex items-center gap-4 text-left md:justify-center relative"> <div className="flex flex-col gap-6 md:grid md:grid-cols-2 md:gap-x-8 md:gap-y-6 lg:flex lg:flex-row lg:items-center lg:justify-between lg:gap-0">
{idx > 0 && ( {PROOF_ITEMS.map((item, idx) => (
<div className="hidden md:block absolute left-0 top-1/2 -translate-y-1/2 w-[1px] h-10 bg-[#EEE7F4]" /> <Fragment key={item.label}>
)} <motion.div
<div className="w-10 h-10 rounded-full bg-[#6D28D9]/8 text-[#6D28D9] flex items-center justify-center shrink-0"> variants={statItem}
<MaterialIcon icon={item.icon} size={18} /> className="flex items-center gap-[18px] group cursor-default transition-transform duration-[250ms] hover:-translate-y-1 lg:flex-1 lg:py-2"
</div> >
<div> <div className="w-16 h-16 rounded-full bg-[#F5EDFF] text-[#6D28D9] flex items-center justify-center shrink-0 transition-colors duration-[250ms] group-hover:bg-[#E4D1FF]">
<div className="text-2xl md:text-3xl font-black text-[#16001D] leading-none tracking-tight"> <MaterialIcon icon={item.icon} size={28} />
{item.label} </div>
</div> <div>
<div className="text-xs text-[#6D6172] font-semibold mt-1"> <div className="text-2xl lg:text-[28px] font-black text-[#17051F] leading-none tracking-tight transition-colors duration-[250ms] group-hover:text-[#6D28D9]">
{item.text} {item.label}
</div> </div>
</div> <div className="text-sm lg:text-[15px] font-medium text-[#6B7280] mt-1.5">
</motion.div> {item.text}
))} </div>
</motion.div> </div>
</motion.div>
{idx < PROOF_ITEMS.length - 1 && (
<div
className="hidden lg:block w-px h-[72px] bg-[#E9D8FD] shrink-0 self-center"
aria-hidden="true"
/>
)}
</Fragment>
))}
</div>
</motion.div>
</div>
</div> </div>
</section> </section>

View File

@@ -18,7 +18,7 @@ const CATEGORIES = [
cta: "Shop Fresh", cta: "Shop Fresh",
}, },
{ {
name: "Medicines & Pharmacy", name: "Wellness",
image: "/images/cat-health-wellness.png", image: "/images/cat-health-wellness.png",
tag: "Available Near You", tag: "Available Near You",
tagStyle: "bg-primary text-white", tagStyle: "bg-primary text-white",

View File

@@ -1,5 +1,6 @@
"use client"; "use client";
import { Fragment } from "react";
import { motion } from "framer-motion"; import { motion } from "framer-motion";
import { MaterialIcon } from "./MaterialIcon"; import { MaterialIcon } from "./MaterialIcon";
import { fadeUp, staggerContainer, viewport } from "@/lib/animations"; import { fadeUp, staggerContainer, viewport } from "@/lib/animations";
@@ -17,57 +18,45 @@ type FeatureStatsRowProps = {
export function FeatureStatsRow({ items, className = "" }: FeatureStatsRowProps) { export function FeatureStatsRow({ items, className = "" }: FeatureStatsRowProps) {
return ( return (
<motion.div <div className={`w-full py-6 md:py-8 lg:py-10 ${className}`}>
className={`w-full py-5 md:py-8 ${className}`} <motion.div
variants={staggerContainer} className="bg-white rounded-[32px] border border-[#E9D8FD] shadow-[0_10px_35px_rgba(124,58,237,0.08),0_2px_8px_rgba(124,58,237,0.05)] px-6 py-6 md:px-8 md:py-7 lg:px-12 lg:py-8"
initial="hidden" variants={staggerContainer}
whileInView="visible" initial="hidden"
viewport={viewport} whileInView="visible"
> viewport={viewport}
<div className="grid grid-cols-2 lg:flex lg:flex-row lg:items-center lg:justify-between gap-3 lg:gap-0"> >
{items.map((item, index) => ( <div className="flex flex-col gap-6 md:grid md:grid-cols-2 md:gap-x-8 md:gap-y-6 lg:flex lg:flex-row lg:items-center lg:justify-between lg:gap-0">
<motion.div {items.map((item, index) => (
key={item.title} <Fragment key={item.title}>
variants={fadeUp} <motion.div
className={[ variants={fadeUp}
// ── Mobile card (< 640 px) ────────────────────────────────── className="flex items-center gap-[18px] group cursor-default transition-transform duration-[250ms] hover:-translate-y-1 lg:flex-1 lg:py-2"
"flex flex-col gap-3", >
"bg-white", <div className="w-16 h-16 rounded-full bg-[#F5EDFF] text-[#6330D6] flex items-center justify-center shrink-0 transition-colors duration-[250ms] group-hover:bg-[#E4D1FF]">
"border border-[#6330D6]/10", <MaterialIcon icon={item.icon} size={28} />
"rounded-2xl", </div>
"shadow-[0_2px_14px_rgba(99,48,214,0.07)]", <div className="min-w-0">
"p-4", <h4 className="text-lg lg:text-xl xl:text-2xl font-black text-[#17051F] leading-tight transition-colors duration-[250ms] group-hover:text-[#6330D6]">
// ── Tablet strip (640 px 1023 px) ──────────────────────── {item.title}
"sm:flex-row sm:items-center sm:gap-3.5", </h4>
"sm:bg-transparent", {item.desc && (
"sm:border-0", <p className="text-sm lg:text-[15px] font-medium text-[#6B7280] mt-1 leading-snug">
"sm:rounded-none", {item.desc}
"sm:shadow-none", </p>
"sm:px-3 sm:py-2", )}
// ── Desktop strip (1024 px +) ─────────────────────────────── </div>
"lg:flex-1 lg:px-8 lg:py-0", </motion.div>
"text-left", {index < items.length - 1 && (
index < items.length - 1 ? "lg:border-r lg:border-[#6330D6]/10" : "", <div
] className="hidden lg:block w-px h-[72px] bg-[#E9D8FD] shrink-0 self-center"
.filter(Boolean) aria-hidden="true"
.join(" ")} />
>
<div className="w-9 h-9 rounded-full bg-[#6330D6]/10 text-[#6330D6] flex items-center justify-center shrink-0">
<MaterialIcon icon={item.icon} size={18} />
</div>
<div className="min-w-0">
<h4 className="text-sm md:text-base font-black text-[#16001D] leading-tight">
{item.title}
</h4>
{item.desc && (
<p className="text-[11px] md:text-xs text-[#5E5866] font-semibold mt-0.5 leading-snug">
{item.desc}
</p>
)} )}
</div> </Fragment>
</motion.div> ))}
))} </div>
</div> </motion.div>
</motion.div> </div>
); );
} }