all hero section add image

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

View File

@@ -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&apos;s first hyper-local managed &ldquo;Neighbourhood living platform&rdquo; which brings all the amenities and requirements of residents to their fingertips.
</motion.p>
<motion.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>

View File

@@ -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>

View File

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

View File

@@ -1,5 +1,6 @@
"use client";
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"

View File

@@ -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>

View File

@@ -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>

View File

@@ -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",

View File

@@ -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>
);
}