all hero section add image
|
Before Width: | Height: | Size: 755 KiB |
|
Before Width: | Height: | Size: 509 KiB |
BIN
public/contact page1.png
Normal file
|
After Width: | Height: | Size: 2.5 MiB |
BIN
public/contact.png
Normal file
|
After Width: | Height: | Size: 1.9 MiB |
BIN
public/images/business1.png
Normal file
|
After Width: | Height: | Size: 2.7 MiB |
BIN
public/images/home1.png
Normal file
|
After Width: | Height: | Size: 2.6 MiB |
BIN
public/images/people1.png
Normal file
|
After Width: | Height: | Size: 2.1 MiB |
@@ -1,15 +1,11 @@
|
||||
"use client";
|
||||
|
||||
import Link from "next/link";
|
||||
import Image from "next/image";
|
||||
import { motion } from "framer-motion";
|
||||
import { HeroVisualCollage } from "@/components/layout/HeroVisualCollage";
|
||||
import { FeatureStatsRow } from "@/components/ui/FeatureStatsRow";
|
||||
import type { Variants } from "framer-motion";
|
||||
import {
|
||||
fadeInSlow,
|
||||
fadeUp,
|
||||
staggerSlow,
|
||||
viewport,
|
||||
} from "@/lib/animations";
|
||||
|
||||
const HERO_STATS = [
|
||||
@@ -19,15 +15,6 @@ const HERO_STATS = [
|
||||
{ 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 titleVariant = {
|
||||
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] },
|
||||
},
|
||||
};
|
||||
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() {
|
||||
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]">
|
||||
<div className="border-b border-[#6330D6]/10">
|
||||
<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">
|
||||
<section className="w-full flex flex-col select-none bg-white">
|
||||
<div className="relative overflow-hidden border-b border-[#6330D6]/10 bg-[#FAF8FC]">
|
||||
<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
|
||||
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}
|
||||
initial="hidden"
|
||||
animate="visible"
|
||||
>
|
||||
<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-[#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
|
||||
</motion.span>
|
||||
|
||||
<motion.h1
|
||||
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
|
||||
<br />
|
||||
<span className="text-[#6330D6]">Neighbourhood.</span>
|
||||
<span className="text-white">Neighbourhood.</span>
|
||||
</motion.h1>
|
||||
|
||||
<motion.p
|
||||
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's first hyper-local managed “Neighbourhood living platform” which brings all the amenities and requirements of residents to their fingertips.
|
||||
</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>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<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} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,16 +1,12 @@
|
||||
"use client";
|
||||
|
||||
import Link from "next/link";
|
||||
import Image from "next/image";
|
||||
import { motion } from "framer-motion";
|
||||
import { HeroVisualCollage } from "@/components/layout/HeroVisualCollage";
|
||||
import { FeatureStatsRow } from "@/components/ui/FeatureStatsRow";
|
||||
import {
|
||||
slideInLeftSubtle,
|
||||
fadeUp,
|
||||
fadeIn,
|
||||
scaleIn,
|
||||
staggerContainer,
|
||||
viewport,
|
||||
} from "@/lib/animations";
|
||||
|
||||
const HERO_BENEFITS = [
|
||||
@@ -20,13 +16,6 @@ const HERO_BENEFITS = [
|
||||
{ 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 titleVariant = {
|
||||
hidden: { opacity: 0, y: 28 },
|
||||
@@ -37,17 +26,27 @@ const titleVariant = {
|
||||
},
|
||||
};
|
||||
const descVariant = fadeIn;
|
||||
const ctaVariant = scaleIn;
|
||||
|
||||
export function BusinessHero() {
|
||||
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]">
|
||||
<div className="border-b border-[#6330D6]/10">
|
||||
<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">
|
||||
<section className="w-full flex flex-col select-none bg-white">
|
||||
<div className="relative overflow-hidden border-b border-[#6330D6]/10 bg-[#FAF8FC]">
|
||||
<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 */}
|
||||
<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}
|
||||
initial="hidden"
|
||||
animate="visible"
|
||||
@@ -70,51 +69,16 @@ export function BusinessHero() {
|
||||
|
||||
<motion.p
|
||||
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.
|
||||
</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>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<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} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
295
src/components/heroes/BusinessHeroVisual.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import Image from "next/image";
|
||||
import { motion } from "framer-motion";
|
||||
import { MaterialIcon } from "@/components/ui/MaterialIcon";
|
||||
import { ContactForm } from "@/components/contact/ContactForm";
|
||||
@@ -52,10 +53,21 @@ const infoStagger = {
|
||||
|
||||
export function ContactHero() {
|
||||
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 */}
|
||||
<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">
|
||||
<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" />
|
||||
@@ -66,12 +78,12 @@ export function ContactHero() {
|
||||
</svg>
|
||||
</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">
|
||||
|
||||
{/* Left Column — Contact Info: sequential stagger from top */}
|
||||
<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}
|
||||
initial="hidden"
|
||||
animate="visible"
|
||||
@@ -93,14 +105,14 @@ export function ContactHero() {
|
||||
|
||||
<motion.p
|
||||
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.
|
||||
</motion.p>
|
||||
|
||||
{/* Info rows: each row staggers in from left */}
|
||||
<motion.div
|
||||
className="mt-8 border-t border-[#6330D6]/10"
|
||||
className="mt-8 border-t border-[#6330D6]/10 w-full"
|
||||
variants={infoStagger}
|
||||
initial="hidden"
|
||||
animate="visible"
|
||||
|
||||
@@ -1,15 +1,12 @@
|
||||
"use client";
|
||||
|
||||
import Link from "next/link";
|
||||
import Image from "next/image";
|
||||
import { motion } from "framer-motion";
|
||||
import { HeroVisualCollage } from "@/components/layout/HeroVisualCollage";
|
||||
import { FeatureStatsRow } from "@/components/ui/FeatureStatsRow";
|
||||
import {
|
||||
scaleInSpring,
|
||||
fadeUpStrong,
|
||||
fadeUp,
|
||||
slideInLeftSubtle,
|
||||
fadeIn,
|
||||
staggerFast,
|
||||
} from "@/lib/animations";
|
||||
|
||||
@@ -20,28 +17,29 @@ const HERO_STATS = [
|
||||
{ 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 titleVariant = fadeUpStrong;
|
||||
const descVariant = fadeUp;
|
||||
const ctaVariant = slideInLeftSubtle;
|
||||
|
||||
export function PeopleHero() {
|
||||
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]">
|
||||
<div className="border-b border-[#6330D6]/10">
|
||||
<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">
|
||||
<section className="w-full flex flex-col select-none bg-white">
|
||||
<div className="relative overflow-hidden border-b border-[#6330D6]/10 bg-[#FAF8FC]">
|
||||
<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
|
||||
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}
|
||||
initial="hidden"
|
||||
animate="visible"
|
||||
@@ -64,51 +62,16 @@ export function PeopleHero() {
|
||||
|
||||
<motion.p
|
||||
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.
|
||||
</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>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<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} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
"use client";
|
||||
|
||||
import Link from "next/link";
|
||||
import { Fragment } from "react";
|
||||
import Image from "next/image";
|
||||
import { motion, useReducedMotion } from "framer-motion";
|
||||
import { motion } from "framer-motion";
|
||||
import { MaterialIcon } from "@/components/ui/MaterialIcon";
|
||||
import { viewport } from "@/lib/animations";
|
||||
|
||||
@@ -15,7 +15,6 @@ const PROOF_ITEMS = [
|
||||
{ label: "Trusted", text: "Local Platform", icon: "star" },
|
||||
];
|
||||
|
||||
// Left column: badge → line1 mask-reveal → line2 mask-reveal → desc → primary CTA → secondary CTA
|
||||
const heroStagger = {
|
||||
hidden: {},
|
||||
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 } },
|
||||
};
|
||||
|
||||
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 = {
|
||||
hidden: {},
|
||||
visible: { transition: { staggerChildren: 0.08 } },
|
||||
@@ -69,175 +53,102 @@ const statItem = {
|
||||
};
|
||||
|
||||
export function Hero() {
|
||||
const reducedMotion = useReducedMotion();
|
||||
|
||||
return (
|
||||
<section className="relative overflow-hidden bg-gradient-to-b from-[#FAF8FC] to-[#FFFFFF] select-none w-full">
|
||||
{/* ─── DECORATIONS (BEHIND CONTENT) ─── */}
|
||||
<section className="bg-white select-none w-full">
|
||||
<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) */}
|
||||
<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" }}
|
||||
/>
|
||||
<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]">
|
||||
|
||||
|
||||
{/* 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
|
||||
className="relative flex items-center justify-center"
|
||||
variants={logoReveal}
|
||||
className="relative z-20 flex w-full max-w-[780px] flex-col items-center text-center"
|
||||
variants={heroStagger}
|
||||
initial="hidden"
|
||||
animate="visible"
|
||||
>
|
||||
{/* Atmospheric glow — elliptical, not circular, fades naturally */}
|
||||
<div
|
||||
className="absolute pointer-events-none"
|
||||
style={{
|
||||
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 }}
|
||||
{/* 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"
|
||||
>
|
||||
<Image
|
||||
src="/nearlenewlogo.png"
|
||||
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>
|
||||
Welcome to Nearle
|
||||
</motion.span>
|
||||
|
||||
{/* 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>
|
||||
|
||||
{/* ─── BOTTOM PROOF STATS ROW ─── */}
|
||||
<div className="border-t border-[#EEE7F4]/80 bg-white">
|
||||
<motion.div
|
||||
className="page-container py-8 grid grid-cols-2 md:grid-cols-4 gap-8 md:gap-4 relative z-20"
|
||||
variants={statStagger}
|
||||
initial="hidden"
|
||||
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">
|
||||
{idx > 0 && (
|
||||
<div className="hidden md:block absolute left-0 top-1/2 -translate-y-1/2 w-[1px] h-10 bg-[#EEE7F4]" />
|
||||
)}
|
||||
<div className="w-10 h-10 rounded-full bg-[#6D28D9]/8 text-[#6D28D9] flex items-center justify-center shrink-0">
|
||||
<MaterialIcon icon={item.icon} size={18} />
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-2xl md:text-3xl font-black text-[#16001D] leading-none tracking-tight">
|
||||
{item.label}
|
||||
</div>
|
||||
<div className="text-xs text-[#6D6172] font-semibold mt-1">
|
||||
{item.text}
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
))}
|
||||
</motion.div>
|
||||
<div className="px-6 sm:px-10 max-w-[1600px] mx-auto py-6 md:py-8 lg:py-10">
|
||||
<motion.div
|
||||
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"
|
||||
variants={statStagger}
|
||||
initial="hidden"
|
||||
whileInView="visible"
|
||||
viewport={viewport}
|
||||
>
|
||||
<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">
|
||||
{PROOF_ITEMS.map((item, idx) => (
|
||||
<Fragment key={item.label}>
|
||||
<motion.div
|
||||
variants={statItem}
|
||||
className="flex items-center gap-[18px] group cursor-default transition-transform duration-[250ms] hover:-translate-y-1 lg:flex-1 lg:py-2"
|
||||
>
|
||||
<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]">
|
||||
<MaterialIcon icon={item.icon} size={28} />
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-2xl lg:text-[28px] font-black text-[#17051F] leading-none tracking-tight transition-colors duration-[250ms] group-hover:text-[#6D28D9]">
|
||||
{item.label}
|
||||
</div>
|
||||
<div className="text-sm lg:text-[15px] font-medium text-[#6B7280] mt-1.5">
|
||||
{item.text}
|
||||
</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>
|
||||
|
||||
</section>
|
||||
|
||||
@@ -18,7 +18,7 @@ const CATEGORIES = [
|
||||
cta: "Shop Fresh",
|
||||
},
|
||||
{
|
||||
name: "Medicines & Pharmacy",
|
||||
name: "Wellness",
|
||||
image: "/images/cat-health-wellness.png",
|
||||
tag: "Available Near You",
|
||||
tagStyle: "bg-primary text-white",
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import { Fragment } from "react";
|
||||
import { motion } from "framer-motion";
|
||||
import { MaterialIcon } from "./MaterialIcon";
|
||||
import { fadeUp, staggerContainer, viewport } from "@/lib/animations";
|
||||
@@ -17,57 +18,45 @@ type FeatureStatsRowProps = {
|
||||
|
||||
export function FeatureStatsRow({ items, className = "" }: FeatureStatsRowProps) {
|
||||
return (
|
||||
<motion.div
|
||||
className={`w-full py-5 md:py-8 ${className}`}
|
||||
variants={staggerContainer}
|
||||
initial="hidden"
|
||||
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) => (
|
||||
<motion.div
|
||||
key={item.title}
|
||||
variants={fadeUp}
|
||||
className={[
|
||||
// ── Mobile card (< 640 px) ──────────────────────────────────
|
||||
"flex flex-col gap-3",
|
||||
"bg-white",
|
||||
"border border-[#6330D6]/10",
|
||||
"rounded-2xl",
|
||||
"shadow-[0_2px_14px_rgba(99,48,214,0.07)]",
|
||||
"p-4",
|
||||
// ── Tablet strip (640 px – 1023 px) ────────────────────────
|
||||
"sm:flex-row sm:items-center sm:gap-3.5",
|
||||
"sm:bg-transparent",
|
||||
"sm:border-0",
|
||||
"sm:rounded-none",
|
||||
"sm:shadow-none",
|
||||
"sm:px-3 sm:py-2",
|
||||
// ── Desktop strip (1024 px +) ───────────────────────────────
|
||||
"lg:flex-1 lg:px-8 lg:py-0",
|
||||
"text-left",
|
||||
index < items.length - 1 ? "lg:border-r lg:border-[#6330D6]/10" : "",
|
||||
]
|
||||
.filter(Boolean)
|
||||
.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 className={`w-full py-6 md:py-8 lg:py-10 ${className}`}>
|
||||
<motion.div
|
||||
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"
|
||||
variants={staggerContainer}
|
||||
initial="hidden"
|
||||
whileInView="visible"
|
||||
viewport={viewport}
|
||||
>
|
||||
<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">
|
||||
{items.map((item, index) => (
|
||||
<Fragment key={item.title}>
|
||||
<motion.div
|
||||
variants={fadeUp}
|
||||
className="flex items-center gap-[18px] group cursor-default transition-transform duration-[250ms] hover:-translate-y-1 lg:flex-1 lg:py-2"
|
||||
>
|
||||
<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]">
|
||||
<MaterialIcon icon={item.icon} size={28} />
|
||||
</div>
|
||||
<div className="min-w-0">
|
||||
<h4 className="text-lg lg:text-xl xl:text-2xl font-black text-[#17051F] leading-tight transition-colors duration-[250ms] group-hover:text-[#6330D6]">
|
||||
{item.title}
|
||||
</h4>
|
||||
{item.desc && (
|
||||
<p className="text-sm lg:text-[15px] font-medium text-[#6B7280] mt-1 leading-snug">
|
||||
{item.desc}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</motion.div>
|
||||
{index < items.length - 1 && (
|
||||
<div
|
||||
className="hidden lg:block w-px h-[72px] bg-[#E9D8FD] shrink-0 self-center"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</motion.div>
|
||||
))}
|
||||
</div>
|
||||
</motion.div>
|
||||
</Fragment>
|
||||
))}
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||