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";
|
"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's first hyper-local managed “Neighbourhood living platform” which brings all the amenities and requirements of residents to their fingertips.
|
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.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>
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
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";
|
"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"
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -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>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||