updated pages
This commit is contained in:
11
public/logo_icons/apple-round.svg
Normal file
11
public/logo_icons/apple-round.svg
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
|
||||||
|
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||||
|
<svg fill="#000000" height="800px" width="800px" version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
|
viewBox="0 0 512 512" xml:space="preserve">
|
||||||
|
<path d="M256,0C114.6,0,0,114.6,0,256s114.6,256,256,256s256-114.6,256-256S397.4,0,256,0z M265.1,142.1
|
||||||
|
c9.4-11.4,25.4-20.1,39.1-21.1c2.3,15.6-4.1,30.8-12.5,41.6c-9,11.6-24.5,20.5-39.5,20C249.6,167.7,256.6,152.4,265.1,142.1z
|
||||||
|
M349.4,339.9c-10.8,16.4-26,36.9-44.9,37.1c-16.8,0.2-21.1-10.9-43.8-10.8c-22.7,0.1-27.5,11-44.3,10.8
|
||||||
|
c-18.9-0.2-33.3-18.7-44.1-35.1c-30.2-46-33.4-99.9-14.7-128.6c13.2-20.4,34.1-32.3,53.8-32.3c20,0,32.5,11,49.1,11
|
||||||
|
c16,0,25.8-11,48.9-11c17.5,0,36,9.5,49.2,26c-43.2,23.7-36.2,85.4,7.5,101.9C360,322.1,357.1,328.1,349.4,339.9z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 881 B |
BIN
public/logo_icons/apple.jpg
Normal file
BIN
public/logo_icons/apple.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 19 KiB |
BIN
public/logo_icons/images.png
Normal file
BIN
public/logo_icons/images.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 11 KiB |
@@ -17,15 +17,6 @@ function Reveal({ children, delay = 0 }: { children: React.ReactNode; delay?: nu
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const VALUES = [
|
|
||||||
{ n: '01', title: 'Intelligence first', desc: 'Every product decision starts with data, not instinct.' },
|
|
||||||
{ n: '02', title: 'Merchant obsessed', desc: 'We build for the store owner who works 14-hour days.' },
|
|
||||||
{ n: '03', title: 'Radical transparency', desc: 'No black boxes. Our AI explains every recommendation.' },
|
|
||||||
{ n: '04', title: 'Build to last', desc: 'We optimise for long-term impact, not vanity metrics.' },
|
|
||||||
];
|
|
||||||
|
|
||||||
const TEAM: { name: string; role: string; initials: string; color: string }[] = [];
|
|
||||||
|
|
||||||
export default function AboutUsPage() {
|
export default function AboutUsPage() {
|
||||||
return (
|
return (
|
||||||
<main style={{ background: '#ffffff', minHeight: '100vh', overflowX: 'hidden' }}>
|
<main style={{ background: '#ffffff', minHeight: '100vh', overflowX: 'hidden' }}>
|
||||||
@@ -101,18 +92,18 @@ export default function AboutUsPage() {
|
|||||||
{[
|
{[
|
||||||
{
|
{
|
||||||
label: 'Mission', bg: '#07070d', textColor: '#fff', accent: '#f4be28',
|
label: 'Mission', bg: '#07070d', textColor: '#fff', accent: '#f4be28',
|
||||||
body: 'To transform physical retail with AI-driven intelligence and meaningful customer engagement.',
|
body: 'Loyaly exists to close the gap between digital discovery and physical purchase. We give local stores the tools to compete, and give shoppers a reason to keep coming back.',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Vision', bg: '#f4be28', textColor: '#111', accent: '#c9960f',
|
label: 'Vision', bg: '#f4be28', textColor: '#111', accent: '#c9960f',
|
||||||
body: 'To become the leading retail intelligence platform across global markets.',
|
body: 'Empowering every neighbourhood, making exceptional in-store experiences and real rewards accessible to all.',
|
||||||
},
|
},
|
||||||
].map((mv, i) => (
|
].map((mv, i) => (
|
||||||
<Reveal key={i} delay={i * 0.15}>
|
<Reveal key={i} delay={i * 0.15}>
|
||||||
<div style={{
|
<div style={{
|
||||||
padding: '72px 56px', borderRadius: 24, background: mv.bg,
|
padding: '72px 56px', borderRadius: 24, background: mv.bg,
|
||||||
height: '100%', minHeight: 360,
|
height: '100%', minHeight: 360,
|
||||||
display: 'flex', flexDirection: 'column', justifyContent: 'space-between',
|
display: 'flex', flexDirection: 'column', justifyContent: 'flex-start', gap: 28,
|
||||||
margin: '0 20px 20px', boxSizing: 'border-box',
|
margin: '0 20px 20px', boxSizing: 'border-box',
|
||||||
}}>
|
}}>
|
||||||
<div style={{ fontSize: 11, fontWeight: 700, letterSpacing: '0.2em', textTransform: 'uppercase', color: mv.accent, fontFamily: 'Sora, sans-serif' }}>{mv.label}</div>
|
<div style={{ fontSize: 11, fontWeight: 700, letterSpacing: '0.2em', textTransform: 'uppercase', color: mv.accent, fontFamily: 'Sora, sans-serif' }}>{mv.label}</div>
|
||||||
@@ -125,35 +116,39 @@ export default function AboutUsPage() {
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
{/* ── VALUES ── */}
|
{/* ── MARKET OPPORTUNITY ── */}
|
||||||
<section style={{ padding: '140px 8%', background: '#fff', margin: '0 20px 20px', borderRadius: 24 }}>
|
<section style={{ padding: '140px 8%', background: '#fff', margin: '0 20px 20px', borderRadius: 24 }}>
|
||||||
<Reveal>
|
<div className="au-market-grid" style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '8vw', alignItems: 'start' }}>
|
||||||
<div style={{ fontSize: 11, fontWeight: 700, letterSpacing: '0.2em', textTransform: 'uppercase', color: '#f4be28', fontFamily: 'Sora, sans-serif', marginBottom: 20 }}>How We Work</div>
|
<Reveal>
|
||||||
<h2 style={{ fontSize: 'clamp(36px, 5vw, 72px)', fontWeight: 800, letterSpacing: '-0.04em', lineHeight: 0.95, color: '#0a0a0f', margin: '0 0 80px', fontFamily: 'Sora, sans-serif' }}>
|
<div style={{ fontSize: 11, fontWeight: 700, letterSpacing: '0.2em', textTransform: 'uppercase', color: '#f4be28', fontFamily: 'Sora, sans-serif', marginBottom: 24 }}>Market Opportunity</div>
|
||||||
What we believe.
|
<h2 style={{ fontSize: 'clamp(36px, 4.5vw, 68px)', fontWeight: 800, letterSpacing: '-0.04em', lineHeight: 0.95, color: '#0a0a0f', margin: '0 0 32px', fontFamily: 'Sora, sans-serif' }}>
|
||||||
</h2>
|
13 Million Stores.<br />One Opportunity.
|
||||||
</Reveal>
|
</h2>
|
||||||
<div style={{ display: 'flex', flexDirection: 'column' }}>
|
<p style={{ fontSize: 'clamp(17px, 1.6vw, 22px)', lineHeight: 1.8, color: 'rgba(0,0,0,0.55)', fontFamily: 'Sora, sans-serif', margin: 0 }}>
|
||||||
{VALUES.map((v, i) => (
|
India's retail market is one of the largest and fastest-growing in the world. We're building Loyaly for the stores that power it, and the shoppers who love them.
|
||||||
<Reveal key={i} delay={i * 0.08}>
|
</p>
|
||||||
<div className="au-value-row" style={{
|
</Reveal>
|
||||||
display: 'grid', gridTemplateColumns: '80px 1fr 1fr',
|
<Reveal delay={0.15}>
|
||||||
gap: '4vw', alignItems: 'center',
|
<div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
|
||||||
padding: '40px 0', borderBottom: '1px solid rgba(0,0,0,0.07)',
|
{[
|
||||||
}}>
|
{ val: '13 Million+', label: 'Total Retail Stores Across India' },
|
||||||
<span style={{ fontSize: 13, fontWeight: 700, color: '#f4be28', fontFamily: 'Sora, sans-serif', letterSpacing: '0.06em' }}>{v.n}</span>
|
{ val: '2 Million+', label: 'Organised & High-Footfall Stores' },
|
||||||
<h3 style={{ fontSize: 'clamp(20px, 2.5vw, 36px)', fontWeight: 800, color: '#0a0a0f', fontFamily: 'Sora, sans-serif', margin: 0, letterSpacing: '-0.03em' }}>{v.title}</h3>
|
{ val: '50,000+', label: 'Stores In Our Launch Cities' },
|
||||||
<p style={{ fontSize: 16, color: 'rgba(0,0,0,0.45)', fontFamily: 'Sora, sans-serif', margin: 0, lineHeight: 1.65 }}>{v.desc}</p>
|
].map((m) => (
|
||||||
</div>
|
<div key={m.label} style={{ padding: '28px 32px', borderRadius: 20, background: '#faf9f6', border: '1px solid rgba(0,0,0,0.06)' }}>
|
||||||
</Reveal>
|
<div style={{ fontSize: 'clamp(26px, 3vw, 40px)', fontWeight: 900, color: '#0a0a0f', fontFamily: 'Sora, sans-serif', letterSpacing: '-0.03em' }}>{m.val}</div>
|
||||||
))}
|
<div style={{ fontSize: 14, color: 'rgba(0,0,0,0.45)', fontFamily: 'Sora, sans-serif', marginTop: 6 }}>{m.label}</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</Reveal>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
{/* ── TEAM ── */}
|
{/* ── TEAM ── */}
|
||||||
<TeamCarousel />
|
<TeamCarousel />
|
||||||
|
|
||||||
{/* ── CULTURE CLOSE ── */}
|
{/* ── CLOSE: POINT TO THE CREW ── */}
|
||||||
<section style={{
|
<section style={{
|
||||||
padding: '160px 8%', background: '#f4be28',
|
padding: '160px 8%', background: '#f4be28',
|
||||||
margin: '0 20px 20px', borderRadius: 24,
|
margin: '0 20px 20px', borderRadius: 24,
|
||||||
@@ -165,21 +160,29 @@ export default function AboutUsPage() {
|
|||||||
<p style={{ fontSize: 'clamp(32px, 6vw, 90px)', fontWeight: 900, letterSpacing: '-0.05em', lineHeight: 0.95, color: '#111', margin: '0 0 48px', fontFamily: 'Sora, sans-serif', position: 'relative', zIndex: 2 }}>
|
<p style={{ fontSize: 'clamp(32px, 6vw, 90px)', fontWeight: 900, letterSpacing: '-0.05em', lineHeight: 0.95, color: '#111', margin: '0 0 48px', fontFamily: 'Sora, sans-serif', position: 'relative', zIndex: 2 }}>
|
||||||
"We're not just building a product. We're redefining retail."
|
"We're not just building a product. We're redefining retail."
|
||||||
</p>
|
</p>
|
||||||
<Link href="/contacts" style={{
|
<div style={{ display: 'flex', gap: 14, flexWrap: 'wrap', justifyContent: 'center', position: 'relative', zIndex: 2 }}>
|
||||||
display: 'inline-flex', alignItems: 'center', gap: 10,
|
<Link href="/solutions_page" style={{
|
||||||
padding: '18px 44px', background: '#111', color: '#f4be28',
|
display: 'inline-flex', alignItems: 'center', gap: 10,
|
||||||
fontSize: 16, fontWeight: 800, borderRadius: 100, textDecoration: 'none',
|
padding: '18px 44px', background: '#111', color: '#f4be28',
|
||||||
fontFamily: 'Sora, sans-serif', position: 'relative', zIndex: 2,
|
fontSize: 16, fontWeight: 800, borderRadius: 100, textDecoration: 'none',
|
||||||
}}>Join Us →</Link>
|
fontFamily: 'Sora, sans-serif',
|
||||||
|
}}>See Our Products →</Link>
|
||||||
|
<Link href="/contacts" style={{
|
||||||
|
display: 'inline-flex', alignItems: 'center', gap: 10,
|
||||||
|
padding: '18px 44px', background: 'rgba(0,0,0,0.08)', color: '#111',
|
||||||
|
fontSize: 16, fontWeight: 700, borderRadius: 100, textDecoration: 'none',
|
||||||
|
fontFamily: 'Sora, sans-serif', border: '1px solid rgba(0,0,0,0.15)',
|
||||||
|
}}>Join Us</Link>
|
||||||
|
</div>
|
||||||
</Reveal>
|
</Reveal>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<style>{`
|
<style>{`
|
||||||
@media (max-width: 860px) {
|
@media (max-width: 860px) {
|
||||||
.au-story-grid { grid-template-columns: 1fr !important; gap: 36px !important; }
|
.au-story-grid { grid-template-columns: 1fr !important; gap: 36px !important; }
|
||||||
|
.au-market-grid { grid-template-columns: 1fr !important; gap: 36px !important; }
|
||||||
.au-mv-grid { grid-template-columns: 1fr !important; }
|
.au-mv-grid { grid-template-columns: 1fr !important; }
|
||||||
.au-mv-grid > div > div { padding: 48px 32px !important; min-height: 280px !important; }
|
.au-mv-grid > div > div { padding: 48px 32px !important; min-height: 280px !important; }
|
||||||
.au-value-row { grid-template-columns: 1fr !important; gap: 10px !important; padding: 28px 0 !important; }
|
|
||||||
}
|
}
|
||||||
`}</style>
|
`}</style>
|
||||||
</main>
|
</main>
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import VerticalScrollWrapper from '@/components/for-people/VerticalScrollWrapper';
|
import VerticalScrollWrapper from '@/components/for-people/VerticalScrollWrapper';
|
||||||
import HeroSection from '@/components/for-people/HeroSection';
|
import HeroSection from '@/components/for-people/HeroSection';
|
||||||
|
import PillarsSection from '@/components/for-people/PillarsSection';
|
||||||
import WhyLoyalySection from '@/components/for-people/WhyLoyalySection';
|
import WhyLoyalySection from '@/components/for-people/WhyLoyalySection';
|
||||||
import DiscoverDealsSection from '@/components/for-people/DiscoverDealsSection';
|
import DiscoverDealsSection from '@/components/for-people/DiscoverDealsSection';
|
||||||
import EarnRewardsSection from '@/components/for-people/EarnRewardsSection';
|
import EarnRewardsSection from '@/components/for-people/EarnRewardsSection';
|
||||||
@@ -14,6 +15,7 @@ import FinalCTASection from '@/components/for-people/FinalCTASection';
|
|||||||
const SECTIONS = [
|
const SECTIONS = [
|
||||||
'Intro',
|
'Intro',
|
||||||
'The Gap',
|
'The Gap',
|
||||||
|
'Save More',
|
||||||
'Discover',
|
'Discover',
|
||||||
'Earn',
|
'Earn',
|
||||||
'Spend',
|
'Spend',
|
||||||
@@ -28,6 +30,7 @@ export default function ForPeoplePage() {
|
|||||||
<VerticalScrollWrapper sections={SECTIONS}>
|
<VerticalScrollWrapper sections={SECTIONS}>
|
||||||
<HeroSection />
|
<HeroSection />
|
||||||
<WhyLoyalySection />
|
<WhyLoyalySection />
|
||||||
|
<PillarsSection />
|
||||||
<DiscoverDealsSection />
|
<DiscoverDealsSection />
|
||||||
<EarnRewardsSection />
|
<EarnRewardsSection />
|
||||||
<SpendAnywhereSection />
|
<SpendAnywhereSection />
|
||||||
|
|||||||
@@ -319,6 +319,9 @@ export default function IndexPage() {
|
|||||||
Walk In Into a <br />
|
Walk In Into a <br />
|
||||||
<span className="hero-gradient-text">Loyal Customer</span>
|
<span className="hero-gradient-text">Loyal Customer</span>
|
||||||
</h1>
|
</h1>
|
||||||
|
<p className="text-[#f4be28] hero-tagline text-sm sm:text-base font-bold tracking-tight mb-3 select-none">
|
||||||
|
Offline is the new Online.
|
||||||
|
</p>
|
||||||
<p className="text-[#4f463a] hero-description text-sm sm:text-base mb-8 leading-relaxed select-none">
|
<p className="text-[#4f463a] hero-description text-sm sm:text-base mb-8 leading-relaxed select-none">
|
||||||
Loyaly.ai turns everyday digital engagement into real world shopping rewards. Customers earn LYTs through games and daily activities, then redeem them at offline stores near them.
|
Loyaly.ai turns everyday digital engagement into real world shopping rewards. Customers earn LYTs through games and daily activities, then redeem them at offline stores near them.
|
||||||
</p>
|
</p>
|
||||||
@@ -444,6 +447,9 @@ export default function IndexPage() {
|
|||||||
Walk In Into a <br />
|
Walk In Into a <br />
|
||||||
<span className="hero-gradient-text">Loyal Customer</span>
|
<span className="hero-gradient-text">Loyal Customer</span>
|
||||||
</h1>
|
</h1>
|
||||||
|
<p className="text-[#f4be28] hero-tagline text-sm sm:text-base md:text-lg font-bold tracking-tight mb-4 select-none">
|
||||||
|
Offline is the new Online.
|
||||||
|
</p>
|
||||||
<p className="text-[#4f463a] hero-description text-sm sm:text-base md:text-lg xl:text-xl mb-8 leading-relaxed max-w-2xl select-none">
|
<p className="text-[#4f463a] hero-description text-sm sm:text-base md:text-lg xl:text-xl mb-8 leading-relaxed max-w-2xl select-none">
|
||||||
Loyaly.ai turns everyday digital engagement into real world shopping rewards. Customers earn LYTs through games and daily activities, then redeem them at offline stores near them.
|
Loyaly.ai turns everyday digital engagement into real world shopping rewards. Customers earn LYTs through games and daily activities, then redeem them at offline stores near them.
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
@@ -1,23 +1,30 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import React, { useState } from 'react';
|
import React from 'react';
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import Image from 'next/image';
|
import Image from 'next/image';
|
||||||
import GSAPAnimator from '@/components/GSAPAnimator';
|
|
||||||
import { useReveal } from '@/hooks/useReveal';
|
import { useReveal } from '@/hooks/useReveal';
|
||||||
|
import GSAPAnimator from '@/components/GSAPAnimator';
|
||||||
import ScrollStack, { ScrollStackItem } from '@/components/ScrollStack';
|
import ScrollStack, { ScrollStackItem } from '@/components/ScrollStack';
|
||||||
|
|
||||||
function RevealBlock({ children, delay = 0 }: { children: React.ReactNode; delay?: number }) {
|
function Reveal({ children, delay = 0 }: { children: React.ReactNode; delay?: number }) {
|
||||||
const { ref, visible } = useReveal();
|
const { ref, visible } = useReveal();
|
||||||
return (
|
return (
|
||||||
<div ref={ref} style={{
|
<div ref={ref} style={{
|
||||||
opacity: visible ? 1 : 0,
|
opacity: visible ? 1 : 0,
|
||||||
transform: visible ? 'translateY(0)' : 'translateY(52px)',
|
transform: visible ? 'translateY(0)' : 'translateY(48px)',
|
||||||
transition: `opacity 0.9s cubic-bezier(0.22,1,0.36,1) ${delay}s, transform 0.9s cubic-bezier(0.22,1,0.36,1) ${delay}s`,
|
transition: `opacity 0.9s cubic-bezier(0.22,1,0.36,1) ${delay}s, transform 0.9s cubic-bezier(0.22,1,0.36,1) ${delay}s`,
|
||||||
}}>{children}</div>
|
}}>{children}</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const VALUES = [
|
||||||
|
{ n: '01', title: 'Intelligence first', desc: 'Every product decision starts with data, not instinct.' },
|
||||||
|
{ n: '02', title: 'Merchant obsessed', desc: 'We build for the store owner who works 14-hour days.' },
|
||||||
|
{ n: '03', title: 'Radical transparency', desc: 'No black boxes. Our AI explains every recommendation.' },
|
||||||
|
{ n: '04', title: 'Build to last', desc: 'We optimise for long-term impact, not vanity metrics.' },
|
||||||
|
];
|
||||||
|
|
||||||
const PRODUCTS = [
|
const PRODUCTS = [
|
||||||
{
|
{
|
||||||
n: '01', title: 'Behavision', subtitle: 'AI Powered Footfall Analytics', color: '#f4be28',
|
n: '01', title: 'Behavision', subtitle: 'AI Powered Footfall Analytics', color: '#f4be28',
|
||||||
@@ -65,124 +72,76 @@ const PRODUCTS = [
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const CAPS = [
|
export default function MeetTheCrewPage() {
|
||||||
{
|
|
||||||
n: '01', title: 'Merchant Campaign Platform', color: '#f4be28',
|
|
||||||
desc: 'Register your store, upload products and inventory, then launch interactive promotional campaigns in minutes. Define maximum discounts per product and track performance in real time.',
|
|
||||||
metrics: [{ val: '5+', lbl: 'Game formats' }, { val: '1-click', lbl: 'Campaign setup' }],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
n: '02', title: 'Game Based Discount Engine', color: '#a78bfa',
|
|
||||||
desc: 'Select a product, choose a game (Maze, Spin Wheel, Scratch Card, or Match Master) and set a maximum discount. Customers play once and discover their reward only after completing the game.',
|
|
||||||
metrics: [{ val: '4×', lbl: 'Engagement lift' }, { val: '100%', lbl: 'Margin controlled' }],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
n: '03', title: 'Smart Coupon System', color: '#34d399',
|
|
||||||
desc: 'Generate daily surprise coupons through the Battery Challenge and other activities. Offer flat discounts, BOGO, percentage-off deals, festival specials, and brand promotions, fresh every day.',
|
|
||||||
metrics: [{ val: '6', lbl: 'Coupon types' }, { val: 'Daily', lbl: 'Fresh surprises' }],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
n: '04', title: 'Footfall & Campaign Analytics', color: '#f97316',
|
|
||||||
desc: 'Track which campaigns drove store visits, measure conversion rates, monitor repeat footfall, and optimize your promotional budget with a real-time analytics dashboard.',
|
|
||||||
metrics: [{ val: '98%', lbl: 'Count accuracy' }, { val: '<9ms', lbl: 'Real-time latency' }],
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
export default function SolutionsPage() {
|
|
||||||
const [hovered, setHovered] = useState<number | null>(null);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<main style={{ background: '#ffffff', minHeight: '100vh', overflowX: 'hidden' }}>
|
<main style={{ background: '#ffffff', minHeight: '100vh', overflowX: 'hidden' }}>
|
||||||
<GSAPAnimator />
|
<GSAPAnimator />
|
||||||
|
|
||||||
{/* ── HERO ── */}
|
{/* ── HERO ── */}
|
||||||
<section style={{
|
<section style={{
|
||||||
minHeight: '92vh', background: 'radial-gradient(ellipse 120% 90% at 70% 0%, #2c2350 0%, #211c3e 38%, #181429 100%)',
|
minHeight: '100vh', background: 'radial-gradient(ellipse 120% 90% at 22% 0%, #3a2b5e 0%, #251c40 38%, #1a1530 100%)',
|
||||||
display: 'flex', alignItems: 'center',
|
display: 'flex', alignItems: 'center',
|
||||||
padding: '120px 8% 100px',
|
padding: '120px 8% 80px',
|
||||||
margin: '20px', borderRadius: '32px',
|
margin: '20px', borderRadius: '32px',
|
||||||
position: 'relative', overflow: 'hidden',
|
position: 'relative', overflow: 'hidden',
|
||||||
}}>
|
}}>
|
||||||
{/* Background photo */}
|
{/* Background photo */}
|
||||||
<Image src="/images/stock/solutions.jpg" alt="" fill priority style={{ objectFit: 'cover', opacity: 0.9 }} />
|
<Image src="/images/stock/about-team.jpg" alt="" fill priority style={{ objectFit: 'cover', opacity: 0.9 }} />
|
||||||
<div style={{ position: 'absolute', inset: 0, background: 'linear-gradient(180deg, rgba(24,20,41,0.1) 0%, rgba(24,20,41,0.55) 85%)' }} />
|
<div style={{ position: 'absolute', inset: 0, background: 'linear-gradient(180deg, rgba(26,21,48,0.1) 0%, rgba(26,21,48,0.55) 85%)' }} />
|
||||||
<div style={{ position: 'absolute', inset: 0, background: 'radial-gradient(ellipse 60% 65% at 50% 48%, rgba(18,14,30,0.78) 0%, rgba(18,14,30,0.35) 60%, transparent 100%)' }} />
|
<div style={{ position: 'absolute', inset: 0, background: 'radial-gradient(ellipse 60% 65% at 50% 48%, rgba(18,14,30,0.78) 0%, rgba(18,14,30,0.35) 60%, transparent 100%)' }} />
|
||||||
{/* Accent blobs */}
|
{/* Accent blobs */}
|
||||||
<div style={{ position: 'absolute', top: '-12%', left: '4%', width: 480, height: 480, borderRadius: '50%', background: 'radial-gradient(circle, rgba(244,190,40,0.2) 0%, transparent 70%)', pointerEvents: 'none' }} />
|
<div style={{ position: 'absolute', top: '-12%', right: '-8%', width: 520, height: 520, borderRadius: '50%', background: 'radial-gradient(circle, rgba(244,190,40,0.22) 0%, transparent 70%)', filter: 'blur(10px)', pointerEvents: 'none' }} />
|
||||||
<div style={{ position: 'absolute', bottom: '-14%', right: '0%', width: 440, height: 440, borderRadius: '50%', background: 'radial-gradient(circle, rgba(167,139,250,0.18) 0%, transparent 70%)', pointerEvents: 'none' }} />
|
<div style={{ position: 'absolute', bottom: '-15%', left: '-10%', width: 460, height: 460, borderRadius: '50%', background: 'radial-gradient(circle, rgba(167,139,250,0.18) 0%, transparent 70%)', pointerEvents: 'none' }} />
|
||||||
{/* Animated rings */}
|
{/* Big ghost text */}
|
||||||
{[600, 900, 1200].map((s, i) => (
|
<div style={{
|
||||||
<div key={i} style={{
|
position: 'absolute', top: '50%', left: '50%',
|
||||||
position: 'absolute', top: '50%', right: '-10%',
|
transform: 'translate(-50%,-50%)',
|
||||||
width: s, height: s, borderRadius: '50%',
|
fontSize: 'clamp(120px, 22vw, 320px)', fontWeight: 900,
|
||||||
border: '1px solid rgba(244,190,40,0.07)',
|
fontFamily: 'Sora, sans-serif', color: 'transparent',
|
||||||
transform: 'translateY(-50%)',
|
WebkitTextStroke: '1px rgba(244,190,40,0.08)',
|
||||||
pointerEvents: 'none',
|
letterSpacing: '-0.06em', lineHeight: 1,
|
||||||
}} />
|
whiteSpace: 'nowrap', userSelect: 'none',
|
||||||
))}
|
pointerEvents: 'none', zIndex: 0,
|
||||||
|
}}>LOYALY</div>
|
||||||
|
|
||||||
<div style={{ width: '100%', position: 'relative', zIndex: 2, display: 'flex', flexDirection: 'column', alignItems: 'center', textAlign: 'center' }}>
|
<div style={{ position: 'relative', zIndex: 2, width: '100%', display: 'flex', flexDirection: 'column', alignItems: 'center', textAlign: 'center' }}>
|
||||||
<div style={{ maxWidth: 760 }}>
|
<div style={{ maxWidth: 760 }}>
|
||||||
<h1 data-gsap="heading" style={{ fontSize: 'clamp(52px, 8.5vw, 130px)', fontWeight: 800, letterSpacing: '-0.05em', lineHeight: 0.88, color: '#fff', margin: '0 0 36px', fontFamily: 'Sora, sans-serif' }}>
|
<h1 data-gsap="heading" style={{
|
||||||
Built for<br />Modern<br />
|
fontSize: 'clamp(52px, 9vw, 140px)', fontWeight: 800,
|
||||||
<span style={{ color: '#f4be28' }}>Retail Growth.</span>
|
letterSpacing: '-0.06em', lineHeight: 0.88,
|
||||||
|
color: '#ffffff', margin: '0 0 36px', fontFamily: 'Sora, sans-serif',
|
||||||
|
}}>
|
||||||
|
Meet the<br />
|
||||||
|
<span style={{ color: '#f4be28' }}>Crew.</span>
|
||||||
</h1>
|
</h1>
|
||||||
<p data-gsap="text" style={{ fontSize: 'clamp(16px, 1.6vw, 20px)', lineHeight: 1.75, color: 'rgba(255,255,255,0.55)', fontFamily: 'Sora, sans-serif', maxWidth: 540, margin: '0 auto 52px' }}>
|
<p data-gsap="text" style={{ fontSize: 'clamp(16px, 1.5vw, 20px)', lineHeight: 1.75, color: 'rgba(255,255,255,0.55)', fontFamily: 'Sora, sans-serif', maxWidth: 560, margin: '0 auto' }}>
|
||||||
Instead of waiting for customers to walk in, create exciting reasons for them to come, with game based campaigns, smart coupons, and a loyalty ecosystem that rewards every visit.
|
The builders, thinkers, and retail obsessives behind Loyaly, working every day to make offline shopping as smart as online.
|
||||||
</p>
|
</p>
|
||||||
<div style={{ display: 'flex', gap: 14, flexWrap: 'wrap', justifyContent: 'center' }}>
|
|
||||||
<Link href="/contacts" style={{ padding: '18px 40px', background: '#f4be28', color: '#111', fontSize: 16, fontWeight: 800, borderRadius: 100, textDecoration: 'none', fontFamily: 'Sora, sans-serif', boxShadow: '0 16px 48px rgba(244,190,40,0.25)' }}>Explore Solutions →</Link>
|
|
||||||
<Link href="/contacts" style={{ padding: '18px 40px', background: 'rgba(255,255,255,0.06)', color: '#fff', fontSize: 16, fontWeight: 700, borderRadius: 100, textDecoration: 'none', fontFamily: 'Sora, sans-serif', border: '1px solid rgba(255,255,255,0.12)', backdropFilter: 'blur(12px)' }}>Book Demo</Link>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
{/* ── CAPABILITIES ── */}
|
{/* ── VALUES ── */}
|
||||||
<section style={{ padding: '140px 8%', background: '#fff', margin: '0 20px 20px', borderRadius: 24 }}>
|
<section style={{ padding: '140px 8%', background: '#fff', margin: '0 20px 20px', borderRadius: 24 }}>
|
||||||
<RevealBlock>
|
<Reveal>
|
||||||
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-end', marginBottom: 80, flexWrap: 'wrap', gap: 24 }}>
|
<div style={{ fontSize: 11, fontWeight: 700, letterSpacing: '0.2em', textTransform: 'uppercase', color: '#f4be28', fontFamily: 'Sora, sans-serif', marginBottom: 20 }}>How We Work</div>
|
||||||
<div>
|
<h2 style={{ fontSize: 'clamp(36px, 5vw, 72px)', fontWeight: 800, letterSpacing: '-0.04em', lineHeight: 0.95, color: '#0a0a0f', margin: '0 0 80px', fontFamily: 'Sora, sans-serif' }}>
|
||||||
<div style={{ fontSize: 11, fontWeight: 700, letterSpacing: '0.2em', textTransform: 'uppercase', color: '#f4be28', fontFamily: 'Sora, sans-serif', marginBottom: 16 }}>Capabilities</div>
|
What we believe.
|
||||||
<h2 style={{ fontSize: 'clamp(36px, 5vw, 72px)', fontWeight: 800, letterSpacing: '-0.04em', lineHeight: 0.95, color: '#0a0a0f', margin: 0, fontFamily: 'Sora, sans-serif' }}>
|
</h2>
|
||||||
Four tools.<br />One merchant platform.
|
</Reveal>
|
||||||
</h2>
|
<div style={{ display: 'flex', flexDirection: 'column' }}>
|
||||||
</div>
|
{VALUES.map((v, i) => (
|
||||||
<p style={{ fontSize: 16, color: 'rgba(0,0,0,0.45)', fontFamily: 'Sora, sans-serif', maxWidth: 360, lineHeight: 1.7 }}>
|
<Reveal key={i} delay={i * 0.08}>
|
||||||
Every tool works independently and amplifies the others, giving merchants a complete system to attract, engage, and retain customers.
|
<div className="mtc-value-row" style={{
|
||||||
</p>
|
display: 'grid', gridTemplateColumns: '80px 1fr 1fr',
|
||||||
</div>
|
gap: '4vw', alignItems: 'center',
|
||||||
</RevealBlock>
|
padding: '40px 0', borderBottom: '1px solid rgba(0,0,0,0.07)',
|
||||||
|
}}>
|
||||||
<div style={{ display: 'flex', flexDirection: 'column', gap: 2 }}>
|
<span style={{ fontSize: 13, fontWeight: 700, color: '#f4be28', fontFamily: 'Sora, sans-serif', letterSpacing: '0.06em' }}>{v.n}</span>
|
||||||
{CAPS.map((cap, i) => (
|
<h3 style={{ fontSize: 'clamp(20px, 2.5vw, 36px)', fontWeight: 800, color: '#0a0a0f', fontFamily: 'Sora, sans-serif', margin: 0, letterSpacing: '-0.03em' }}>{v.title}</h3>
|
||||||
<RevealBlock key={i} delay={i * 0.08}>
|
<p style={{ fontSize: 16, color: 'rgba(0,0,0,0.45)', fontFamily: 'Sora, sans-serif', margin: 0, lineHeight: 1.65 }}>{v.desc}</p>
|
||||||
<div
|
|
||||||
onMouseEnter={() => setHovered(i)}
|
|
||||||
onMouseLeave={() => setHovered(null)}
|
|
||||||
className="sp-cap-row"
|
|
||||||
style={{
|
|
||||||
display: 'grid', gridTemplateColumns: '80px 1fr 1fr auto',
|
|
||||||
alignItems: 'center', gap: '4vw',
|
|
||||||
padding: '40px 0',
|
|
||||||
borderBottom: '1px solid rgba(0,0,0,0.07)',
|
|
||||||
cursor: 'default',
|
|
||||||
transition: 'all 0.3s ease',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<span style={{ fontSize: 13, fontWeight: 700, color: hovered === i ? cap.color : 'rgba(0,0,0,0.2)', fontFamily: 'Sora, sans-serif', letterSpacing: '0.06em', transition: 'color 0.3s' }}>{cap.n}</span>
|
|
||||||
<h3 style={{ fontSize: 'clamp(22px, 2.8vw, 40px)', fontWeight: 800, color: hovered === i ? '#0a0a0f' : 'rgba(0,0,0,0.8)', fontFamily: 'Sora, sans-serif', letterSpacing: '-0.03em', margin: 0, transition: 'color 0.3s' }}>{cap.title}</h3>
|
|
||||||
<p style={{ fontSize: 15, color: 'rgba(0,0,0,0.45)', fontFamily: 'Sora, sans-serif', margin: 0, lineHeight: 1.6, maxWidth: 340 }}>{cap.desc}</p>
|
|
||||||
<div style={{ display: 'flex', gap: 28 }}>
|
|
||||||
{cap.metrics.map((m, j) => (
|
|
||||||
<div key={j} style={{ textAlign: 'right' }}>
|
|
||||||
<div style={{ fontSize: 22, fontWeight: 900, color: cap.color, fontFamily: 'Sora, sans-serif', letterSpacing: '-0.03em' }}>{m.val}</div>
|
|
||||||
<div style={{ fontSize: 11, color: 'rgba(0,0,0,0.35)', fontFamily: 'Sora, sans-serif', marginTop: 3 }}>{m.lbl}</div>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</RevealBlock>
|
</Reveal>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
@@ -190,15 +149,15 @@ export default function SolutionsPage() {
|
|||||||
{/* ── OUR PRODUCTS ── */}
|
{/* ── OUR PRODUCTS ── */}
|
||||||
<section style={{ padding: '140px 8%', background: '#07070d', margin: '0 20px 20px', borderRadius: 24, overflow: 'hidden', position: 'relative' }}>
|
<section style={{ padding: '140px 8%', background: '#07070d', margin: '0 20px 20px', borderRadius: 24, overflow: 'hidden', position: 'relative' }}>
|
||||||
<div style={{ position: 'absolute', inset: 0, backgroundImage: 'linear-gradient(rgba(244,190,40,0.025) 1px,transparent 1px),linear-gradient(90deg,rgba(244,190,40,0.025) 1px,transparent 1px)', backgroundSize: '64px 64px', pointerEvents: 'none' }} />
|
<div style={{ position: 'absolute', inset: 0, backgroundImage: 'linear-gradient(rgba(244,190,40,0.025) 1px,transparent 1px),linear-gradient(90deg,rgba(244,190,40,0.025) 1px,transparent 1px)', backgroundSize: '64px 64px', pointerEvents: 'none' }} />
|
||||||
<RevealBlock>
|
<Reveal>
|
||||||
<div style={{ fontSize: 11, fontWeight: 700, letterSpacing: '0.2em', textTransform: 'uppercase', color: '#f4be28', fontFamily: 'Sora, sans-serif', marginBottom: 20, position: 'relative' }}>Our Products</div>
|
<div style={{ fontSize: 11, fontWeight: 700, letterSpacing: '0.2em', textTransform: 'uppercase', color: '#f4be28', fontFamily: 'Sora, sans-serif', marginBottom: 20, position: 'relative' }}>Meet the Products</div>
|
||||||
<h2 style={{ fontSize: 'clamp(36px, 5vw, 72px)', fontWeight: 800, letterSpacing: '-0.04em', lineHeight: 0.95, color: '#fff', margin: '0 0 20px', fontFamily: 'Sora, sans-serif', position: 'relative', maxWidth: 700 }}>
|
<h2 style={{ fontSize: 'clamp(36px, 5vw, 72px)', fontWeight: 800, letterSpacing: '-0.04em', lineHeight: 0.95, color: '#fff', margin: '0 0 20px', fontFamily: 'Sora, sans-serif', position: 'relative', maxWidth: 700 }}>
|
||||||
Four products.<br />One ecosystem.
|
Four products.<br />One ecosystem.
|
||||||
</h2>
|
</h2>
|
||||||
<p style={{ fontSize: 16, color: 'rgba(255,255,255,0.45)', fontFamily: 'Sora, sans-serif', maxWidth: 460, lineHeight: 1.7, marginBottom: 80, position: 'relative' }}>
|
<p style={{ fontSize: 16, color: 'rgba(255,255,255,0.45)', fontFamily: 'Sora, sans-serif', maxWidth: 460, lineHeight: 1.7, marginBottom: 80, position: 'relative' }}>
|
||||||
Each product solves a distinct part of the retail journey, and together they form one connected platform, from footfall to spend to loyalty.
|
Behavision, SpendSense, Dyscount, and Identiq, each solves a distinct part of the retail journey, and together they form one connected platform, from footfall to spend to loyalty.
|
||||||
</p>
|
</p>
|
||||||
</RevealBlock>
|
</Reveal>
|
||||||
|
|
||||||
<div style={{ position: 'relative' }}>
|
<div style={{ position: 'relative' }}>
|
||||||
<ScrollStack useWindowScroll itemDistance={160} itemScale={0.035} itemStackDistance={40} baseScale={0.86} blurAmount={1.2}>
|
<ScrollStack useWindowScroll itemDistance={160} itemScale={0.035} itemStackDistance={40} baseScale={0.86} blurAmount={1.2}>
|
||||||
@@ -209,7 +168,7 @@ export default function SolutionsPage() {
|
|||||||
border: `1px solid ${p.color}40`,
|
border: `1px solid ${p.color}40`,
|
||||||
borderRadius: 28, padding: 'clamp(28px, 3.2vw, 48px)', height: '100%', boxSizing: 'border-box',
|
borderRadius: 28, padding: 'clamp(28px, 3.2vw, 48px)', height: '100%', boxSizing: 'border-box',
|
||||||
}}>
|
}}>
|
||||||
<div className="sp-product-grid" style={{ display: 'grid', gridTemplateColumns: '1.35fr 1fr', gap: 'clamp(28px, 4vw, 56px)', alignItems: 'start' }}>
|
<div className="mtc-product-grid" style={{ display: 'grid', gridTemplateColumns: '1.35fr 1fr', gap: 'clamp(28px, 4vw, 56px)', alignItems: 'start' }}>
|
||||||
|
|
||||||
{/* Left — identity + description */}
|
{/* Left — identity + description */}
|
||||||
<div>
|
<div>
|
||||||
@@ -264,63 +223,31 @@ export default function SolutionsPage() {
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
{/* ── WHY IT MATTERS ── */}
|
{/* ── CULTURE CLOSE ── */}
|
||||||
<section style={{ padding: '140px 8%', background: '#07070d', margin: '0 20px 20px', borderRadius: 24, overflow: 'hidden', position: 'relative' }}>
|
<section style={{
|
||||||
<div style={{ position: 'absolute', inset: 0, backgroundImage: 'linear-gradient(rgba(244,190,40,0.025) 1px,transparent 1px),linear-gradient(90deg,rgba(244,190,40,0.025) 1px,transparent 1px)', backgroundSize: '64px 64px', pointerEvents: 'none' }} />
|
padding: '160px 8%', background: '#f4be28',
|
||||||
<RevealBlock>
|
margin: '0 20px 20px', borderRadius: 24,
|
||||||
<blockquote style={{
|
display: 'flex', flexDirection: 'column', alignItems: 'center', textAlign: 'center',
|
||||||
margin: 0, padding: 0,
|
position: 'relative', overflow: 'hidden',
|
||||||
fontSize: 'clamp(32px, 5vw, 72px)', fontWeight: 900,
|
}}>
|
||||||
letterSpacing: '-0.04em', lineHeight: 1.05,
|
<div style={{ position: 'absolute', inset: 0, background: 'radial-gradient(ellipse at 50% 0%,rgba(255,255,255,0.2) 0%,transparent 60%)', pointerEvents: 'none' }} />
|
||||||
color: '#fff', fontFamily: 'Sora, sans-serif',
|
<Reveal>
|
||||||
maxWidth: 900,
|
<p style={{ fontSize: 'clamp(32px, 6vw, 90px)', fontWeight: 900, letterSpacing: '-0.05em', lineHeight: 0.95, color: '#111', margin: '0 0 48px', fontFamily: 'Sora, sans-serif', position: 'relative', zIndex: 2 }}>
|
||||||
}}>
|
"We're not just building a product. We're redefining retail."
|
||||||
"Every digital interaction should lead to a{' '}
|
|
||||||
<span style={{ color: '#f4be28' }}>meaningful in-store experience.</span>"
|
|
||||||
</blockquote>
|
|
||||||
<div style={{ height: 2, width: 80, background: '#f4be28', margin: '48px 0 32px' }} />
|
|
||||||
<p style={{ fontSize: 16, color: 'rgba(255,255,255,0.4)', fontFamily: 'Sora, sans-serif', margin: 0 }}>Loyaly.ai, 2025</p>
|
|
||||||
</RevealBlock>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
{/* ── FINAL CTA ── */}
|
|
||||||
<section className="sp-cta-grid" style={{ padding: '140px 8%', background: '#fff8e8', margin: '0 20px 20px', borderRadius: 24, display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '6vw', alignItems: 'center' }}>
|
|
||||||
<RevealBlock>
|
|
||||||
<h2 style={{ fontSize: 'clamp(36px, 5vw, 68px)', fontWeight: 800, letterSpacing: '-0.04em', lineHeight: 0.95, color: '#0a0a0f', margin: '0 0 24px', fontFamily: 'Sora, sans-serif' }}>
|
|
||||||
See every solution working together.
|
|
||||||
</h2>
|
|
||||||
<p style={{ fontSize: 16, color: 'rgba(0,0,0,0.5)', fontFamily: 'Sora, sans-serif', margin: '0 0 40px', lineHeight: 1.7 }}>
|
|
||||||
Get a tailored walkthrough of how Loyaly.ai's merchant platform, game campaigns, and coupon engine fit your specific retail format.
|
|
||||||
</p>
|
</p>
|
||||||
<div style={{ display: 'flex', gap: 14, flexWrap: 'wrap' }}>
|
<Link href="/contacts" style={{
|
||||||
<Link href="/contacts" style={{ padding: '18px 40px', background: '#f4be28', color: '#111', fontSize: 16, fontWeight: 800, borderRadius: 100, textDecoration: 'none', fontFamily: 'Sora, sans-serif', boxShadow: '0 12px 40px rgba(244,190,40,0.3)' }}>Book Demo →</Link>
|
display: 'inline-flex', alignItems: 'center', gap: 10,
|
||||||
<Link href="/contacts" style={{ padding: '18px 40px', background: 'transparent', color: '#111', fontSize: 16, fontWeight: 700, borderRadius: 100, textDecoration: 'none', fontFamily: 'Sora, sans-serif', border: '1.5px solid rgba(0,0,0,0.15)' }}>Explore Solutions</Link>
|
padding: '18px 44px', background: '#111', color: '#f4be28',
|
||||||
</div>
|
fontSize: 16, fontWeight: 800, borderRadius: 100, textDecoration: 'none',
|
||||||
</RevealBlock>
|
fontFamily: 'Sora, sans-serif', position: 'relative', zIndex: 2,
|
||||||
<RevealBlock delay={0.15}>
|
}}>Join Us →</Link>
|
||||||
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12 }}>
|
</Reveal>
|
||||||
{[
|
|
||||||
{ v: '10K+', l: 'Partner stores' }, { v: '50K+', l: 'Active users' },
|
|
||||||
{ v: '98%', l: 'Uptime SLA' }, { v: '<9ms', l: 'Response time' },
|
|
||||||
].map((s, i) => (
|
|
||||||
<div key={i} style={{ padding: '32px 28px', background: '#fff', borderRadius: 20, boxShadow: '0 4px 32px rgba(0,0,0,0.06)', border: '1px solid rgba(0,0,0,0.05)' }}>
|
|
||||||
<div style={{ fontSize: 'clamp(28px, 3.5vw, 44px)', fontWeight: 900, color: '#0a0a0f', fontFamily: 'Sora, sans-serif', letterSpacing: '-0.04em' }}>{s.v}</div>
|
|
||||||
<div style={{ fontSize: 13, color: 'rgba(0,0,0,0.4)', fontFamily: 'Sora, sans-serif', marginTop: 8 }}>{s.l}</div>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</RevealBlock>
|
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<style>{`
|
<style>{`
|
||||||
@media (max-width: 860px) {
|
@media (max-width: 860px) {
|
||||||
.sp-cap-row { grid-template-columns: 1fr !important; gap: 14px !important; padding: 28px 0 !important; }
|
.mtc-value-row { grid-template-columns: 1fr !important; gap: 10px !important; padding: 28px 0 !important; }
|
||||||
.sp-cap-row > div:last-child { justify-content: flex-start !important; }
|
.mtc-product-grid { grid-template-columns: 1fr !important; }
|
||||||
.sp-cta-grid { grid-template-columns: 1fr !important; gap: 40px !important; }
|
|
||||||
.sp-product-grid { grid-template-columns: 1fr !important; }
|
|
||||||
}
|
|
||||||
@media (max-width: 480px) {
|
|
||||||
.sp-cta-grid > div > div { grid-template-columns: 1fr !important; }
|
|
||||||
}
|
}
|
||||||
`}</style>
|
`}</style>
|
||||||
</main>
|
</main>
|
||||||
|
|||||||
@@ -14,6 +14,70 @@ const OUTCOMES = [
|
|||||||
{ stat: '9ms', label: 'Real-time decision latency' },
|
{ stat: '9ms', label: 'Real-time decision latency' },
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const CAPS = [
|
||||||
|
{
|
||||||
|
n: '01', title: 'Merchant Campaign Platform', color: '#f4be28',
|
||||||
|
desc: 'Register your store, upload products and inventory, then launch interactive promotional campaigns in minutes. Define maximum discounts per product and track performance in real time.',
|
||||||
|
metrics: [{ val: '5+', lbl: 'Game formats' }, { val: '1-click', lbl: 'Campaign setup' }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
n: '02', title: 'Game Based Discount Engine', color: '#a78bfa',
|
||||||
|
desc: 'Select a product, choose a game (Maze, Spin Wheel, Scratch Card, or Match Master) and set a maximum discount. Customers play once and discover their reward only after completing the game.',
|
||||||
|
metrics: [{ val: '4×', lbl: 'Engagement lift' }, { val: '100%', lbl: 'Margin controlled' }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
n: '03', title: 'Smart Coupon System', color: '#34d399',
|
||||||
|
desc: 'Generate daily surprise coupons through the Battery Challenge and other activities. Offer flat discounts, BOGO, percentage-off deals, festival specials, and brand promotions, fresh every day.',
|
||||||
|
metrics: [{ val: '6', lbl: 'Coupon types' }, { val: 'Daily', lbl: 'Fresh surprises' }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
n: '04', title: 'Footfall & Campaign Analytics', color: '#f97316',
|
||||||
|
desc: 'Track which campaigns drove store visits, measure conversion rates, monitor repeat footfall, and optimize your promotional budget with a real-time analytics dashboard.',
|
||||||
|
metrics: [{ val: '98%', lbl: 'Count accuracy' }, { val: '<9ms', lbl: 'Real-time latency' }],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const STEPS = [
|
||||||
|
{
|
||||||
|
n: '01', title: 'Sign Up', desc: 'Create your Loyaly merchant account in minutes.', color: '#f4be28',
|
||||||
|
icon: <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M16 21v-2a4 4 0 00-4-4H6a4 4 0 00-4 4v2"/><circle cx="9" cy="7" r="4"/><line x1="19" y1="8" x2="19" y2="14"/><line x1="22" y1="11" x2="16" y2="11"/></svg>,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
n: '02', title: 'Upload Your Products', desc: 'Add your catalogue, deals, and offers to the platform.', color: '#a78bfa',
|
||||||
|
icon: <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4"/><polyline points="17 8 12 3 7 8"/><line x1="12" y1="3" x2="12" y2="15"/></svg>,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
n: '03', title: 'Publish Your Offers', desc: 'Go live with targeted deals your nearby customers will see instantly.', color: '#34d399',
|
||||||
|
icon: <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M3 11l18-5v12L3 14v-3z"/><path d="M11.6 16.8a3 3 0 11-5.8-1.6"/></svg>,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
n: '04', title: 'Connect to Customers', desc: 'Loyaly matches you with shoppers in your area who are ready to buy.', color: '#f97316',
|
||||||
|
icon: <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M17 21v-2a4 4 0 00-4-4H5a4 4 0 00-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M23 21v-2a4 4 0 00-3-3.87"/><path d="M16 3.13a4 4 0 010 7.75"/></svg>,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
n: '05', title: 'Close the Deal', desc: 'Customers walk in. They purchase. You grow.', color: '#f4be28',
|
||||||
|
icon: <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M20 6L9 17l-5-5"/></svg>,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const PILLARS = [
|
||||||
|
{
|
||||||
|
title: 'Get Online', color: '#f4be28',
|
||||||
|
desc: 'Your store, visible to thousands of local shoppers, without building a website.',
|
||||||
|
icon: <svg width="26" height="26" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="10"/><line x1="2" y1="12" x2="22" y2="12"/><path d="M12 2a15.3 15.3 0 010 20 15.3 15.3 0 010-20z"/></svg>,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Get Noticed', color: '#a78bfa',
|
||||||
|
desc: "Push real-time offers and proximity alerts that reach customers the moment they're nearby.",
|
||||||
|
icon: <svg width="26" height="26" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><path d="M18 8a6 6 0 10-12 0c0 7-3 9-3 9h18s-3-2-3-9"/><path d="M13.73 21a2 2 0 01-3.46 0"/></svg>,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Get Simplified', color: '#34d399',
|
||||||
|
desc: 'One dashboard. All your deals, customers, and performance, managed in one place.',
|
||||||
|
icon: <svg width="26" height="26" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><rect x="3" y="3" width="7" height="9" rx="1"/><rect x="14" y="3" width="7" height="5" rx="1"/><rect x="14" y="12" width="7" height="9" rx="1"/><rect x="3" y="16" width="7" height="5" rx="1"/></svg>,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
const WHO = [
|
const WHO = [
|
||||||
{
|
{
|
||||||
label: 'Retail Stores',
|
label: 'Retail Stores',
|
||||||
@@ -48,6 +112,7 @@ function RevealBlock({ children, delay = 0, className = '' }: { children: React.
|
|||||||
|
|
||||||
export default function ForBusinessPage() {
|
export default function ForBusinessPage() {
|
||||||
const [countVisible, setCountVisible] = useState(false);
|
const [countVisible, setCountVisible] = useState(false);
|
||||||
|
const [hovered, setHovered] = useState<number | null>(null);
|
||||||
const statsRef = useRef<HTMLDivElement>(null);
|
const statsRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -162,6 +227,186 @@ export default function ForBusinessPage() {
|
|||||||
{/* ── PRODUCTS ── */}
|
{/* ── PRODUCTS ── */}
|
||||||
<ProductsScrollSection />
|
<ProductsScrollSection />
|
||||||
|
|
||||||
|
{/* ── CAPABILITIES ── */}
|
||||||
|
<section style={{ padding: '140px 8%', background: '#fff', margin: '0 20px 20px', borderRadius: 24 }}>
|
||||||
|
<RevealBlock>
|
||||||
|
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-end', marginBottom: 80, flexWrap: 'wrap', gap: 24 }}>
|
||||||
|
<div>
|
||||||
|
<div style={{ fontSize: 11, fontWeight: 700, letterSpacing: '0.2em', textTransform: 'uppercase', color: '#f4be28', fontFamily: 'Sora, sans-serif', marginBottom: 16 }}>Capabilities</div>
|
||||||
|
<h2 style={{ fontSize: 'clamp(36px, 5vw, 72px)', fontWeight: 800, letterSpacing: '-0.04em', lineHeight: 0.95, color: '#0a0a0f', margin: 0, fontFamily: 'Sora, sans-serif' }}>
|
||||||
|
Four tools.<br />One merchant platform.
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
<p style={{ fontSize: 16, color: 'rgba(0,0,0,0.45)', fontFamily: 'Sora, sans-serif', maxWidth: 360, lineHeight: 1.7 }}>
|
||||||
|
Every tool works independently and amplifies the others, giving merchants a complete system to attract, engage, and retain customers.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</RevealBlock>
|
||||||
|
|
||||||
|
<div style={{ display: 'flex', flexDirection: 'column', gap: 2 }}>
|
||||||
|
{CAPS.map((cap, i) => (
|
||||||
|
<RevealBlock key={i} delay={i * 0.08}>
|
||||||
|
<div
|
||||||
|
onMouseEnter={() => setHovered(i)}
|
||||||
|
onMouseLeave={() => setHovered(null)}
|
||||||
|
className="uc-cap-row"
|
||||||
|
style={{
|
||||||
|
display: 'grid', gridTemplateColumns: '80px 1fr 1fr auto',
|
||||||
|
alignItems: 'center', gap: '4vw',
|
||||||
|
padding: '40px 0',
|
||||||
|
borderBottom: '1px solid rgba(0,0,0,0.07)',
|
||||||
|
cursor: 'default',
|
||||||
|
transition: 'all 0.3s ease',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<span style={{ fontSize: 13, fontWeight: 700, color: hovered === i ? cap.color : 'rgba(0,0,0,0.2)', fontFamily: 'Sora, sans-serif', letterSpacing: '0.06em', transition: 'color 0.3s' }}>{cap.n}</span>
|
||||||
|
<h3 style={{ fontSize: 'clamp(22px, 2.8vw, 40px)', fontWeight: 800, color: hovered === i ? '#0a0a0f' : 'rgba(0,0,0,0.8)', fontFamily: 'Sora, sans-serif', letterSpacing: '-0.03em', margin: 0, transition: 'color 0.3s' }}>{cap.title}</h3>
|
||||||
|
<p style={{ fontSize: 15, color: 'rgba(0,0,0,0.45)', fontFamily: 'Sora, sans-serif', margin: 0, lineHeight: 1.6, maxWidth: 340 }}>{cap.desc}</p>
|
||||||
|
<div style={{ display: 'flex', gap: 28 }}>
|
||||||
|
{cap.metrics.map((m, j) => (
|
||||||
|
<div key={j} style={{ textAlign: 'right' }}>
|
||||||
|
<div style={{ fontSize: 22, fontWeight: 900, color: cap.color, fontFamily: 'Sora, sans-serif', letterSpacing: '-0.03em' }}>{m.val}</div>
|
||||||
|
<div style={{ fontSize: 11, color: 'rgba(0,0,0,0.35)', fontFamily: 'Sora, sans-serif', marginTop: 3 }}>{m.lbl}</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</RevealBlock>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* ── HOW IT WORKS ── */}
|
||||||
|
<section style={{ padding: '140px 8%', background: '#07070d', margin: '0 20px 20px', borderRadius: 24, overflow: 'hidden', position: 'relative' }}>
|
||||||
|
<div style={{ position: 'absolute', inset: 0, backgroundImage: 'linear-gradient(rgba(244,190,40,0.025) 1px,transparent 1px),linear-gradient(90deg,rgba(244,190,40,0.025) 1px,transparent 1px)', backgroundSize: '64px 64px', pointerEvents: 'none' }} />
|
||||||
|
<RevealBlock>
|
||||||
|
<div style={{ fontSize: 11, fontWeight: 700, letterSpacing: '0.2em', textTransform: 'uppercase', color: '#f4be28', fontFamily: 'Sora, sans-serif', marginBottom: 20, position: 'relative' }}>How It Works</div>
|
||||||
|
<h2 style={{ fontSize: 'clamp(36px, 5vw, 72px)', fontWeight: 800, letterSpacing: '-0.04em', lineHeight: 0.95, color: '#fff', margin: '0 0 80px', fontFamily: 'Sora, sans-serif', maxWidth: 700, position: 'relative' }}>
|
||||||
|
Live in five steps.
|
||||||
|
</h2>
|
||||||
|
</RevealBlock>
|
||||||
|
<div className="uc-timeline" style={{ position: 'relative', maxWidth: 880 }}>
|
||||||
|
<div className="uc-timeline-line" aria-hidden style={{ position: 'absolute', left: 27, top: 8, bottom: 8, width: 2, background: 'linear-gradient(180deg, rgba(255,255,255,0.18) 0%, rgba(255,255,255,0.04) 100%)' }} />
|
||||||
|
{STEPS.map((step, i) => (
|
||||||
|
<RevealBlock key={step.n} delay={i * 0.08}>
|
||||||
|
<div className="uc-timeline-row" style={{
|
||||||
|
display: 'grid', gridTemplateColumns: '56px 1fr', gap: 28,
|
||||||
|
paddingBottom: i < STEPS.length - 1 ? 48 : 0,
|
||||||
|
position: 'relative',
|
||||||
|
}}>
|
||||||
|
<div style={{
|
||||||
|
width: 56, height: 56, borderRadius: '50%', flexShrink: 0,
|
||||||
|
background: '#0c0c12', border: `2px solid ${step.color}`,
|
||||||
|
display: 'flex', alignItems: 'center', justifyContent: 'center',
|
||||||
|
color: step.color, position: 'relative', zIndex: 1,
|
||||||
|
boxShadow: `0 0 0 6px #07070d, 0 8px 24px -8px ${step.color}80`,
|
||||||
|
}}>
|
||||||
|
{step.icon}
|
||||||
|
</div>
|
||||||
|
<div className="uc-timeline-card" style={{
|
||||||
|
background: 'rgba(255,255,255,0.03)', borderRadius: 18, padding: '26px 30px',
|
||||||
|
border: '1px solid rgba(255,255,255,0.08)', backdropFilter: 'blur(12px)',
|
||||||
|
display: 'flex', flexDirection: 'column', gap: 6,
|
||||||
|
}}>
|
||||||
|
<div style={{ display: 'flex', alignItems: 'baseline', gap: 12 }}>
|
||||||
|
<span style={{ fontSize: 12, fontWeight: 800, color: step.color, fontFamily: 'Sora, sans-serif', letterSpacing: '0.1em' }}>{step.n}</span>
|
||||||
|
<h3 style={{ fontSize: 'clamp(19px, 2.2vw, 26px)', fontWeight: 800, color: '#fff', fontFamily: 'Sora, sans-serif', margin: 0, letterSpacing: '-0.02em' }}>{step.title}</h3>
|
||||||
|
</div>
|
||||||
|
<p style={{ fontSize: 15, color: 'rgba(255,255,255,0.5)', fontFamily: 'Sora, sans-serif', margin: 0, lineHeight: 1.6 }}>{step.desc}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</RevealBlock>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* ── MERCHANT BENEFITS ── */}
|
||||||
|
<section style={{ padding: '140px 8%', background: '#fff', margin: '0 20px 20px', borderRadius: 24, overflow: 'hidden', position: 'relative' }}>
|
||||||
|
<RevealBlock>
|
||||||
|
<div style={{ fontSize: 11, fontWeight: 700, letterSpacing: '0.2em', textTransform: 'uppercase', color: '#f4be28', fontFamily: 'Sora, sans-serif', marginBottom: 20, position: 'relative' }}>Why Merchants Choose Us</div>
|
||||||
|
<h2 style={{ fontSize: 'clamp(36px, 5vw, 72px)', fontWeight: 800, letterSpacing: '-0.04em', lineHeight: 0.95, color: '#0a0a0f', margin: '0 0 80px', fontFamily: 'Sora, sans-serif', maxWidth: 700, position: 'relative' }}>
|
||||||
|
Three ways we grow your store.
|
||||||
|
</h2>
|
||||||
|
</RevealBlock>
|
||||||
|
<div className="uc-pillar-grid" style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 24, position: 'relative' }}>
|
||||||
|
{PILLARS.map((p, i) => (
|
||||||
|
<RevealBlock key={p.title} delay={i * 0.1}>
|
||||||
|
<div className="uc-pillar-card" style={{
|
||||||
|
padding: '36px 32px', borderRadius: 22, height: '100%', boxSizing: 'border-box',
|
||||||
|
background: `linear-gradient(160deg, ${p.color}14 0%, #faf9f6 60%)`,
|
||||||
|
border: `1px solid ${p.color}35`, position: 'relative', overflow: 'hidden',
|
||||||
|
transition: 'transform 0.35s cubic-bezier(0.22,1,0.36,1), border-color 0.35s ease',
|
||||||
|
}}>
|
||||||
|
<span style={{
|
||||||
|
position: 'absolute', top: -18, right: -10, fontSize: 96, fontWeight: 900,
|
||||||
|
color: 'transparent', WebkitTextStroke: `1px ${p.color}22`, fontFamily: 'Sora, sans-serif',
|
||||||
|
lineHeight: 1, userSelect: 'none', pointerEvents: 'none',
|
||||||
|
}}>0{i + 1}</span>
|
||||||
|
<div style={{
|
||||||
|
width: 54, height: 54, borderRadius: 16, marginBottom: 24,
|
||||||
|
background: `${p.color}18`, border: `1px solid ${p.color}45`,
|
||||||
|
display: 'flex', alignItems: 'center', justifyContent: 'center', color: p.color,
|
||||||
|
position: 'relative', zIndex: 1,
|
||||||
|
}}>{p.icon}</div>
|
||||||
|
<h3 style={{ fontSize: 22, fontWeight: 800, color: '#0a0a0f', fontFamily: 'Sora, sans-serif', margin: '0 0 12px', letterSpacing: '-0.02em', position: 'relative', zIndex: 1 }}>{p.title}</h3>
|
||||||
|
<p style={{ fontSize: 15, lineHeight: 1.7, color: 'rgba(0,0,0,0.55)', fontFamily: 'Sora, sans-serif', margin: '0 0 20px', position: 'relative', zIndex: 1 }}>{p.desc}</p>
|
||||||
|
<div style={{ height: 3, width: 40, borderRadius: 2, background: p.color, position: 'relative', zIndex: 1 }} />
|
||||||
|
</div>
|
||||||
|
</RevealBlock>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* ── PROXIMITY MARKETING ── */}
|
||||||
|
<section style={{ padding: '120px 8%', background: '#0c0a06', margin: '0 20px 20px', borderRadius: 24, overflow: 'hidden', position: 'relative' }}>
|
||||||
|
<div style={{ position: 'absolute', inset: 0, backgroundImage: 'linear-gradient(rgba(244,190,40,0.03) 1px,transparent 1px),linear-gradient(90deg,rgba(244,190,40,0.03) 1px,transparent 1px)', backgroundSize: '56px 56px', pointerEvents: 'none' }} />
|
||||||
|
<RevealBlock>
|
||||||
|
<div className="uc-proximity-grid" style={{ display: 'grid', gridTemplateColumns: '0.85fr 1.15fr', gap: '6vw', alignItems: 'center', position: 'relative' }}>
|
||||||
|
|
||||||
|
{/* Radar visual */}
|
||||||
|
<div className="uc-radar" style={{ position: 'relative', width: '100%', aspectRatio: '1 / 1', maxWidth: 320, margin: '0 auto' }}>
|
||||||
|
{[0, 1, 2].map((r) => (
|
||||||
|
<div key={r} className="uc-radar-ring" style={{
|
||||||
|
position: 'absolute', inset: 0, borderRadius: '50%',
|
||||||
|
border: '1.5px solid rgba(244,190,40,0.35)',
|
||||||
|
animation: `ucRadarPulse 3s ease-out ${r * 1}s infinite`,
|
||||||
|
}} />
|
||||||
|
))}
|
||||||
|
<div style={{
|
||||||
|
position: 'absolute', top: '50%', left: '50%', transform: 'translate(-50%,-50%)',
|
||||||
|
width: '34%', height: '34%', borderRadius: '50%',
|
||||||
|
background: 'radial-gradient(circle, #f4be28 0%, #c9960f 100%)',
|
||||||
|
display: 'flex', alignItems: 'center', justifyContent: 'center',
|
||||||
|
boxShadow: '0 0 40px rgba(244,190,40,0.5)',
|
||||||
|
}}>
|
||||||
|
<svg width="34%" height="34%" viewBox="0 0 24 24" fill="#111" style={{ width: '38%', height: '38%' }}>
|
||||||
|
<path d="M12 2C8.13 2 5 5.13 5 9c0 5.25 7 13 7 13s7-7.75 7-13c0-3.87-3.13-7-7-7zm0 9.5A2.5 2.5 0 1112 6.5a2.5 2.5 0 010 5z" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Content */}
|
||||||
|
<div>
|
||||||
|
<div style={{ fontSize: 11, fontWeight: 700, letterSpacing: '0.2em', textTransform: 'uppercase', color: '#f4be28', fontFamily: 'Sora, sans-serif', marginBottom: 20 }}>Capability Spotlight</div>
|
||||||
|
<h2 style={{ fontSize: 'clamp(28px, 3.6vw, 48px)', fontWeight: 800, letterSpacing: '-0.03em', lineHeight: 1.08, color: '#fff', margin: '0 0 20px', fontFamily: 'Sora, sans-serif' }}>
|
||||||
|
Reach customers the moment they're nearby.
|
||||||
|
</h2>
|
||||||
|
<p style={{ fontSize: 16, lineHeight: 1.8, color: 'rgba(255,255,255,0.5)', fontFamily: 'Sora, sans-serif', margin: '0 0 32px', maxWidth: 480 }}>
|
||||||
|
Loyaly's proximity engine sends instant notifications to shoppers browsing within your store's radius. No ad spend. No guesswork. Just timely, relevant offers delivered at exactly the right moment.
|
||||||
|
</p>
|
||||||
|
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 12 }}>
|
||||||
|
{[{ v: 'Instant', l: 'Notification speed' }, { v: '0', l: 'Ad spend required' }, { v: 'Real-time', l: 'Radius targeting' }].map((s) => (
|
||||||
|
<div key={s.l} style={{ padding: '14px 20px', borderRadius: 14, background: 'rgba(244,190,40,0.08)', border: '1px solid rgba(244,190,40,0.25)' }}>
|
||||||
|
<div style={{ fontSize: 18, fontWeight: 900, color: '#f4be28', fontFamily: 'Sora, sans-serif', letterSpacing: '-0.02em' }}>{s.v}</div>
|
||||||
|
<div style={{ fontSize: 11.5, color: 'rgba(255,255,255,0.45)', fontFamily: 'Sora, sans-serif', marginTop: 3 }}>{s.l}</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</RevealBlock>
|
||||||
|
</section>
|
||||||
|
|
||||||
{/* ── OUTCOMES ── */}
|
{/* ── OUTCOMES ── */}
|
||||||
<section ref={statsRef} style={{ padding: '140px 8%', background: '#fff', margin: '0 20px 20px', borderRadius: 24 }}>
|
<section ref={statsRef} style={{ padding: '140px 8%', background: '#fff', margin: '0 20px 20px', borderRadius: 24 }}>
|
||||||
<RevealBlock>
|
<RevealBlock>
|
||||||
@@ -235,16 +480,31 @@ export default function ForBusinessPage() {
|
|||||||
<style>{`
|
<style>{`
|
||||||
@keyframes shimmer { 0%{background-position:200% center} 100%{background-position:-200% center} }
|
@keyframes shimmer { 0%{background-position:200% center} 100%{background-position:-200% center} }
|
||||||
@keyframes floatY { 0%,100%{transform:translateY(0)} 50%{transform:translateY(-12px)} }
|
@keyframes floatY { 0%,100%{transform:translateY(0)} 50%{transform:translateY(-12px)} }
|
||||||
|
@keyframes ucRadarPulse {
|
||||||
|
0% { transform: scale(0.3); opacity: 0.9; }
|
||||||
|
100% { transform: scale(1.7); opacity: 0; }
|
||||||
|
}
|
||||||
|
.uc-pillar-card:hover { transform: translateY(-6px); }
|
||||||
@media (max-width: 860px) {
|
@media (max-width: 860px) {
|
||||||
.uc-challenge-grid { grid-template-columns: 1fr !important; gap: 40px !important; }
|
.uc-challenge-grid { grid-template-columns: 1fr !important; gap: 40px !important; }
|
||||||
.uc-outcomes-grid { grid-template-columns: repeat(2,1fr) !important; }
|
.uc-outcomes-grid { grid-template-columns: repeat(2,1fr) !important; }
|
||||||
.uc-outcomes-grid > div > div { border-radius: 16px !important; }
|
.uc-outcomes-grid > div > div { border-radius: 16px !important; }
|
||||||
.uc-who-grid { grid-template-columns: repeat(2,1fr) !important; }
|
.uc-who-grid { grid-template-columns: repeat(2,1fr) !important; }
|
||||||
|
.uc-cap-row { grid-template-columns: 1fr !important; gap: 14px !important; padding: 28px 0 !important; }
|
||||||
|
.uc-cap-row > div:last-child { justify-content: flex-start !important; }
|
||||||
|
.uc-pillar-grid { grid-template-columns: 1fr !important; }
|
||||||
|
.uc-proximity-grid { grid-template-columns: 1fr !important; gap: 40px !important; }
|
||||||
|
.uc-timeline-row { grid-template-columns: 44px 1fr !important; gap: 18px !important; }
|
||||||
|
.uc-timeline-row > div:first-child { width: 44px !important; height: 44px !important; }
|
||||||
|
.uc-timeline-line { left: 21px !important; }
|
||||||
}
|
}
|
||||||
@media (max-width: 520px) {
|
@media (max-width: 520px) {
|
||||||
.uc-outcomes-grid { grid-template-columns: 1fr !important; }
|
.uc-outcomes-grid { grid-template-columns: 1fr !important; }
|
||||||
.uc-who-grid { grid-template-columns: 1fr !important; }
|
.uc-who-grid { grid-template-columns: 1fr !important; }
|
||||||
}
|
}
|
||||||
|
@media (prefers-reduced-motion: reduce) {
|
||||||
|
.uc-radar-ring { animation: none !important; opacity: 0.4 !important; }
|
||||||
|
}
|
||||||
`}</style>
|
`}</style>
|
||||||
</main>
|
</main>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,154 +0,0 @@
|
|||||||
import Image from 'next/image';
|
|
||||||
import Link from 'next/link';
|
|
||||||
|
|
||||||
const FEATURES = [
|
|
||||||
{
|
|
||||||
icon: '👁',
|
|
||||||
title: 'Turn Footfall into Insight',
|
|
||||||
description:
|
|
||||||
'Real-time visitor tracking and movement analytics reveal exactly how customers move through your store, enabling smarter layout, staffing, and marketing decisions.',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
icon: '🎯',
|
|
||||||
title: 'Personalisation, Perfected',
|
|
||||||
description:
|
|
||||||
'AI-driven profiles let you deliver the right offer to the right customer at precisely the right moment — online, in-store, or both.',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
icon: '⚙️',
|
|
||||||
title: 'One Engine. Total Intelligence.',
|
|
||||||
description:
|
|
||||||
'A single unified platform connects footfall, loyalty, promotions, and revenue data so every team works from the same source of truth.',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
export default function About() {
|
|
||||||
return (
|
|
||||||
<section id="about" className="about-section" aria-label="About Loyaly.AI" style={{ margin: '0 20px 20px', borderRadius: '24px', overflow: 'hidden' }}>
|
|
||||||
{/* Two-column intro */}
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
display: 'grid',
|
|
||||||
gridTemplateColumns: 'repeat(auto-fit, minmax(280px, 1fr))',
|
|
||||||
gap: '48px',
|
|
||||||
alignItems: 'center',
|
|
||||||
maxWidth: '1200px',
|
|
||||||
margin: '0 auto',
|
|
||||||
padding: '80px 24px 60px',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{/* Image */}
|
|
||||||
<div style={{ position: 'relative', minHeight: '340px', borderRadius: '16px', overflow: 'hidden' }}>
|
|
||||||
<Image
|
|
||||||
src="/loyaly_php/assets/images/about.png"
|
|
||||||
alt="Loyaly.AI platform dashboard showing customer intelligence data"
|
|
||||||
fill
|
|
||||||
style={{ objectFit: 'cover' }}
|
|
||||||
sizes="(max-width: 768px) 100vw, 50vw"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Text */}
|
|
||||||
<div>
|
|
||||||
<p
|
|
||||||
style={{
|
|
||||||
margin: '0 0 12px',
|
|
||||||
fontSize: '13px',
|
|
||||||
fontWeight: 700,
|
|
||||||
textTransform: 'uppercase',
|
|
||||||
letterSpacing: '0.1em',
|
|
||||||
color: '#f4be28',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
About Us
|
|
||||||
</p>
|
|
||||||
<h2
|
|
||||||
style={{
|
|
||||||
margin: '0 0 20px',
|
|
||||||
fontSize: 'clamp(1.6rem, 3vw, 2.4rem)',
|
|
||||||
fontWeight: 800,
|
|
||||||
lineHeight: 1.2,
|
|
||||||
color: '#171512',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
AI Powered Customer Intelligence for Retail
|
|
||||||
</h2>
|
|
||||||
<p style={{ margin: '0 0 16px', fontSize: '16px', lineHeight: 1.75, color: '#4f463a' }}>
|
|
||||||
Loyaly.ai is an AI powered customer intelligence platform built for modern retail. We help
|
|
||||||
businesses understand who their customers are, what drives their behaviour, and how to
|
|
||||||
build lasting loyalty at every touchpoint.
|
|
||||||
</p>
|
|
||||||
<p style={{ margin: '0 0 28px', fontSize: '16px', lineHeight: 1.75, color: '#4f463a' }}>
|
|
||||||
From footfall tracking and personalised engagement to smart loyalty programmes and revenue
|
|
||||||
optimisation, Loyaly.AI gives retailers one unified platform to know their customers deeply
|
|
||||||
and act on that knowledge instantly.
|
|
||||||
</p>
|
|
||||||
<Link
|
|
||||||
href="/solutions_page"
|
|
||||||
style={{
|
|
||||||
display: 'inline-flex',
|
|
||||||
alignItems: 'center',
|
|
||||||
gap: '8px',
|
|
||||||
padding: '12px 28px',
|
|
||||||
background: '#f4be28',
|
|
||||||
color: '#171512',
|
|
||||||
borderRadius: '4px',
|
|
||||||
fontWeight: 700,
|
|
||||||
textDecoration: 'none',
|
|
||||||
fontSize: '15px',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Explore Our Solutions <span aria-hidden="true">→</span>
|
|
||||||
</Link>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Three-feature grid */}
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
background: '#fff2c8',
|
|
||||||
padding: '60px 24px',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
display: 'grid',
|
|
||||||
gridTemplateColumns: 'repeat(auto-fit, minmax(240px, 1fr))',
|
|
||||||
gap: '32px',
|
|
||||||
maxWidth: '1200px',
|
|
||||||
margin: '0 auto',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{FEATURES.map(({ icon, title, description }) => (
|
|
||||||
<div
|
|
||||||
key={title}
|
|
||||||
style={{
|
|
||||||
background: '#fff8e8',
|
|
||||||
borderRadius: '12px',
|
|
||||||
padding: '32px 28px',
|
|
||||||
boxShadow: '0 2px 12px rgba(23,21,18,0.06)',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div style={{ fontSize: '32px', marginBottom: '16px' }} aria-hidden="true">
|
|
||||||
{icon}
|
|
||||||
</div>
|
|
||||||
<h3
|
|
||||||
style={{
|
|
||||||
margin: '0 0 12px',
|
|
||||||
fontSize: '18px',
|
|
||||||
fontWeight: 700,
|
|
||||||
color: '#171512',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{title}
|
|
||||||
</h3>
|
|
||||||
<p style={{ margin: 0, fontSize: '15px', lineHeight: 1.7, color: '#4f463a' }}>
|
|
||||||
{description}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,193 +0,0 @@
|
|||||||
import Image from 'next/image';
|
|
||||||
import Link from 'next/link';
|
|
||||||
|
|
||||||
const CASE_STUDIES = [
|
|
||||||
{
|
|
||||||
slug: 'ai-maximises-discount-strategy',
|
|
||||||
title: 'Stop Wasting Discounts: How AI Maximises Every Offer You Give',
|
|
||||||
excerpt:
|
|
||||||
'Most retail discounts go to customers who would have bought anyway. Discover how Loyaly.AI\'s promotion intelligence engine targets the right buyers at the right margin.',
|
|
||||||
tags: ['AI Solutions', 'Retail Intelligence'],
|
|
||||||
image: '/loyaly_php/assets/images/case-study-2-img-960x718.jpeg',
|
|
||||||
imageAlt: 'Data visualisation showing AI-optimised discount targeting across customer segments',
|
|
||||||
readTime: '5 min read',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
slug: 'ai-redefining-retail-loyalty-2026',
|
|
||||||
title: 'Beyond Points: How AI is Redefining Retail Loyalty in 2026',
|
|
||||||
excerpt:
|
|
||||||
'Traditional points schemes are losing ground. Learn how AI-driven loyalty programmes build genuine relationships through personalisation, timing, and context-aware rewards.',
|
|
||||||
tags: ['AI Retail', 'Loyalty Intelligence'],
|
|
||||||
image: '/loyaly_php/assets/images/case-study-1-img-960x718.jpeg',
|
|
||||||
imageAlt: 'Retail customer using a loyalty app powered by Loyaly.AI',
|
|
||||||
readTime: '7 min read',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
export default function BlogSection() {
|
|
||||||
return (
|
|
||||||
<section
|
|
||||||
id="case-studies"
|
|
||||||
aria-label="Case studies"
|
|
||||||
style={{ padding: '80px 24px', background: '#fff8e8', margin: '0 20px 20px', borderRadius: '24px', overflow: 'hidden' }}
|
|
||||||
>
|
|
||||||
<div style={{ maxWidth: '1200px', margin: '0 auto' }}>
|
|
||||||
{/* Header */}
|
|
||||||
<div style={{ marginBottom: '48px', display: 'flex', alignItems: 'flex-end', justifyContent: 'space-between', flexWrap: 'wrap', gap: '16px' }}>
|
|
||||||
<div>
|
|
||||||
<p
|
|
||||||
style={{
|
|
||||||
margin: '0 0 10px',
|
|
||||||
fontSize: '13px',
|
|
||||||
fontWeight: 700,
|
|
||||||
textTransform: 'uppercase',
|
|
||||||
letterSpacing: '0.1em',
|
|
||||||
color: '#f4be28',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Case Studies
|
|
||||||
</p>
|
|
||||||
<h2
|
|
||||||
style={{
|
|
||||||
margin: 0,
|
|
||||||
fontSize: 'clamp(1.6rem, 3vw, 2.4rem)',
|
|
||||||
fontWeight: 800,
|
|
||||||
color: '#171512',
|
|
||||||
lineHeight: 1.2,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Insights from the Loyaly.AI field
|
|
||||||
</h2>
|
|
||||||
</div>
|
|
||||||
<Link
|
|
||||||
href="/blog_main"
|
|
||||||
style={{
|
|
||||||
display: 'inline-flex',
|
|
||||||
alignItems: 'center',
|
|
||||||
gap: '6px',
|
|
||||||
padding: '10px 22px',
|
|
||||||
border: '2px solid #f4be28',
|
|
||||||
borderRadius: '4px',
|
|
||||||
color: '#171512',
|
|
||||||
fontWeight: 700,
|
|
||||||
textDecoration: 'none',
|
|
||||||
fontSize: '14px',
|
|
||||||
whiteSpace: 'nowrap',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
All Articles <span aria-hidden="true">→</span>
|
|
||||||
</Link>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Card grid */}
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
display: 'grid',
|
|
||||||
gridTemplateColumns: 'repeat(auto-fit, minmax(300px, 1fr))',
|
|
||||||
gap: '32px',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{CASE_STUDIES.map(({ slug, title, excerpt, tags, image, imageAlt, readTime }) => (
|
|
||||||
<article
|
|
||||||
key={slug}
|
|
||||||
style={{
|
|
||||||
background: '#fff',
|
|
||||||
borderRadius: '16px',
|
|
||||||
overflow: 'hidden',
|
|
||||||
boxShadow: '0 2px 16px rgba(23,21,18,0.07)',
|
|
||||||
display: 'flex',
|
|
||||||
flexDirection: 'column',
|
|
||||||
transition: 'transform 0.25s ease, box-shadow 0.25s ease',
|
|
||||||
}}
|
|
||||||
onMouseEnter={e => {
|
|
||||||
const el = e.currentTarget as HTMLElement;
|
|
||||||
el.style.transform = 'translateY(-4px)';
|
|
||||||
el.style.boxShadow = '0 8px 32px rgba(23,21,18,0.12)';
|
|
||||||
}}
|
|
||||||
onMouseLeave={e => {
|
|
||||||
const el = e.currentTarget as HTMLElement;
|
|
||||||
el.style.transform = 'translateY(0)';
|
|
||||||
el.style.boxShadow = '0 2px 16px rgba(23,21,18,0.07)';
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{/* Image */}
|
|
||||||
<Link href={`/use_cases/${slug}`} tabIndex={-1} aria-hidden="true">
|
|
||||||
<div style={{ position: 'relative', height: '220px' }}>
|
|
||||||
<Image
|
|
||||||
src={image}
|
|
||||||
alt={imageAlt}
|
|
||||||
fill
|
|
||||||
style={{ objectFit: 'cover' }}
|
|
||||||
sizes="(max-width: 768px) 100vw, 50vw"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</Link>
|
|
||||||
|
|
||||||
{/* Content */}
|
|
||||||
<div style={{ padding: '28px', flex: 1, display: 'flex', flexDirection: 'column', gap: '12px' }}>
|
|
||||||
{/* Tags */}
|
|
||||||
<div style={{ display: 'flex', gap: '8px', flexWrap: 'wrap' }}>
|
|
||||||
{tags.map(tag => (
|
|
||||||
<span
|
|
||||||
key={tag}
|
|
||||||
style={{
|
|
||||||
padding: '4px 10px',
|
|
||||||
background: '#fff2c8',
|
|
||||||
color: '#bc7122',
|
|
||||||
borderRadius: '20px',
|
|
||||||
fontSize: '12px',
|
|
||||||
fontWeight: 700,
|
|
||||||
letterSpacing: '0.04em',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{tag}
|
|
||||||
</span>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h3
|
|
||||||
style={{
|
|
||||||
margin: 0,
|
|
||||||
fontSize: '18px',
|
|
||||||
fontWeight: 700,
|
|
||||||
lineHeight: 1.35,
|
|
||||||
color: '#171512',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Link
|
|
||||||
href={`/use_cases/${slug}`}
|
|
||||||
style={{ textDecoration: 'none', color: 'inherit' }}
|
|
||||||
>
|
|
||||||
{title}
|
|
||||||
</Link>
|
|
||||||
</h3>
|
|
||||||
|
|
||||||
<p style={{ margin: 0, fontSize: '14px', lineHeight: 1.7, color: '#4f463a', flex: 1 }}>
|
|
||||||
{excerpt}
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginTop: '8px' }}>
|
|
||||||
<span style={{ fontSize: '13px', color: '#bc7122', fontWeight: 600 }}>{readTime}</span>
|
|
||||||
<Link
|
|
||||||
href={`/use_cases/${slug}`}
|
|
||||||
style={{
|
|
||||||
fontSize: '14px',
|
|
||||||
fontWeight: 700,
|
|
||||||
color: '#171512',
|
|
||||||
textDecoration: 'none',
|
|
||||||
display: 'inline-flex',
|
|
||||||
alignItems: 'center',
|
|
||||||
gap: '4px',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Read more <span aria-hidden="true">→</span>
|
|
||||||
</Link>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</article>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -16,9 +16,9 @@ const NAV = [
|
|||||||
{
|
{
|
||||||
title: 'Platform',
|
title: 'Platform',
|
||||||
links: [
|
links: [
|
||||||
{ label: 'Behavision AI', href: '/solutions_page' },
|
{ label: 'Behavision AI', href: '/use_cases' },
|
||||||
{ label: 'SpendSense AI', href: '/solutions_page' },
|
{ label: 'SpendSense AI', href: '/use_cases' },
|
||||||
{ label: 'Dyscount AI', href: '/solutions_page' },
|
{ label: 'Dyscount AI', href: '/use_cases' },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,28 +0,0 @@
|
|||||||
'use client';
|
|
||||||
|
|
||||||
import React from 'react';
|
|
||||||
import { useGSAPReveal, RevealAnimation } from '@/hooks/useGSAPReveal';
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
children: React.ReactNode;
|
|
||||||
delay?: number;
|
|
||||||
animation?: RevealAnimation;
|
|
||||||
duration?: number;
|
|
||||||
ease?: string;
|
|
||||||
start?: string;
|
|
||||||
className?: string;
|
|
||||||
style?: React.CSSProperties;
|
|
||||||
as?: keyof React.JSX.IntrinsicElements;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function GSAPReveal({
|
|
||||||
children, delay = 0, animation = 'fade-up',
|
|
||||||
duration = 1.0, ease, start, className, style,
|
|
||||||
}: Props) {
|
|
||||||
const ref = useGSAPReveal({ delay, animation, duration, ease, start });
|
|
||||||
return (
|
|
||||||
<div ref={ref} className={className} style={{ willChange: 'transform, opacity', ...style }}>
|
|
||||||
{children}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,153 +0,0 @@
|
|||||||
import Image from 'next/image';
|
|
||||||
|
|
||||||
const PARTNERS = [
|
|
||||||
{ name: 'Partner 1', src: '/loyaly_php/assets/images/partners-1.png' },
|
|
||||||
{ name: 'Partner 2', src: '/loyaly_php/assets/images/partners-2.png' },
|
|
||||||
{ name: 'Partner 3', src: '/loyaly_php/assets/images/partners-3.png' },
|
|
||||||
{ name: 'Partner 4', src: '/loyaly_php/assets/images/partners-4.png' },
|
|
||||||
{ name: 'Partner 5', src: '/loyaly_php/assets/images/partners-5.png' },
|
|
||||||
{ name: 'Partner 6', src: '/loyaly_php/assets/images/partners-6.png' },
|
|
||||||
];
|
|
||||||
|
|
||||||
// Duplicate list so the CSS marquee loops seamlessly
|
|
||||||
const TRACK = [...PARTNERS, ...PARTNERS];
|
|
||||||
|
|
||||||
export default function Partners() {
|
|
||||||
return (
|
|
||||||
<section
|
|
||||||
id="partners"
|
|
||||||
aria-label="Our partners"
|
|
||||||
style={{ padding: '60px 0', overflow: 'hidden', background: '#fff8e8', margin: '0 20px 20px', borderRadius: '24px' }}
|
|
||||||
>
|
|
||||||
<div style={{ textAlign: 'center', padding: '0 24px 40px' }}>
|
|
||||||
<p
|
|
||||||
style={{
|
|
||||||
margin: '0 0 10px',
|
|
||||||
fontSize: '13px',
|
|
||||||
fontWeight: 700,
|
|
||||||
textTransform: 'uppercase',
|
|
||||||
letterSpacing: '0.1em',
|
|
||||||
color: '#f4be28',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Our Partners
|
|
||||||
</p>
|
|
||||||
<h2
|
|
||||||
style={{
|
|
||||||
margin: 0,
|
|
||||||
fontSize: 'clamp(1.2rem, 2.5vw, 1.8rem)',
|
|
||||||
fontWeight: 700,
|
|
||||||
color: '#171512',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Our trusted collaborators in progress and success
|
|
||||||
</h2>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Marquee track */}
|
|
||||||
<div
|
|
||||||
style={{ position: 'relative', overflow: 'hidden' }}
|
|
||||||
aria-hidden="true" // purely decorative – screen readers can skip
|
|
||||||
>
|
|
||||||
{/* Fade edges */}
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
position: 'absolute',
|
|
||||||
top: 0,
|
|
||||||
left: 0,
|
|
||||||
width: '120px',
|
|
||||||
height: '100%',
|
|
||||||
background: 'linear-gradient(to right, #fff8e8, transparent)',
|
|
||||||
zIndex: 1,
|
|
||||||
pointerEvents: 'none',
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
position: 'absolute',
|
|
||||||
top: 0,
|
|
||||||
right: 0,
|
|
||||||
width: '120px',
|
|
||||||
height: '100%',
|
|
||||||
background: 'linear-gradient(to left, #fff8e8, transparent)',
|
|
||||||
zIndex: 1,
|
|
||||||
pointerEvents: 'none',
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<div
|
|
||||||
className="partners-track"
|
|
||||||
style={{
|
|
||||||
display: 'flex',
|
|
||||||
alignItems: 'center',
|
|
||||||
gap: '56px',
|
|
||||||
width: 'max-content',
|
|
||||||
animation: 'marquee 28s linear infinite',
|
|
||||||
padding: '8px 0',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{TRACK.map(({ name, src }, i) => (
|
|
||||||
<div
|
|
||||||
key={`${name}-${i}`}
|
|
||||||
style={{
|
|
||||||
flex: '0 0 auto',
|
|
||||||
width: '140px',
|
|
||||||
height: '64px',
|
|
||||||
position: 'relative',
|
|
||||||
filter: 'grayscale(1)',
|
|
||||||
opacity: 0.6,
|
|
||||||
transition: 'filter 0.3s, opacity 0.3s',
|
|
||||||
}}
|
|
||||||
onMouseEnter={e => {
|
|
||||||
(e.currentTarget as HTMLDivElement).style.filter = 'grayscale(0)';
|
|
||||||
(e.currentTarget as HTMLDivElement).style.opacity = '1';
|
|
||||||
}}
|
|
||||||
onMouseLeave={e => {
|
|
||||||
(e.currentTarget as HTMLDivElement).style.filter = 'grayscale(1)';
|
|
||||||
(e.currentTarget as HTMLDivElement).style.opacity = '0.6';
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Image
|
|
||||||
src={src}
|
|
||||||
alt={name}
|
|
||||||
fill
|
|
||||||
style={{ objectFit: 'contain' }}
|
|
||||||
sizes="140px"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<style>{`
|
|
||||||
@keyframes marquee {
|
|
||||||
from { transform: translateX(0); }
|
|
||||||
to { transform: translateX(-50%); }
|
|
||||||
}
|
|
||||||
@media (prefers-reduced-motion: reduce) {
|
|
||||||
.partners-track { animation: none; }
|
|
||||||
}
|
|
||||||
`}</style>
|
|
||||||
|
|
||||||
{/* Accessible static list for screen readers */}
|
|
||||||
<ul
|
|
||||||
aria-label="Partner logos"
|
|
||||||
style={{
|
|
||||||
position: 'absolute',
|
|
||||||
width: '1px',
|
|
||||||
height: '1px',
|
|
||||||
overflow: 'hidden',
|
|
||||||
clip: 'rect(0,0,0,0)',
|
|
||||||
whiteSpace: 'nowrap',
|
|
||||||
listStyle: 'none',
|
|
||||||
margin: 0,
|
|
||||||
padding: 0,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{PARTNERS.map(({ name }) => (
|
|
||||||
<li key={name}>{name}</li>
|
|
||||||
))}
|
|
||||||
</ul>
|
|
||||||
</section>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,175 +0,0 @@
|
|||||||
'use client';
|
|
||||||
|
|
||||||
import React, { useRef, useEffect, useCallback } from 'react';
|
|
||||||
|
|
||||||
export default function PhoneWidget() {
|
|
||||||
const stageRef = useRef<HTMLDivElement>(null);
|
|
||||||
|
|
||||||
const onMove = useCallback((e: MouseEvent) => {
|
|
||||||
const el = stageRef.current;
|
|
||||||
if (!el) return;
|
|
||||||
const r = el.getBoundingClientRect();
|
|
||||||
const px = (e.clientX - r.left) / r.width - 0.5;
|
|
||||||
const py = (e.clientY - r.top) / r.height - 0.5;
|
|
||||||
el.style.setProperty('--rx', `${(-py * 8).toFixed(2)}deg`);
|
|
||||||
el.style.setProperty('--ry', `${(px * 10).toFixed(2)}deg`);
|
|
||||||
el.style.setProperty('--tx', `${(px * 18).toFixed(1)}px`);
|
|
||||||
el.style.setProperty('--ty', `${(py * 18).toFixed(1)}px`);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const onLeave = useCallback(() => {
|
|
||||||
const el = stageRef.current;
|
|
||||||
if (!el) return;
|
|
||||||
el.style.setProperty('--rx', '0deg');
|
|
||||||
el.style.setProperty('--ry', '0deg');
|
|
||||||
el.style.setProperty('--tx', '0px');
|
|
||||||
el.style.setProperty('--ty', '0px');
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const el = stageRef.current;
|
|
||||||
if (!el) return;
|
|
||||||
el.addEventListener('mousemove', onMove);
|
|
||||||
el.addEventListener('mouseleave', onLeave);
|
|
||||||
return () => {
|
|
||||||
el.removeEventListener('mousemove', onMove);
|
|
||||||
el.removeEventListener('mouseleave', onLeave);
|
|
||||||
};
|
|
||||||
}, [onMove, onLeave]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<style>{`
|
|
||||||
@keyframes pwOrbFloat { 0%,100%{transform:translateY(0) scale(1)} 50%{transform:translateY(-22px) scale(1.04)} }
|
|
||||||
@keyframes pwOrb2Float { 0%,100%{transform:translateY(0) scale(1)} 50%{transform:translateY(18px) scale(0.97)} }
|
|
||||||
@keyframes pwGlow { 0%,100%{box-shadow:0 0 30px rgba(244,190,40,0.2)} 50%{box-shadow:0 0 60px rgba(244,190,40,0.5),0 0 120px rgba(244,190,40,0.2)} }
|
|
||||||
@keyframes pwScreenShimmer { 0%{left:-40%} 60%{left:120%} 100%{left:120%} }
|
|
||||||
.pw-hero-grid { display: grid; grid-template-columns: 1fr auto; align-items: center; gap: 6vw; width: 100%; }
|
|
||||||
@media (max-width: 900px) { .pw-hero-grid { grid-template-columns: 1fr; } .pw-widget-col { display: none; } }
|
|
||||||
`}</style>
|
|
||||||
|
|
||||||
<div
|
|
||||||
ref={stageRef}
|
|
||||||
style={{
|
|
||||||
position: 'relative', display: 'flex',
|
|
||||||
justifyContent: 'center', alignItems: 'center',
|
|
||||||
perspective: 1200, cursor: 'default',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div style={{
|
|
||||||
transformStyle: 'preserve-3d',
|
|
||||||
transform: 'rotateX(var(--rx,0deg)) rotateY(var(--ry,0deg)) translate(var(--tx,0px), var(--ty,0px))',
|
|
||||||
transition: 'transform 0.5s cubic-bezier(0.22,1,0.36,1)',
|
|
||||||
position: 'relative',
|
|
||||||
}}>
|
|
||||||
{/* Glow ring */}
|
|
||||||
<div style={{
|
|
||||||
position: 'absolute', inset: -36, borderRadius: '56px',
|
|
||||||
background: 'radial-gradient(circle at 50% 50%, rgba(244,190,40,0.2) 0%, transparent 70%)',
|
|
||||||
animation: 'pwGlow 3s ease-in-out infinite',
|
|
||||||
}} />
|
|
||||||
|
|
||||||
{/* Phone shell */}
|
|
||||||
<div style={{
|
|
||||||
width: 268, height: 548, borderRadius: '48px',
|
|
||||||
background: 'linear-gradient(160deg, #22223a 0%, #10101c 100%)',
|
|
||||||
border: '1.5px solid rgba(255,255,255,0.1)',
|
|
||||||
boxShadow: '0 70px 130px rgba(0,0,0,0.8), 0 0 0 1px rgba(255,255,255,0.06), inset 0 1px 0 rgba(255,255,255,0.1)',
|
|
||||||
display: 'flex', flexDirection: 'column', overflow: 'hidden',
|
|
||||||
animation: 'pwOrbFloat 6s ease-in-out infinite', position: 'relative',
|
|
||||||
}}>
|
|
||||||
{/* Shimmer sweep */}
|
|
||||||
<div style={{ position: 'absolute', inset: 0, pointerEvents: 'none', zIndex: 20, overflow: 'hidden', borderRadius: '48px' }}>
|
|
||||||
<div style={{
|
|
||||||
position: 'absolute', top: '-20%', left: 0, width: '40%', height: '140%',
|
|
||||||
background: 'linear-gradient(105deg, transparent 0%, rgba(255,255,255,0.07) 50%, transparent 100%)',
|
|
||||||
animation: 'pwScreenShimmer 4.5s ease-in-out infinite', animationDelay: '1s',
|
|
||||||
}} />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Dynamic island */}
|
|
||||||
<div style={{ display: 'flex', justifyContent: 'center', paddingTop: 16, paddingBottom: 4 }}>
|
|
||||||
<div style={{ width: 96, height: 28, borderRadius: 20, background: '#080810', display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 6 }}>
|
|
||||||
<div style={{ width: 10, height: 10, borderRadius: '50%', background: '#1a1a28', border: '1px solid rgba(255,255,255,0.08)' }} />
|
|
||||||
<div style={{ width: 6, height: 6, borderRadius: '50%', background: '#0d0d18' }} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Header */}
|
|
||||||
<div style={{ padding: '8px 22px 12px' }}>
|
|
||||||
<div style={{ fontSize: 10, color: '#f4be28', fontWeight: 700, fontFamily: 'Sora, sans-serif', letterSpacing: '0.12em', textTransform: 'uppercase' }}>Good Morning</div>
|
|
||||||
<div style={{ fontSize: 16, color: '#fff', fontWeight: 800, fontFamily: 'Sora, sans-serif', marginTop: 2 }}>Loyaly ✦</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* LYTs balance card */}
|
|
||||||
<div style={{
|
|
||||||
margin: '0 14px', borderRadius: 22,
|
|
||||||
background: 'linear-gradient(135deg, #f4be28 0%, #e09820 100%)',
|
|
||||||
padding: '18px 20px', boxShadow: '0 8px 24px rgba(244,190,40,0.35)',
|
|
||||||
position: 'relative', overflow: 'hidden',
|
|
||||||
}}>
|
|
||||||
<div style={{ position: 'absolute', top: '-30%', right: '-10%', width: 110, height: 110, borderRadius: '50%', background: 'rgba(255,255,255,0.12)' }} />
|
|
||||||
<div style={{ fontSize: 10, color: 'rgba(23,21,18,0.65)', fontWeight: 700, fontFamily: 'Sora, sans-serif', letterSpacing: '0.1em', textTransform: 'uppercase' }}>Total LYTs</div>
|
|
||||||
<div style={{ fontSize: 34, color: '#171512', fontWeight: 900, fontFamily: 'Sora, sans-serif', letterSpacing: '-0.03em', marginTop: 2 }}>284</div>
|
|
||||||
<div style={{ fontSize: 10, color: 'rgba(23,21,18,0.6)', fontFamily: 'Sora, sans-serif', marginTop: 4 }}>≈ ₹284 redeemable</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Activity feed */}
|
|
||||||
<div style={{ padding: '14px 12px', display: 'flex', flexDirection: 'column', gap: 7, flex: 1 }}>
|
|
||||||
{[
|
|
||||||
{ label: 'Daily Login', pts: '+50', color: '#4ade80' },
|
|
||||||
{ label: 'Walking 5k Steps', pts: '+80', color: '#4ade80' },
|
|
||||||
{ label: 'Spin Wheel', pts: '-50', color: '#f87171' },
|
|
||||||
].map((item, i) => (
|
|
||||||
<div key={i} style={{
|
|
||||||
display: 'flex', justifyContent: 'space-between', alignItems: 'center',
|
|
||||||
background: 'rgba(255,255,255,0.04)', borderRadius: 12, padding: '10px 13px',
|
|
||||||
border: '1px solid rgba(255,255,255,0.06)',
|
|
||||||
}}>
|
|
||||||
<span style={{ fontSize: 12, color: 'rgba(255,255,255,0.78)', fontFamily: 'Sora, sans-serif' }}>{item.label}</span>
|
|
||||||
<span style={{ fontSize: 12, color: item.color, fontWeight: 700, fontFamily: 'Sora, sans-serif' }}>{item.pts}</span>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Nav dots */}
|
|
||||||
<div style={{ display: 'flex', justifyContent: 'center', gap: 6, padding: '10px 0 20px' }}>
|
|
||||||
{[1, 0, 0, 0].map((a, i) => (
|
|
||||||
<div key={i} style={{ width: a ? 22 : 6, height: 4, borderRadius: 2, background: a ? '#f4be28' : 'rgba(255,255,255,0.2)' }} />
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Floating chip — top left */}
|
|
||||||
<div style={{
|
|
||||||
position: 'absolute', top: '12%', left: '-22%', borderRadius: 16,
|
|
||||||
padding: '12px 16px', display: 'flex', alignItems: 'center', gap: 10,
|
|
||||||
background: 'rgba(255,255,255,0.08)', backdropFilter: 'blur(20px)',
|
|
||||||
border: '1px solid rgba(255,255,255,0.12)',
|
|
||||||
boxShadow: '0 8px 32px rgba(0,0,0,0.4)',
|
|
||||||
animation: 'pwOrb2Float 7s ease-in-out infinite',
|
|
||||||
}}>
|
|
||||||
<div style={{ width: 30, height: 30, borderRadius: 9, background: 'rgba(74,222,128,0.16)', display: 'flex', alignItems: 'center', justifyContent: 'center', color: '#4ade80', fontSize: 14, fontWeight: 800 }}>↑</div>
|
|
||||||
<div>
|
|
||||||
<div style={{ fontSize: 11, fontWeight: 700, color: '#fff', fontFamily: 'Sora, sans-serif' }}>+120 LYTs</div>
|
|
||||||
<div style={{ fontSize: 9, color: 'rgba(255,255,255,0.4)', fontFamily: 'Sora, sans-serif' }}>just now</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Floating chip — bottom right */}
|
|
||||||
<div style={{
|
|
||||||
position: 'absolute', bottom: '14%', right: '-22%', borderRadius: 16,
|
|
||||||
padding: '12px 16px',
|
|
||||||
background: 'rgba(255,255,255,0.08)', backdropFilter: 'blur(20px)',
|
|
||||||
border: '1px solid rgba(255,255,255,0.12)',
|
|
||||||
boxShadow: '0 8px 32px rgba(0,0,0,0.4)',
|
|
||||||
animation: 'pwOrbFloat 8s ease-in-out infinite',
|
|
||||||
}}>
|
|
||||||
<div style={{ fontSize: 9, color: 'rgba(255,255,255,0.45)', fontFamily: 'Sora, sans-serif', letterSpacing: '0.1em', textTransform: 'uppercase', marginBottom: 3 }}>Redeemable</div>
|
|
||||||
<div style={{ fontSize: 17, fontWeight: 900, color: '#f4be28', fontFamily: 'Sora, sans-serif', letterSpacing: '-0.02em' }}>₹284.00</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,196 +0,0 @@
|
|||||||
'use client';
|
|
||||||
|
|
||||||
import { useEffect, useRef } from 'react';
|
|
||||||
|
|
||||||
interface Particle {
|
|
||||||
x: number;
|
|
||||||
y: number;
|
|
||||||
vx: number;
|
|
||||||
vy: number;
|
|
||||||
radius: number;
|
|
||||||
alpha: number;
|
|
||||||
type: 'lost' | 'converted' | 'regular';
|
|
||||||
pulseSpeed: number;
|
|
||||||
pulseTime: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function ProblemParticles() {
|
|
||||||
const canvasRef = useRef<HTMLCanvasElement | null>(null);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const canvas = canvasRef.current;
|
|
||||||
if (!canvas) return;
|
|
||||||
|
|
||||||
const ctx = canvas.getContext('2d');
|
|
||||||
if (!ctx) return;
|
|
||||||
|
|
||||||
let animationFrameId = 0;
|
|
||||||
let cssWidth = canvas.offsetWidth;
|
|
||||||
let cssHeight = canvas.offsetHeight;
|
|
||||||
|
|
||||||
const particles: Particle[] = [];
|
|
||||||
const storeNode = { x: cssWidth / 2, y: cssHeight / 2, radius: 18 };
|
|
||||||
|
|
||||||
const setCanvasSize = () => {
|
|
||||||
const dpr = Math.max(1, window.devicePixelRatio || 1);
|
|
||||||
cssWidth = canvas.offsetWidth;
|
|
||||||
cssHeight = canvas.offsetHeight;
|
|
||||||
canvas.width = Math.round(cssWidth * dpr);
|
|
||||||
canvas.height = Math.round(cssHeight * dpr);
|
|
||||||
// Map drawing coordinates to CSS pixels
|
|
||||||
ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
|
|
||||||
storeNode.x = cssWidth / 2;
|
|
||||||
storeNode.y = cssHeight / 2;
|
|
||||||
};
|
|
||||||
|
|
||||||
const createParticle = (isInitial = false): Particle => {
|
|
||||||
const typeRand = Math.random();
|
|
||||||
const type = typeRand < 0.2 ? 'lost' : typeRand < 0.45 ? 'converted' : 'regular';
|
|
||||||
|
|
||||||
let x: number, y: number;
|
|
||||||
if (isInitial) {
|
|
||||||
x = Math.random() * cssWidth;
|
|
||||||
y = Math.random() * cssHeight;
|
|
||||||
} else {
|
|
||||||
// Spawn from edges
|
|
||||||
if (Math.random() < 0.5) {
|
|
||||||
x = Math.random() < 0.5 ? 0 : cssWidth;
|
|
||||||
y = Math.random() * cssHeight;
|
|
||||||
} else {
|
|
||||||
x = Math.random() * cssWidth;
|
|
||||||
y = Math.random() < 0.5 ? 0 : cssHeight;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Vector pointing towards the store node (center)
|
|
||||||
const angle = Math.atan2(storeNode.y - y, storeNode.x - x);
|
|
||||||
const speed = 0.4 + Math.random() * 0.8;
|
|
||||||
|
|
||||||
return {
|
|
||||||
x,
|
|
||||||
y,
|
|
||||||
vx: Math.cos(angle) * speed + (Math.random() - 0.5) * 0.2,
|
|
||||||
vy: Math.sin(angle) * speed + (Math.random() - 0.5) * 0.2,
|
|
||||||
radius: 2 + Math.random() * 4,
|
|
||||||
alpha: 0.1 + Math.random() * 0.7,
|
|
||||||
type,
|
|
||||||
pulseSpeed: 0.05 + Math.random() * 0.05,
|
|
||||||
pulseTime: Math.random() * Math.PI,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
// Initialize
|
|
||||||
setCanvasSize();
|
|
||||||
for (let i = 0; i < 45; i++) particles.push(createParticle(true));
|
|
||||||
|
|
||||||
const handleResize = () => {
|
|
||||||
if (!canvas) return;
|
|
||||||
setCanvasSize();
|
|
||||||
};
|
|
||||||
|
|
||||||
window.addEventListener('resize', handleResize);
|
|
||||||
|
|
||||||
const draw = () => {
|
|
||||||
ctx.clearRect(0, 0, cssWidth, cssHeight);
|
|
||||||
|
|
||||||
// Background glow
|
|
||||||
const bgGlow = ctx.createRadialGradient(
|
|
||||||
storeNode.x,
|
|
||||||
storeNode.y,
|
|
||||||
10,
|
|
||||||
storeNode.x,
|
|
||||||
storeNode.y,
|
|
||||||
cssWidth * 0.4
|
|
||||||
);
|
|
||||||
bgGlow.addColorStop(0, 'rgba(0, 102, 255, 0.08)');
|
|
||||||
bgGlow.addColorStop(1, 'rgba(0, 0, 0, 0)');
|
|
||||||
ctx.fillStyle = bgGlow;
|
|
||||||
ctx.fillRect(0, 0, cssWidth, cssHeight);
|
|
||||||
|
|
||||||
// Store hub
|
|
||||||
ctx.shadowBlur = 30;
|
|
||||||
ctx.shadowColor = '#0066ff';
|
|
||||||
ctx.fillStyle = 'rgba(0, 102, 255, 0.9)';
|
|
||||||
ctx.beginPath();
|
|
||||||
ctx.arc(storeNode.x, storeNode.y, storeNode.radius, 0, Math.PI * 2);
|
|
||||||
ctx.fill();
|
|
||||||
|
|
||||||
ctx.strokeStyle = 'rgba(255, 255, 255, 0.6)';
|
|
||||||
ctx.lineWidth = 2;
|
|
||||||
ctx.beginPath();
|
|
||||||
ctx.arc(storeNode.x, storeNode.y, storeNode.radius - 6, 0, Math.PI * 2);
|
|
||||||
ctx.stroke();
|
|
||||||
ctx.shadowBlur = 0;
|
|
||||||
|
|
||||||
// Particles
|
|
||||||
particles.forEach((p, idx) => {
|
|
||||||
p.x += p.vx;
|
|
||||||
p.y += p.vy;
|
|
||||||
p.pulseTime += p.pulseSpeed;
|
|
||||||
|
|
||||||
let alpha = p.alpha;
|
|
||||||
let radius = p.radius;
|
|
||||||
|
|
||||||
if (p.type === 'converted') {
|
|
||||||
alpha = Math.max(0.4, p.alpha + Math.sin(p.pulseTime) * 0.3);
|
|
||||||
radius = p.radius + Math.sin(p.pulseTime) * 1.5;
|
|
||||||
} else if (p.type === 'lost') {
|
|
||||||
const dist = Math.hypot(storeNode.x - p.x, storeNode.y - p.y);
|
|
||||||
if (dist < 150) p.alpha -= 0.008;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Connections between particles
|
|
||||||
for (let j = idx + 1; j < particles.length; j++) {
|
|
||||||
const p2 = particles[j];
|
|
||||||
const dist = Math.hypot(p2.x - p.x, p2.y - p.y);
|
|
||||||
if (dist < 80 && p.alpha > 0 && p2.alpha > 0) {
|
|
||||||
const lineAlpha = (1 - dist / 80) * 0.18 * Math.min(alpha, p2.alpha);
|
|
||||||
ctx.strokeStyle = `rgba(0, 102, 255, ${lineAlpha})`;
|
|
||||||
ctx.lineWidth = 1;
|
|
||||||
ctx.beginPath();
|
|
||||||
ctx.moveTo(p.x, p.y);
|
|
||||||
ctx.lineTo(p2.x, p2.y);
|
|
||||||
ctx.stroke();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Connection to store hub
|
|
||||||
const distToStore = Math.hypot(storeNode.x - p.x, storeNode.y - p.y);
|
|
||||||
if (distToStore < 120 && p.alpha > 0) {
|
|
||||||
const lineAlpha = (1 - distToStore / 120) * 0.25 * p.alpha;
|
|
||||||
ctx.strokeStyle = p.type === 'converted' ? `rgba(0, 220, 255, ${lineAlpha})` : `rgba(0, 102, 255, ${lineAlpha})`;
|
|
||||||
ctx.beginPath();
|
|
||||||
ctx.moveTo(p.x, p.y);
|
|
||||||
ctx.lineTo(storeNode.x, storeNode.y);
|
|
||||||
ctx.stroke();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Respawn check
|
|
||||||
if (distToStore < storeNode.radius || p.x < 0 || p.x > cssWidth || p.y < 0 || p.y > cssHeight || p.alpha <= 0) {
|
|
||||||
particles[idx] = createParticle();
|
|
||||||
} else {
|
|
||||||
ctx.fillStyle = p.type === 'converted' ? `rgba(0, 220, 255, ${alpha})` : p.type === 'lost' ? `rgba(255, 68, 68, ${alpha})` : `rgba(255, 255, 255, ${alpha})`;
|
|
||||||
if (p.type === 'converted') {
|
|
||||||
ctx.shadowBlur = 10;
|
|
||||||
ctx.shadowColor = '#00dcff';
|
|
||||||
}
|
|
||||||
ctx.beginPath();
|
|
||||||
ctx.arc(p.x, p.y, radius, 0, Math.PI * 2);
|
|
||||||
ctx.fill();
|
|
||||||
ctx.shadowBlur = 0;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
animationFrameId = requestAnimationFrame(draw);
|
|
||||||
};
|
|
||||||
|
|
||||||
draw();
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
window.removeEventListener('resize', handleResize);
|
|
||||||
cancelAnimationFrame(animationFrameId);
|
|
||||||
};
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return <canvas ref={canvasRef} className="w-full h-full absolute inset-0" />;
|
|
||||||
}
|
|
||||||
@@ -1,237 +0,0 @@
|
|||||||
'use client';
|
|
||||||
|
|
||||||
import { useState } from 'react';
|
|
||||||
import Image from 'next/image';
|
|
||||||
import Link from 'next/link';
|
|
||||||
|
|
||||||
const SOLUTIONS = [
|
|
||||||
{
|
|
||||||
id: 'footfall',
|
|
||||||
category: 'AI Solution',
|
|
||||||
title: 'Footfall Intelligence',
|
|
||||||
subtitle: 'Understand Customer Movement in Real Time',
|
|
||||||
excerpt:
|
|
||||||
'Track visitor count, movement patterns, and peak hours across your retail spaces. Turn anonymous foot traffic into actionable intelligence that drives layout, staffing, and promotions.',
|
|
||||||
image: '/loyaly_php/assets/images/deepvision-fi-640x640.jpg',
|
|
||||||
imageAlt: 'Footfall Intelligence dashboard showing real-time customer movement heatmaps',
|
|
||||||
href: '/solutions/footfall-intelligence',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'journey',
|
|
||||||
category: 'AI Solution',
|
|
||||||
title: 'Customer Journey',
|
|
||||||
subtitle: 'Map Every Interaction Seamlessly',
|
|
||||||
excerpt:
|
|
||||||
'Track and understand each step of your customer\'s journey — online and in-store — to identify friction points, improve conversion, and deliver experiences that build loyalty.',
|
|
||||||
image: '/loyaly_php/assets/images/nlpgenius-natural-language-processing-fi-640x640.jpg',
|
|
||||||
imageAlt: 'Customer journey map visualisation inside Loyaly.AI platform',
|
|
||||||
href: '/solutions/customer-journey',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'engagement',
|
|
||||||
category: 'AI Solution',
|
|
||||||
title: 'Customer Engagement',
|
|
||||||
subtitle: 'Drive Meaningful Interactions',
|
|
||||||
excerpt:
|
|
||||||
'Analyse behaviour and preferences to deliver personalised experiences, timely offers, and targeted messaging that keep customers coming back.',
|
|
||||||
image: '/loyaly_php/assets/images/smarttrader-predictive-stock-market-analysis-fi-640x640.jpg',
|
|
||||||
imageAlt: 'Customer engagement analytics showing personalisation performance metrics',
|
|
||||||
href: '/solutions/customer-engagement',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'loyalty',
|
|
||||||
category: 'AI Solution',
|
|
||||||
title: 'Loyalty Management',
|
|
||||||
subtitle: 'Build Lasting Relationships',
|
|
||||||
excerpt:
|
|
||||||
'Reward customer loyalty with smart programmes that adapt in real time — from LYTs and tiers to personalised perks that feel genuinely earned.',
|
|
||||||
image: '/loyaly_php/assets/images/cognivision-transformative-ai-for-intelligent-fi-640x640.jpg',
|
|
||||||
imageAlt: 'Loyalty management module showing customer tier performance',
|
|
||||||
href: '/solutions/loyalty-management',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'revenue',
|
|
||||||
category: 'AI Solution',
|
|
||||||
title: 'Revenue Optimisation',
|
|
||||||
subtitle: 'Maximise Business Performance',
|
|
||||||
excerpt:
|
|
||||||
'Leverage data insights to optimise pricing, promotions, and strategies for higher revenue growth — without sacrificing margin.',
|
|
||||||
image: '/loyaly_php/assets/images/neuraforge-crafting-future-ready-ai-solutions-fi-640x640.jpg',
|
|
||||||
imageAlt: 'Revenue optimisation charts showing margin improvements',
|
|
||||||
href: '/solutions/revenue-optimisation',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
export default function Solutions() {
|
|
||||||
const [hoveredId, setHoveredId] = useState<string | null>(null);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<section
|
|
||||||
id="solutions"
|
|
||||||
aria-label="Our solutions"
|
|
||||||
style={{ padding: '80px 24px', background: '#fff', margin: '0 20px 20px', borderRadius: '24px', overflow: 'hidden' }}
|
|
||||||
>
|
|
||||||
<div style={{ maxWidth: '1200px', margin: '0 auto' }}>
|
|
||||||
{/* Header */}
|
|
||||||
<div style={{ marginBottom: '56px', maxWidth: '640px' }}>
|
|
||||||
<p
|
|
||||||
style={{
|
|
||||||
margin: '0 0 12px',
|
|
||||||
fontSize: '13px',
|
|
||||||
fontWeight: 700,
|
|
||||||
textTransform: 'uppercase',
|
|
||||||
letterSpacing: '0.1em',
|
|
||||||
color: '#f4be28',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Our Solutions
|
|
||||||
</p>
|
|
||||||
<h2
|
|
||||||
style={{
|
|
||||||
margin: '0 0 16px',
|
|
||||||
fontSize: 'clamp(1.6rem, 3vw, 2.4rem)',
|
|
||||||
fontWeight: 800,
|
|
||||||
lineHeight: 1.2,
|
|
||||||
color: '#171512',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Exploring groundbreaking AI solutions transforming retail
|
|
||||||
</h2>
|
|
||||||
<p style={{ margin: 0, fontSize: '16px', lineHeight: 1.7, color: '#4f463a' }}>
|
|
||||||
From understanding footfall to optimising revenue, our five AI modules work independently
|
|
||||||
or together as one unified intelligence engine.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Grid */}
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
display: 'grid',
|
|
||||||
gridTemplateColumns: 'repeat(auto-fill, minmax(300px, 1fr))',
|
|
||||||
gap: '28px',
|
|
||||||
marginBottom: '48px',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{SOLUTIONS.map(({ id, category, title, subtitle, excerpt, image, imageAlt, href }) => {
|
|
||||||
const isHovered = hoveredId === id;
|
|
||||||
return (
|
|
||||||
<article
|
|
||||||
key={id}
|
|
||||||
onMouseEnter={() => setHoveredId(id)}
|
|
||||||
onMouseLeave={() => setHoveredId(null)}
|
|
||||||
style={{
|
|
||||||
background: '#fff8e8',
|
|
||||||
borderRadius: '16px',
|
|
||||||
overflow: 'hidden',
|
|
||||||
boxShadow: isHovered
|
|
||||||
? '0 12px 40px rgba(23,21,18,0.14)'
|
|
||||||
: '0 2px 12px rgba(23,21,18,0.06)',
|
|
||||||
transform: isHovered ? 'translateY(-6px)' : 'translateY(0)',
|
|
||||||
transition: 'transform 0.3s ease, box-shadow 0.3s ease',
|
|
||||||
display: 'flex',
|
|
||||||
flexDirection: 'column',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{/* Card image */}
|
|
||||||
<Link href={href} tabIndex={-1} aria-hidden="true" style={{ display: 'block' }}>
|
|
||||||
<div style={{ position: 'relative', height: '220px', overflow: 'hidden' }}>
|
|
||||||
<Image
|
|
||||||
src={image}
|
|
||||||
alt={imageAlt}
|
|
||||||
fill
|
|
||||||
style={{
|
|
||||||
objectFit: 'cover',
|
|
||||||
transform: isHovered ? 'scale(1.05)' : 'scale(1)',
|
|
||||||
transition: 'transform 0.4s ease',
|
|
||||||
}}
|
|
||||||
sizes="(max-width: 640px) 100vw, (max-width: 1024px) 50vw, 33vw"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</Link>
|
|
||||||
|
|
||||||
{/* Card content */}
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
padding: '24px 24px 28px',
|
|
||||||
flex: 1,
|
|
||||||
display: 'flex',
|
|
||||||
flexDirection: 'column',
|
|
||||||
gap: '10px',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{/* Category badge */}
|
|
||||||
<span
|
|
||||||
style={{
|
|
||||||
display: 'inline-block',
|
|
||||||
padding: '4px 10px',
|
|
||||||
background: '#fff2c8',
|
|
||||||
color: '#bc7122',
|
|
||||||
borderRadius: '20px',
|
|
||||||
fontSize: '12px',
|
|
||||||
fontWeight: 700,
|
|
||||||
letterSpacing: '0.04em',
|
|
||||||
alignSelf: 'flex-start',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{category}
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<h3 style={{ margin: 0, fontSize: '19px', fontWeight: 800, color: '#171512', lineHeight: 1.2 }}>
|
|
||||||
<Link href={href} style={{ textDecoration: 'none', color: 'inherit' }}>
|
|
||||||
{title}
|
|
||||||
</Link>
|
|
||||||
</h3>
|
|
||||||
|
|
||||||
<p style={{ margin: 0, fontSize: '14px', fontWeight: 600, color: '#bc7122' }}>
|
|
||||||
{subtitle}
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p style={{ margin: 0, fontSize: '14px', lineHeight: 1.7, color: '#4f463a', flex: 1 }}>
|
|
||||||
{excerpt}
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<Link
|
|
||||||
href={href}
|
|
||||||
style={{
|
|
||||||
display: 'inline-flex',
|
|
||||||
alignItems: 'center',
|
|
||||||
gap: '6px',
|
|
||||||
marginTop: '8px',
|
|
||||||
fontWeight: 700,
|
|
||||||
fontSize: '14px',
|
|
||||||
color: '#171512',
|
|
||||||
textDecoration: 'none',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Explore more <span aria-hidden="true">→</span>
|
|
||||||
</Link>
|
|
||||||
</div>
|
|
||||||
</article>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* CTA */}
|
|
||||||
<div style={{ textAlign: 'center' }}>
|
|
||||||
<Link
|
|
||||||
href="/solutions_page"
|
|
||||||
style={{
|
|
||||||
display: 'inline-flex',
|
|
||||||
alignItems: 'center',
|
|
||||||
gap: '8px',
|
|
||||||
padding: '14px 36px',
|
|
||||||
background: '#f4be28',
|
|
||||||
color: '#171512',
|
|
||||||
borderRadius: '4px',
|
|
||||||
fontWeight: 700,
|
|
||||||
textDecoration: 'none',
|
|
||||||
fontSize: '16px',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
View all solutions <span aria-hidden="true">→</span>
|
|
||||||
</Link>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,211 +0,0 @@
|
|||||||
'use client';
|
|
||||||
|
|
||||||
import { useState, useEffect, useRef, useCallback } from 'react';
|
|
||||||
|
|
||||||
const TESTIMONIALS = [
|
|
||||||
{
|
|
||||||
quote:
|
|
||||||
'Loyaly.AI transformed how we understand our customers. Foot traffic insights alone helped us rearrange our store layout and boost average basket size by 18% in the first quarter.',
|
|
||||||
author: 'Priya Nair',
|
|
||||||
role: 'Head of Retail Operations',
|
|
||||||
company: 'Trendsetter Fashion Stores',
|
|
||||||
avatar: '/loyaly_php/assets/images/partners-1.png',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
quote:
|
|
||||||
'The AI powered loyalty engine learns fast. Within weeks we were delivering personalised offers that felt genuinely relevant — our repeat visit rate climbed 23%.',
|
|
||||||
author: 'Arjun Mehta',
|
|
||||||
role: 'VP of Customer Experience',
|
|
||||||
company: 'FreshMart Supermarkets',
|
|
||||||
avatar: '/loyaly_php/assets/images/partners-2.png',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
quote:
|
|
||||||
"We tried three loyalty platforms before Loyaly.AI. This is the first one that actually connects footfall data, promotions, and CRM in a single dashboard. It's changed how we run campaigns.",
|
|
||||||
author: 'Sarah Connelly',
|
|
||||||
role: 'Chief Marketing Officer',
|
|
||||||
company: 'Urban Living Group',
|
|
||||||
avatar: '/loyaly_php/assets/images/partners-3.png',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
export default function Testimonial() {
|
|
||||||
const [active, setActive] = useState(0);
|
|
||||||
const [paused, setPaused] = useState(false);
|
|
||||||
const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
|
||||||
const total = TESTIMONIALS.length;
|
|
||||||
|
|
||||||
const go = useCallback(
|
|
||||||
(index: number) => {
|
|
||||||
setActive((index + total) % total);
|
|
||||||
},
|
|
||||||
[total]
|
|
||||||
);
|
|
||||||
|
|
||||||
// Auto-advance every 6 s
|
|
||||||
useEffect(() => {
|
|
||||||
if (paused) return;
|
|
||||||
timerRef.current = setTimeout(() => go(active + 1), 6000);
|
|
||||||
return () => {
|
|
||||||
if (timerRef.current) clearTimeout(timerRef.current);
|
|
||||||
};
|
|
||||||
}, [active, paused, go]);
|
|
||||||
|
|
||||||
const { quote, author, role, company } = TESTIMONIALS[active];
|
|
||||||
|
|
||||||
return (
|
|
||||||
<section
|
|
||||||
id="testimonials"
|
|
||||||
aria-label="Customer testimonials"
|
|
||||||
style={{ background: '#171512', color: '#fff', padding: '80px 24px', margin: '0 20px 20px', borderRadius: '24px', overflow: 'hidden' }}
|
|
||||||
onMouseEnter={() => setPaused(true)}
|
|
||||||
onMouseLeave={() => setPaused(false)}
|
|
||||||
>
|
|
||||||
<div style={{ maxWidth: '860px', margin: '0 auto', textAlign: 'center' }}>
|
|
||||||
{/* Section label */}
|
|
||||||
<p
|
|
||||||
style={{
|
|
||||||
margin: '0 0 12px',
|
|
||||||
fontSize: '13px',
|
|
||||||
fontWeight: 700,
|
|
||||||
textTransform: 'uppercase',
|
|
||||||
letterSpacing: '0.1em',
|
|
||||||
color: '#f4be28',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Customer Stories
|
|
||||||
</p>
|
|
||||||
<h2
|
|
||||||
style={{
|
|
||||||
margin: '0 0 52px',
|
|
||||||
fontSize: 'clamp(1.4rem, 3vw, 2rem)',
|
|
||||||
fontWeight: 700,
|
|
||||||
lineHeight: 1.3,
|
|
||||||
color: '#fff',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
See how retailers are transforming customer loyalty with Loyaly.AI
|
|
||||||
</h2>
|
|
||||||
|
|
||||||
{/* Quote card */}
|
|
||||||
<div
|
|
||||||
key={active}
|
|
||||||
style={{
|
|
||||||
background: 'rgba(255,255,255,0.05)',
|
|
||||||
borderRadius: '16px',
|
|
||||||
padding: '48px 40px',
|
|
||||||
position: 'relative',
|
|
||||||
animation: 'fadeIn 0.5s ease',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{/* Decorative quote mark */}
|
|
||||||
<span
|
|
||||||
aria-hidden="true"
|
|
||||||
style={{
|
|
||||||
position: 'absolute',
|
|
||||||
top: '24px',
|
|
||||||
left: '32px',
|
|
||||||
fontSize: '80px',
|
|
||||||
lineHeight: 1,
|
|
||||||
color: '#f4be28',
|
|
||||||
opacity: 0.25,
|
|
||||||
fontFamily: 'Sora, serif',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
"
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<blockquote
|
|
||||||
style={{
|
|
||||||
margin: '0 0 32px',
|
|
||||||
fontSize: 'clamp(1rem, 2.2vw, 1.2rem)',
|
|
||||||
lineHeight: 1.8,
|
|
||||||
color: 'rgba(255,255,255,0.9)',
|
|
||||||
fontStyle: 'italic',
|
|
||||||
position: 'relative',
|
|
||||||
zIndex: 1,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{quote}
|
|
||||||
</blockquote>
|
|
||||||
|
|
||||||
<footer style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: '4px' }}>
|
|
||||||
<cite style={{ fontStyle: 'normal', fontWeight: 700, fontSize: '16px', color: '#f4be28' }}>
|
|
||||||
{author}
|
|
||||||
</cite>
|
|
||||||
<span style={{ fontSize: '14px', color: 'rgba(255,255,255,0.6)' }}>
|
|
||||||
{role}, {company}
|
|
||||||
</span>
|
|
||||||
</footer>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Navigation dots */}
|
|
||||||
<div
|
|
||||||
role="tablist"
|
|
||||||
aria-label="Testimonial navigation"
|
|
||||||
style={{ display: 'flex', justifyContent: 'center', gap: '10px', marginTop: '32px' }}
|
|
||||||
>
|
|
||||||
{TESTIMONIALS.map((_, i) => (
|
|
||||||
<button
|
|
||||||
key={i}
|
|
||||||
role="tab"
|
|
||||||
aria-selected={i === active}
|
|
||||||
aria-label={`Show testimonial ${i + 1}`}
|
|
||||||
onClick={() => { go(i); setPaused(true); }}
|
|
||||||
style={{
|
|
||||||
width: i === active ? '28px' : '10px',
|
|
||||||
height: '10px',
|
|
||||||
borderRadius: '5px',
|
|
||||||
background: i === active ? '#f4be28' : 'rgba(255,255,255,0.25)',
|
|
||||||
border: 'none',
|
|
||||||
cursor: 'pointer',
|
|
||||||
padding: 0,
|
|
||||||
transition: 'width 0.3s ease, background 0.3s ease',
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Prev / Next */}
|
|
||||||
<div style={{ display: 'flex', justifyContent: 'center', gap: '12px', marginTop: '20px' }}>
|
|
||||||
<button
|
|
||||||
onClick={() => { go(active - 1); setPaused(true); }}
|
|
||||||
aria-label="Previous testimonial"
|
|
||||||
style={arrowBtnStyle}
|
|
||||||
>
|
|
||||||
←
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
onClick={() => { go(active + 1); setPaused(true); }}
|
|
||||||
aria-label="Next testimonial"
|
|
||||||
style={arrowBtnStyle}
|
|
||||||
>
|
|
||||||
→
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<style>{`
|
|
||||||
@keyframes fadeIn {
|
|
||||||
from { opacity: 0; transform: translateY(12px); }
|
|
||||||
to { opacity: 1; transform: translateY(0); }
|
|
||||||
}
|
|
||||||
`}</style>
|
|
||||||
</section>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const arrowBtnStyle: React.CSSProperties = {
|
|
||||||
width: '40px',
|
|
||||||
height: '40px',
|
|
||||||
borderRadius: '50%',
|
|
||||||
background: 'rgba(255,255,255,0.08)',
|
|
||||||
color: '#fff',
|
|
||||||
border: '1px solid rgba(255,255,255,0.15)',
|
|
||||||
cursor: 'pointer',
|
|
||||||
fontSize: '16px',
|
|
||||||
display: 'flex',
|
|
||||||
alignItems: 'center',
|
|
||||||
justifyContent: 'center',
|
|
||||||
transition: 'background 0.2s',
|
|
||||||
};
|
|
||||||
@@ -1,8 +1,14 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import React, { useState } from 'react';
|
import React, { useState, useLayoutEffect, useEffect, useRef } from 'react';
|
||||||
import Image from 'next/image';
|
import Image from 'next/image';
|
||||||
import { PhoneFrame, PhoneBottomNav, BellIcon, PinIcon, ChevronIcon, SearchIcon, MicIcon, CameraIcon, MapIcon, HeartLogoIcon } from './PhoneMockup';
|
import { PhoneFrame, PhoneBottomNav, BellIcon, PinIcon, ChevronIcon, SearchIcon, MicIcon, CameraIcon, MapIcon, HeartLogoIcon } from './PhoneMockup';
|
||||||
|
import { gsap } from 'gsap';
|
||||||
|
import { ScrollTrigger } from 'gsap/ScrollTrigger';
|
||||||
|
|
||||||
|
if (typeof window !== 'undefined') gsap.registerPlugin(ScrollTrigger);
|
||||||
|
|
||||||
|
const useIsomorphicLayoutEffect = typeof window !== 'undefined' ? useLayoutEffect : useEffect;
|
||||||
|
|
||||||
const deals = [
|
const deals = [
|
||||||
{ store: 'Starbucks', category: 'Coffee & Drinks', offer: '2× LYTs', savings: '₹120 saved', color: '#00704A', dot: '#22c55e', distance: '0.3 km', rating: 4.8 },
|
{ store: 'Starbucks', category: 'Coffee & Drinks', offer: '2× LYTs', savings: '₹120 saved', color: '#00704A', dot: '#22c55e', distance: '0.3 km', rating: 4.8 },
|
||||||
@@ -14,9 +20,37 @@ const deals = [
|
|||||||
|
|
||||||
export default function DiscoverDealsSection() {
|
export default function DiscoverDealsSection() {
|
||||||
const [hovered, setHovered] = useState<number | null>(null);
|
const [hovered, setHovered] = useState<number | null>(null);
|
||||||
|
const panelRef = useRef<HTMLDivElement>(null);
|
||||||
|
const phoneRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
|
useIsomorphicLayoutEffect(() => {
|
||||||
|
if (typeof window === 'undefined') return;
|
||||||
|
const section = panelRef.current;
|
||||||
|
const phone = phoneRef.current;
|
||||||
|
if (!section || !phone) return;
|
||||||
|
|
||||||
|
const ctx = gsap.context(() => {
|
||||||
|
gsap.fromTo(phone,
|
||||||
|
{ y: 160, opacity: 0 },
|
||||||
|
{
|
||||||
|
y: 0,
|
||||||
|
opacity: 1,
|
||||||
|
ease: 'power2.out',
|
||||||
|
scrollTrigger: {
|
||||||
|
trigger: section,
|
||||||
|
start: 'top 92%',
|
||||||
|
end: 'top 25%',
|
||||||
|
scrub: 1.2,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}, section);
|
||||||
|
|
||||||
|
return () => ctx.revert();
|
||||||
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="fp-panel" style={{ background: '#08080f' }}>
|
<section ref={panelRef} className="fp-panel" style={{ background: '#08080f' }}>
|
||||||
|
|
||||||
{/* Background photo */}
|
{/* Background photo */}
|
||||||
<Image src="/images/stock/deals-retail.png" alt="" fill style={{ objectFit: 'cover', opacity: 0.25, zIndex: 0 }} />
|
<Image src="/images/stock/deals-retail.png" alt="" fill style={{ objectFit: 'cover', opacity: 0.25, zIndex: 0 }} />
|
||||||
@@ -63,7 +97,7 @@ export default function DiscoverDealsSection() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Phone mockup — white app screen, matches the in-app Discover experience */}
|
{/* Phone mockup — white app screen, matches the in-app Discover experience */}
|
||||||
<div className="fp-rise" style={{ transitionDelay: '0.1s', display: 'flex', justifyContent: 'center' }}>
|
<div ref={phoneRef} style={{ display: 'flex', justifyContent: 'center', opacity: 0, width: '100%' }}>
|
||||||
<PhoneFrame floatClassName="ddm-phone-shell">
|
<PhoneFrame floatClassName="ddm-phone-shell">
|
||||||
|
|
||||||
{/* Amber header */}
|
{/* Amber header */}
|
||||||
@@ -151,7 +185,7 @@ export default function DiscoverDealsSection() {
|
|||||||
<ChevronIcon />
|
<ChevronIcon />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<PhoneBottomNav active="heart" />
|
<PhoneBottomNav active="tag" />
|
||||||
</PhoneFrame>
|
</PhoneFrame>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import React, { useEffect, useRef, useState } from 'react';
|
import React, { useEffect, useLayoutEffect, useRef, useState } from 'react';
|
||||||
import Image from 'next/image';
|
import Image from 'next/image';
|
||||||
import { gsap } from 'gsap';
|
import { gsap } from 'gsap';
|
||||||
import { ScrollTrigger } from 'gsap/ScrollTrigger';
|
import { ScrollTrigger } from 'gsap/ScrollTrigger';
|
||||||
@@ -8,6 +8,8 @@ import { PhoneFrame, PhoneBottomNav, BellIcon, FlameIcon } from './PhoneMockup';
|
|||||||
|
|
||||||
if (typeof window !== 'undefined') gsap.registerPlugin(ScrollTrigger);
|
if (typeof window !== 'undefined') gsap.registerPlugin(ScrollTrigger);
|
||||||
|
|
||||||
|
const useIsomorphicLayoutEffect = typeof window !== 'undefined' ? useLayoutEffect : useEffect;
|
||||||
|
|
||||||
const feed = [
|
const feed = [
|
||||||
{ store: 'Daily Login', pts: +50, time: '2m ago', type: 'earn' },
|
{ store: 'Daily Login', pts: +50, time: '2m ago', type: 'earn' },
|
||||||
{ store: 'Walking 5,000 steps', pts: +80, time: '1h ago', type: 'earn' },
|
{ store: 'Walking 5,000 steps', pts: +80, time: '1h ago', type: 'earn' },
|
||||||
@@ -18,10 +20,38 @@ const feed = [
|
|||||||
export default function EarnRewardsSection() {
|
export default function EarnRewardsSection() {
|
||||||
const [pts, setPts] = useState(0);
|
const [pts, setPts] = useState(0);
|
||||||
const panelRef = useRef<HTMLDivElement>(null);
|
const panelRef = useRef<HTMLDivElement>(null);
|
||||||
|
const phoneRef = useRef<HTMLDivElement>(null);
|
||||||
const rafRef = useRef<number>(0);
|
const rafRef = useRef<number>(0);
|
||||||
const rowRefs = useRef<(HTMLDivElement | null)[]>([]);
|
const rowRefs = useRef<(HTMLDivElement | null)[]>([]);
|
||||||
const activeRowRef = useRef(0);
|
const activeRowRef = useRef(0);
|
||||||
|
|
||||||
|
// Phone mockup rises in from the bottom as the section scrolls into view
|
||||||
|
useIsomorphicLayoutEffect(() => {
|
||||||
|
if (typeof window === 'undefined') return;
|
||||||
|
const section = panelRef.current;
|
||||||
|
const phone = phoneRef.current;
|
||||||
|
if (!section || !phone) return;
|
||||||
|
|
||||||
|
const ctx = gsap.context(() => {
|
||||||
|
gsap.fromTo(phone,
|
||||||
|
{ y: 160, opacity: 0 },
|
||||||
|
{
|
||||||
|
y: 0,
|
||||||
|
opacity: 1,
|
||||||
|
ease: 'power2.out',
|
||||||
|
scrollTrigger: {
|
||||||
|
trigger: section,
|
||||||
|
start: 'top 92%',
|
||||||
|
end: 'top 25%',
|
||||||
|
scrub: 1.2,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}, section);
|
||||||
|
|
||||||
|
return () => ctx.revert();
|
||||||
|
}, []);
|
||||||
|
|
||||||
// Move the highlighted feed card as the section scrolls through the viewport
|
// Move the highlighted feed card as the section scrolls through the viewport
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (typeof window === 'undefined') return;
|
if (typeof window === 'undefined') return;
|
||||||
@@ -136,7 +166,7 @@ export default function EarnRewardsSection() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Right — phone mockup, matches the in-app Earn / Home experience */}
|
{/* Right — phone mockup, matches the in-app Earn / Home experience */}
|
||||||
<div className="fp-rise" style={{ transitionDelay: '0.15s', display: 'flex', justifyContent: 'center' }}>
|
<div ref={phoneRef} style={{ display: 'flex', justifyContent: 'center', opacity: 0, width: '100%' }}>
|
||||||
<PhoneFrame floatClassName="erm-phone-shell">
|
<PhoneFrame floatClassName="erm-phone-shell">
|
||||||
|
|
||||||
{/* Amber header */}
|
{/* Amber header */}
|
||||||
@@ -230,7 +260,7 @@ export default function EarnRewardsSection() {
|
|||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<PhoneBottomNav active="home" />
|
<PhoneBottomNav active="user" />
|
||||||
</PhoneFrame>
|
</PhoneFrame>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,6 +1,12 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import React from 'react';
|
import React, { useLayoutEffect, useEffect, useRef } from 'react';
|
||||||
|
import { gsap } from 'gsap';
|
||||||
|
import { ScrollTrigger } from 'gsap/ScrollTrigger';
|
||||||
|
|
||||||
|
if (typeof window !== 'undefined') gsap.registerPlugin(ScrollTrigger);
|
||||||
|
|
||||||
|
const useIsomorphicLayoutEffect = typeof window !== 'undefined' ? useLayoutEffect : useEffect;
|
||||||
|
|
||||||
const words = [
|
const words = [
|
||||||
{ text: 'Effortless.', size: 'clamp(58px, 9vw, 134px)', color: '#ffffff' },
|
{ text: 'Effortless.', size: 'clamp(58px, 9vw, 134px)', color: '#ffffff' },
|
||||||
@@ -14,8 +20,37 @@ const steps = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
export default function ExperienceSection() {
|
export default function ExperienceSection() {
|
||||||
|
const panelRef = useRef<HTMLDivElement>(null);
|
||||||
|
const cardRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
|
useIsomorphicLayoutEffect(() => {
|
||||||
|
if (typeof window === 'undefined') return;
|
||||||
|
const section = panelRef.current;
|
||||||
|
const card = cardRef.current;
|
||||||
|
if (!section || !card) return;
|
||||||
|
|
||||||
|
const ctx = gsap.context(() => {
|
||||||
|
gsap.fromTo(card,
|
||||||
|
{ x: 200, opacity: 0 },
|
||||||
|
{
|
||||||
|
x: 0,
|
||||||
|
opacity: 1,
|
||||||
|
ease: 'power2.out',
|
||||||
|
scrollTrigger: {
|
||||||
|
trigger: section,
|
||||||
|
start: 'top 92%',
|
||||||
|
end: 'top 25%',
|
||||||
|
scrub: 1.2,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}, section);
|
||||||
|
|
||||||
|
return () => ctx.revert();
|
||||||
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="fp-panel" style={{ background: '#07070d' }}>
|
<section ref={panelRef} className="fp-panel" style={{ background: '#07070d' }}>
|
||||||
<div className="fp-shell">
|
<div className="fp-shell">
|
||||||
|
|
||||||
<div style={{ marginBottom: 'clamp(36px, 5vh, 60px)' }}>
|
<div style={{ marginBottom: 'clamp(36px, 5vh, 60px)' }}>
|
||||||
@@ -36,35 +71,41 @@ export default function ExperienceSection() {
|
|||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Steps */}
|
<div ref={cardRef} style={{
|
||||||
<div>
|
background: '#f4be28',
|
||||||
<p className="fp-rise" style={{
|
padding: 'clamp(28px, 4.5vw, 44px)',
|
||||||
fontSize: 16, lineHeight: 1.85, color: 'rgba(255,255,255,0.45)', fontFamily: 'Sora, sans-serif', margin: '0 0 44px', maxWidth: 360,
|
borderRadius: '28px',
|
||||||
|
boxShadow: '0 24px 48px rgba(244, 190, 40, 0.12)',
|
||||||
|
width: '100%',
|
||||||
|
opacity: 0,
|
||||||
|
}}>
|
||||||
|
<p style={{
|
||||||
|
fontSize: 16, lineHeight: 1.85, color: 'rgba(7, 7, 13, 0.75)', fontFamily: 'Sora, sans-serif', margin: '0 0 36px', maxWidth: 360,
|
||||||
|
fontWeight: 500,
|
||||||
}}>
|
}}>
|
||||||
No plastic cards. No coupon hunting. No app open required at checkout. Loyaly works quietly in the background while you shop the way you always have.
|
No plastic cards. No coupon hunting. No app open required at checkout. Loyaly works quietly in the background while you shop the way you always have.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div style={{ display: 'flex', flexDirection: 'column' }}>
|
<div style={{ display: 'flex', flexDirection: 'column' }}>
|
||||||
{steps.map((s, i) => (
|
{steps.map((s, i) => (
|
||||||
<div key={i} className="fp-rise" style={{
|
<div key={i} style={{
|
||||||
display: 'flex', gap: 20, alignItems: 'center', padding: '20px 0',
|
display: 'flex', gap: 20, alignItems: 'center', padding: '20px 0',
|
||||||
borderBottom: i < steps.length - 1 ? '1px solid rgba(255,255,255,0.07)' : 'none',
|
borderBottom: i < steps.length - 1 ? '1px solid rgba(7, 7, 13, 0.1)' : 'none',
|
||||||
transitionDelay: `${0.2 + i * 0.1}s`,
|
|
||||||
}}>
|
}}>
|
||||||
<span style={{ fontSize: 12, fontWeight: 700, color: '#f4be28', fontFamily: 'Sora, sans-serif', letterSpacing: '0.06em', flexShrink: 0, width: 24 }}>{s.n}</span>
|
<span style={{ fontSize: 13, fontWeight: 800, color: '#07070d', fontFamily: 'Sora, sans-serif', letterSpacing: '0.06em', flexShrink: 0, width: 24 }}>{s.n}</span>
|
||||||
<span style={{ fontSize: 16, fontWeight: 600, color: 'rgba(255,255,255,0.75)', fontFamily: 'Sora, sans-serif', lineHeight: 1.4 }}>{s.label}</span>
|
<span style={{ fontSize: 16, fontWeight: 700, color: '#07070d', fontFamily: 'Sora, sans-serif', lineHeight: 1.4 }}>{s.label}</span>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="fp-rise" style={{ marginTop: 40, display: 'flex', alignItems: 'center', gap: 12, transitionDelay: '0.5s' }}>
|
<div style={{ marginTop: 36, display: 'flex', alignItems: 'center', gap: 12 }}>
|
||||||
<div style={{ display: 'flex' }}>
|
<div style={{ display: 'flex' }}>
|
||||||
{['#f4be28', '#4ade80', '#a855f7', '#3b82f6'].map((c, i) => (
|
{['#ff7b39', '#4ade80', '#a855f7', '#3b82f6'].map((c, i) => (
|
||||||
<div key={i} style={{ width: 30, height: 30, borderRadius: '50%', background: c, border: '2px solid #07070d', marginLeft: i > 0 ? -9 : 0 }} />
|
<div key={i} style={{ width: 30, height: 30, borderRadius: '50%', background: c, border: '2px solid #f4be28', marginLeft: i > 0 ? -9 : 0 }} />
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
<span style={{ fontSize: 13, color: 'rgba(255,255,255,0.4)', fontFamily: 'Sora, sans-serif' }}>
|
<span style={{ fontSize: 13, color: 'rgba(7, 7, 13, 0.65)', fontFamily: 'Sora, sans-serif', fontWeight: 500 }}>
|
||||||
Joined by <span style={{ color: '#fff', fontWeight: 700 }}>50,000+</span> shoppers
|
Joined by <span style={{ color: '#07070d', fontWeight: 800 }}>50,000+</span> shoppers
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -44,13 +44,9 @@ export default function FinalCTASection() {
|
|||||||
const tl = gsap.timeline({
|
const tl = gsap.timeline({
|
||||||
scrollTrigger: { trigger: sectionRef.current, start: 'top 80%', toggleActions: 'play none none reset' },
|
scrollTrigger: { trigger: sectionRef.current, start: 'top 80%', toggleActions: 'play none none reset' },
|
||||||
});
|
});
|
||||||
tl.fromTo('.fcta-badge',
|
tl.fromTo('.fcta-line-1',
|
||||||
{ opacity: 0, y: 20, scale: 0.9 },
|
|
||||||
{ opacity: 1, y: 0, scale: 1, duration: 0.6, ease: 'back.out(2)' }
|
|
||||||
)
|
|
||||||
.fromTo('.fcta-line-1',
|
|
||||||
{ opacity: 0, y: 50, filter: 'blur(8px)' },
|
{ opacity: 0, y: 50, filter: 'blur(8px)' },
|
||||||
{ opacity: 1, y: 0, filter: 'blur(0px)', duration: 0.8, ease: 'expo.out' }, '-=0.2'
|
{ opacity: 1, y: 0, filter: 'blur(0px)', duration: 0.8, ease: 'expo.out' }
|
||||||
)
|
)
|
||||||
.fromTo('.fcta-line-2',
|
.fromTo('.fcta-line-2',
|
||||||
{ opacity: 0, y: 50, filter: 'blur(8px)' },
|
{ opacity: 0, y: 50, filter: 'blur(8px)' },
|
||||||
@@ -60,9 +56,32 @@ export default function FinalCTASection() {
|
|||||||
{ opacity: 0, y: 24 },
|
{ opacity: 0, y: 24 },
|
||||||
{ opacity: 1, y: 0, duration: 0.65, ease: 'power3.out' }, '-=0.4'
|
{ opacity: 1, y: 0, duration: 0.65, ease: 'power3.out' }, '-=0.4'
|
||||||
)
|
)
|
||||||
|
.fromTo('.fcta-hanging-logo',
|
||||||
|
{ opacity: 0, y: -60, rotation: -16 },
|
||||||
|
{ opacity: 1, y: 0, rotation: 0, duration: 1.1, stagger: 0.16, ease: 'back.out(1.5)' },
|
||||||
|
'-=0.45'
|
||||||
|
)
|
||||||
|
.fromTo('.fcta-logo-link',
|
||||||
|
{ rotation: 10 },
|
||||||
|
{ rotation: 0, duration: 1.2, stagger: 0.16, ease: 'back.out(1.6)' },
|
||||||
|
'<'
|
||||||
|
)
|
||||||
|
.call(() => {
|
||||||
|
if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) return;
|
||||||
|
gsap.utils.toArray<HTMLElement>('.fcta-hanging-logo').forEach((el, i) => {
|
||||||
|
gsap.to(el, {
|
||||||
|
rotation: i % 2 === 0 ? 3.5 : -3.5,
|
||||||
|
duration: 2.4 + i * 0.3,
|
||||||
|
ease: 'sine.inOut',
|
||||||
|
yoyo: true,
|
||||||
|
repeat: -1,
|
||||||
|
transformOrigin: 'top center',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
})
|
||||||
.fromTo('.fcta-btns',
|
.fromTo('.fcta-btns',
|
||||||
{ opacity: 0, y: 20 },
|
{ opacity: 0, y: 20 },
|
||||||
{ opacity: 1, y: 0, duration: 0.55, ease: 'power3.out' }, '-=0.3'
|
{ opacity: 1, y: 0, duration: 0.55, ease: 'power3.out' }, '-=0.45'
|
||||||
)
|
)
|
||||||
.fromTo('.fcta-stat',
|
.fromTo('.fcta-stat',
|
||||||
{ opacity: 0, y: 28, scale: 0.88 },
|
{ opacity: 0, y: 28, scale: 0.88 },
|
||||||
@@ -94,30 +113,10 @@ export default function FinalCTASection() {
|
|||||||
{/* Amber glow orb top-center */}
|
{/* Amber glow orb top-center */}
|
||||||
<div style={{ position: 'absolute', top: '-20%', left: '50%', transform: 'translateX(-50%)', width: '70%', height: '60%', borderRadius: '50%', background: 'radial-gradient(ellipse, rgba(244,190,40,0.12) 0%, transparent 65%)', filter: 'blur(50px)', pointerEvents: 'none' }} />
|
<div style={{ position: 'absolute', top: '-20%', left: '50%', transform: 'translateX(-50%)', width: '70%', height: '60%', borderRadius: '50%', background: 'radial-gradient(ellipse, rgba(244,190,40,0.12) 0%, transparent 65%)', filter: 'blur(50px)', pointerEvents: 'none' }} />
|
||||||
|
|
||||||
{/* Ghost wordmark */}
|
|
||||||
<div style={{ position: 'absolute', bottom: -20, left: '50%', transform: 'translateX(-50%)', whiteSpace: 'nowrap', pointerEvents: 'none', zIndex: 0 }}>
|
|
||||||
<span style={{
|
|
||||||
fontSize: 'clamp(100px,20vw,280px)', fontWeight: 900,
|
|
||||||
fontFamily: 'Sora, sans-serif', letterSpacing: '-0.06em', lineHeight: 1,
|
|
||||||
color: 'transparent', WebkitTextStroke: '1px rgba(23,21,18,0.05)',
|
|
||||||
display: 'block',
|
|
||||||
}}>LOYALY</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Content */}
|
{/* Content */}
|
||||||
<div style={{ position: 'relative', zIndex: 10, maxWidth: 820, margin: '0 auto' }}>
|
<div style={{ position: 'relative', zIndex: 10, maxWidth: 820, margin: '0 auto' }}>
|
||||||
|
|
||||||
{/* Live badge */}
|
|
||||||
<div className="fcta-badge" style={{
|
|
||||||
display: 'inline-flex', alignItems: 'center', gap: 8, marginBottom: 36,
|
|
||||||
background: '#f0fdf4', border: '1.5px solid rgba(22,163,74,0.35)',
|
|
||||||
borderRadius: 100, padding: '9px 20px',
|
|
||||||
}}>
|
|
||||||
<span style={{ width: 7, height: 7, borderRadius: '50%', background: '#22c55e', display: 'block', animation: 'fctaPulse 1.6s ease-in-out infinite', boxShadow: '0 0 0 3px rgba(34,197,94,0.2)' }} />
|
|
||||||
<span style={{ fontSize: 12, fontWeight: 700, color: '#16a34a', fontFamily: 'Sora, sans-serif', letterSpacing: '0.1em', textTransform: 'uppercase' }}>
|
|
||||||
Now live in Coimbatore
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Headline */}
|
{/* Headline */}
|
||||||
<h2 style={{ margin: '0 0 28px', fontFamily: 'Sora, sans-serif', lineHeight: 0.92, letterSpacing: '-0.055em' }}>
|
<h2 style={{ margin: '0 0 28px', fontFamily: 'Sora, sans-serif', lineHeight: 0.92, letterSpacing: '-0.055em' }}>
|
||||||
@@ -144,13 +143,130 @@ export default function FinalCTASection() {
|
|||||||
|
|
||||||
{/* Subtitle */}
|
{/* Subtitle */}
|
||||||
<p className="fcta-sub" style={{
|
<p className="fcta-sub" style={{
|
||||||
|
position: 'relative',
|
||||||
|
zIndex: 5,
|
||||||
fontSize: 'clamp(1rem,1.2vw,1.15rem)', lineHeight: 1.75,
|
fontSize: 'clamp(1rem,1.2vw,1.15rem)', lineHeight: 1.75,
|
||||||
color: 'rgba(23,21,18,0.5)', fontFamily: 'Sora, sans-serif',
|
color: '#171512', fontFamily: 'Sora, sans-serif',
|
||||||
maxWidth: 440, margin: '0 auto 52px',
|
maxWidth: 520, width: '100%', margin: '0 auto 0px',
|
||||||
|
background: '#f4be28',
|
||||||
|
border: '1.5px solid #f4be28',
|
||||||
|
borderRadius: 100,
|
||||||
|
padding: '14px 28px',
|
||||||
|
display: 'inline-block',
|
||||||
|
boxSizing: 'border-box',
|
||||||
}}>
|
}}>
|
||||||
Download Loyaly and start earning on your very next purchase. Free. Instant. Yours.
|
Download Loyaly and start earning on your very next purchase. Free. Instant. Yours.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
{/* Hanging Logos */}
|
||||||
|
<div className="fcta-hanging-logos-wrapper" style={{
|
||||||
|
position: 'relative',
|
||||||
|
height: 250,
|
||||||
|
margin: '-34px auto 40px',
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'flex-start',
|
||||||
|
gap: 140,
|
||||||
|
width: 'fit-content',
|
||||||
|
zIndex: 1,
|
||||||
|
}}>
|
||||||
|
{/* Play Store Logo (hanging) */}
|
||||||
|
<div className="fcta-hanging-logo play-store" style={{
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
alignItems: 'center',
|
||||||
|
transformOrigin: 'top center',
|
||||||
|
position: 'relative',
|
||||||
|
}}>
|
||||||
|
{/* Keyring loop */}
|
||||||
|
<div style={{
|
||||||
|
width: 16, height: 16, borderRadius: '50%',
|
||||||
|
border: '2px solid #f4be28', marginTop: 14, marginBottom: -3,
|
||||||
|
boxShadow: '0 0 10px rgba(244,190,40,0.35)',
|
||||||
|
flexShrink: 0,
|
||||||
|
}} />
|
||||||
|
{/* String */}
|
||||||
|
<div style={{
|
||||||
|
width: 2,
|
||||||
|
height: 62,
|
||||||
|
background: '#f4be28',
|
||||||
|
opacity: 0.7,
|
||||||
|
boxShadow: '0 0 6px rgba(244,190,40,0.25)',
|
||||||
|
}} />
|
||||||
|
{/* Logo Circle */}
|
||||||
|
<Link href="/contacts" className="fcta-logo-link" style={{
|
||||||
|
width: 116,
|
||||||
|
height: 116,
|
||||||
|
borderRadius: '50%',
|
||||||
|
overflow: 'hidden',
|
||||||
|
background: '#000000',
|
||||||
|
boxShadow: '0 18px 40px rgba(0,0,0,0.24), 0 0 0 1px rgba(244,190,40,0.15)',
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
border: '5px solid #f4be28',
|
||||||
|
cursor: 'pointer',
|
||||||
|
textDecoration: 'none',
|
||||||
|
transformOrigin: 'top center',
|
||||||
|
marginTop: -1,
|
||||||
|
}}>
|
||||||
|
<img src="/logo_icons/images.png" alt="Google Play" style={{ width: '100%', height: '100%', objectFit: 'cover' }} />
|
||||||
|
</Link>
|
||||||
|
{/* Tooltip */}
|
||||||
|
<div className="fcta-tooltip">
|
||||||
|
Download In Playstore
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Apple Logo (hanging) */}
|
||||||
|
<div className="fcta-hanging-logo apple-store" style={{
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
alignItems: 'center',
|
||||||
|
transformOrigin: 'top center',
|
||||||
|
position: 'relative',
|
||||||
|
}}>
|
||||||
|
{/* Keyring loop */}
|
||||||
|
<div style={{
|
||||||
|
width: 16, height: 16, borderRadius: '50%',
|
||||||
|
border: '2px solid #f4be28', marginTop: 14, marginBottom: -3,
|
||||||
|
boxShadow: '0 0 10px rgba(244,190,40,0.35)',
|
||||||
|
flexShrink: 0,
|
||||||
|
}} />
|
||||||
|
{/* String */}
|
||||||
|
<div style={{
|
||||||
|
width: 2,
|
||||||
|
height: 92,
|
||||||
|
background: '#f4be28',
|
||||||
|
opacity: 0.7,
|
||||||
|
boxShadow: '0 0 6px rgba(244,190,40,0.25)',
|
||||||
|
}} />
|
||||||
|
{/* Logo Circle */}
|
||||||
|
<Link href="/contacts" className="fcta-logo-link" style={{
|
||||||
|
width: 116,
|
||||||
|
height: 116,
|
||||||
|
borderRadius: '50%',
|
||||||
|
overflow: 'hidden',
|
||||||
|
background: '#000000',
|
||||||
|
boxShadow: '0 18px 40px rgba(0,0,0,0.24), 0 0 0 1px rgba(244,190,40,0.15)',
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
border: '5px solid #f4be28',
|
||||||
|
cursor: 'pointer',
|
||||||
|
textDecoration: 'none',
|
||||||
|
transformOrigin: 'top center',
|
||||||
|
marginTop: -1,
|
||||||
|
}}>
|
||||||
|
<img src="/logo_icons/apple.jpg" alt="App Store" style={{ width: '100%', height: '100%', objectFit: 'cover' }} />
|
||||||
|
</Link>
|
||||||
|
{/* Tooltip */}
|
||||||
|
<div className="fcta-tooltip">
|
||||||
|
Download in App store
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* CTAs */}
|
{/* CTAs */}
|
||||||
<div className="fcta-btns" style={{ display: 'flex', gap: 14, justifyContent: 'center', flexWrap: 'wrap', marginBottom: 64 }}>
|
<div className="fcta-btns" style={{ display: 'flex', gap: 14, justifyContent: 'center', flexWrap: 'wrap', marginBottom: 64 }}>
|
||||||
<Link
|
<Link
|
||||||
@@ -210,6 +326,58 @@ export default function FinalCTASection() {
|
|||||||
<style>{`
|
<style>{`
|
||||||
@keyframes fctaPulse { 0%,100%{box-shadow:0 0 0 0 rgba(34,197,94,0.5)} 50%{box-shadow:0 0 0 6px rgba(34,197,94,0)} }
|
@keyframes fctaPulse { 0%,100%{box-shadow:0 0 0 0 rgba(34,197,94,0.5)} 50%{box-shadow:0 0 0 6px rgba(34,197,94,0)} }
|
||||||
@keyframes fctaShimmer { 0%{background-position:200% center} 100%{background-position:-200% center} }
|
@keyframes fctaShimmer { 0%{background-position:200% center} 100%{background-position:-200% center} }
|
||||||
|
.fcta-hanging-logo a {
|
||||||
|
transition: transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
|
||||||
|
}
|
||||||
|
.fcta-hanging-logo a:hover {
|
||||||
|
transform: scale(1.08);
|
||||||
|
}
|
||||||
|
.fcta-tooltip {
|
||||||
|
position: absolute;
|
||||||
|
top: calc(100% + 4px);
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%) translateY(8px);
|
||||||
|
background: #171512;
|
||||||
|
color: #ffffff;
|
||||||
|
padding: 6px 14px;
|
||||||
|
border-radius: 6px;
|
||||||
|
font-size: 11px;
|
||||||
|
font-weight: 700;
|
||||||
|
font-family: 'Sora', sans-serif;
|
||||||
|
white-space: nowrap;
|
||||||
|
opacity: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
transition: opacity 0.25s ease, transform 0.25s cubic-bezier(0.25, 1, 0.22, 1);
|
||||||
|
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
|
||||||
|
z-index: 10;
|
||||||
|
}
|
||||||
|
.fcta-hanging-logo:hover .fcta-tooltip {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateX(-50%) translateY(0);
|
||||||
|
}
|
||||||
|
.fcta-tooltip::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: -4px;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%) rotate(45deg);
|
||||||
|
width: 8px;
|
||||||
|
height: 8px;
|
||||||
|
background: #171512;
|
||||||
|
}
|
||||||
|
@media (max-width: 1023px) {
|
||||||
|
.fcta-hanging-logos-wrapper {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
.fcta-sub {
|
||||||
|
margin-bottom: 40px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media (min-width: 1024px) {
|
||||||
|
.fcta-btns {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
`}</style>
|
`}</style>
|
||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ export default function HeroSection() {
|
|||||||
<div style={{ maxWidth: 720 }}>
|
<div style={{ maxWidth: 720 }}>
|
||||||
<h1 className="fp-headline" style={{
|
<h1 className="fp-headline" style={{
|
||||||
fontSize: 'clamp(40px, 5.4vw, 82px)', fontWeight: 800, lineHeight: 1.02,
|
fontSize: 'clamp(40px, 5.4vw, 82px)', fontWeight: 800, lineHeight: 1.02,
|
||||||
letterSpacing: '-0.045em', color: '#fff', margin: '0 0 28px', fontFamily: 'Sora, sans-serif',
|
letterSpacing: '-0.045em', color: '#fff', margin: '50px 0 28px', fontFamily: 'Sora, sans-serif',
|
||||||
}}>
|
}}>
|
||||||
<span className="fp-mask"><span>Shop Smart.</span></span>
|
<span className="fp-mask"><span>Shop Smart.</span></span>
|
||||||
<span className="fp-mask"><span className="fp-shimmer">Live Rewarded.</span></span>
|
<span className="fp-mask"><span className="fp-shimmer">Live Rewarded.</span></span>
|
||||||
@@ -71,7 +71,7 @@ export default function HeroSection() {
|
|||||||
fontSize: 'clamp(16px, 1.4vw, 19px)', lineHeight: 1.7, fontWeight: 400,
|
fontSize: 'clamp(16px, 1.4vw, 19px)', lineHeight: 1.7, fontWeight: 400,
|
||||||
color: 'rgba(255,255,255,0.58)', maxWidth: 640, margin: '0 auto 40px', fontFamily: 'Sora, sans-serif',
|
color: 'rgba(255,255,255,0.58)', maxWidth: 640, margin: '0 auto 40px', fontFamily: 'Sora, sans-serif',
|
||||||
}}>
|
}}>
|
||||||
Meet <strong>LYT (Loyaly Token)</strong>: the single currency behind every reward in the app. Earn them through daily tasks, walking challenges, and games, then spend them instantly at partner stores near you with zero expiry.
|
Meet <strong>LYTs (Loyaly Tokens)</strong>: the single currency behind every reward. Earn them through daily challenges and games, then spend instantly at partner stores near you with zero expiry.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div className="fp-content fp-cta" style={{ display: 'flex', gap: 16, flexWrap: 'wrap', alignItems: 'center', justifyContent: 'center' }}>
|
<div className="fp-content fp-cta" style={{ display: 'flex', gap: 16, flexWrap: 'wrap', alignItems: 'center', justifyContent: 'center' }}>
|
||||||
|
|||||||
@@ -56,9 +56,20 @@ export function MapIcon() {
|
|||||||
</svg>
|
</svg>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
export function HeartLogoIcon({ size = 16 }: { size?: number }) {
|
export function HeartLogoIcon({ size = 16, active = false }: { size?: number; active?: boolean }) {
|
||||||
return (
|
return (
|
||||||
<Image src="/images/loyalyai-logo.png" alt="" width={32} height={32} style={{ width: size, height: size, objectFit: 'contain' }} />
|
<Image
|
||||||
|
src="/images/loyalyai-logo.png"
|
||||||
|
alt=""
|
||||||
|
width={32}
|
||||||
|
height={32}
|
||||||
|
style={{
|
||||||
|
width: size,
|
||||||
|
height: size,
|
||||||
|
objectFit: 'contain',
|
||||||
|
filter: active ? 'brightness(0)' : 'none',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
export function UpArrowIcon({ color = '#16a34a' }: { color?: string }) {
|
export function UpArrowIcon({ color = '#16a34a' }: { color?: string }) {
|
||||||
@@ -85,12 +96,12 @@ export function FlameIcon({ color = '#f4be28' }: { color?: string }) {
|
|||||||
|
|
||||||
/* ── Bottom nav — pass the active tab key to highlight it ── */
|
/* ── Bottom nav — pass the active tab key to highlight it ── */
|
||||||
export function PhoneBottomNav({ active = 'home' }: { active?: string }) {
|
export function PhoneBottomNav({ active = 'home' }: { active?: string }) {
|
||||||
const items: { key: string; icon: React.ReactNode }[] = [
|
const items: { key: string; icon: (isActive: boolean) => React.ReactNode }[] = [
|
||||||
{ key: 'home', icon: <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round"><path d="M3 10.5L12 3l9 7.5" /><path d="M5 9.5V21h14V9.5" /></svg> },
|
{ key: 'home', icon: () => <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round"><path d="M3 10.5L12 3l9 7.5" /><path d="M5 9.5V21h14V9.5" /></svg> },
|
||||||
{ key: 'tag', icon: <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round"><path d="M20.59 13.41 12 22l-9-9V4h9z" /><circle cx="7.5" cy="8.5" r="1.2" /></svg> },
|
{ key: 'tag', icon: () => <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round"><path d="M20.59 13.41 12 22l-9-9V4h9z" /><circle cx="7.5" cy="8.5" r="1.2" /></svg> },
|
||||||
{ key: 'heart', icon: <HeartLogoIcon size={18} /> },
|
{ key: 'heart', icon: (isActive) => <HeartLogoIcon size={18} active={isActive} /> },
|
||||||
{ key: 'shop', icon: <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round"><path d="M3 9l1.5-5h15L21 9" /><path d="M3 9h18v11H3z" /><path d="M9 20v-6h6v6" /></svg> },
|
{ key: 'shop', icon: () => <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round"><path d="M3 9l1.5-5h15L21 9" /><path d="M3 9h18v11H3z" /><path d="M9 20v-6h6v6" /></svg> },
|
||||||
{ key: 'user', icon: <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="8" r="4" /><path d="M4 21c1.5-4 5-6 8-6s6.5 2 8 6" /></svg> },
|
{ key: 'user', icon: () => <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="8" r="4" /><path d="M4 21c1.5-4 5-6 8-6s6.5 2 8 6" /></svg> },
|
||||||
];
|
];
|
||||||
return (
|
return (
|
||||||
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-around', padding: '10px 8px', borderTop: '1px solid #f0f0f0' }}>
|
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-around', padding: '10px 8px', borderTop: '1px solid #f0f0f0' }}>
|
||||||
@@ -99,11 +110,11 @@ export function PhoneBottomNav({ active = 'home' }: { active?: string }) {
|
|||||||
return (
|
return (
|
||||||
<div key={n.key} style={{
|
<div key={n.key} style={{
|
||||||
width: 34, height: 34, borderRadius: 12, display: 'flex', alignItems: 'center', justifyContent: 'center',
|
width: 34, height: 34, borderRadius: 12, display: 'flex', alignItems: 'center', justifyContent: 'center',
|
||||||
color: isActive && n.key !== 'heart' ? '#171512' : '#9ca3af',
|
color: isActive ? '#171512' : '#9ca3af',
|
||||||
background: isActive ? '#fff7e0' : 'transparent',
|
background: isActive ? '#f4be28' : 'transparent',
|
||||||
border: isActive ? '1.5px solid #f4be28' : 'none',
|
border: isActive ? '1.5px solid #f4be28' : 'none',
|
||||||
}}>
|
}}>
|
||||||
{n.icon}
|
{n.icon(isActive)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
|||||||
68
src/components/for-people/PillarsSection.tsx
Normal file
68
src/components/for-people/PillarsSection.tsx
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
const PILLARS = [
|
||||||
|
{
|
||||||
|
n: '01',
|
||||||
|
title: 'Shop Smarter',
|
||||||
|
desc: 'Unlock top deals, discounts, and exclusive offers at stores near you, just by walking in.',
|
||||||
|
color: '#f4be28',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
n: '02',
|
||||||
|
title: 'Earn Rewards',
|
||||||
|
desc: 'Every rupee spent earns LYT points. Zero expiry. Redeem anytime, at any partner store.',
|
||||||
|
color: '#16a34a',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
n: '03',
|
||||||
|
title: 'Make It a Pleasure',
|
||||||
|
desc: 'Shopping should feel good. Loyaly makes every trip more rewarding, more fun, and more personal.',
|
||||||
|
color: '#a78bfa',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export default function PillarsSection() {
|
||||||
|
return (
|
||||||
|
<section className="fp-panel fp-light" style={{ background: '#ffffff' }}>
|
||||||
|
<div className="fp-shell">
|
||||||
|
<div style={{ marginBottom: 'clamp(40px, 6vh, 64px)' }}>
|
||||||
|
<span className="fp-kicker fp-rise">Save More<span className="fp-kicker-num">02</span></span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h2 className="fp-rise" style={{
|
||||||
|
fontSize: 'clamp(30px, 3.6vw, 50px)', fontWeight: 800, lineHeight: 1.08,
|
||||||
|
letterSpacing: '-0.04em', color: '#171512', margin: '0 0 20px', fontFamily: 'Sora, sans-serif', maxWidth: 640,
|
||||||
|
}}>
|
||||||
|
Save more on every in-store visit.
|
||||||
|
</h2>
|
||||||
|
<p className="fp-rise" style={{
|
||||||
|
fontSize: 16, lineHeight: 1.8, color: '#4f463a', margin: '0 0 56px',
|
||||||
|
fontFamily: 'Sora, sans-serif', maxWidth: 560,
|
||||||
|
}}>
|
||||||
|
Earn Loyaly rewards on everyday shopping, from groceries to fashion to home essentials. Every purchase brings you closer to your next reward.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div className="fp-pillar-cols" style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 24 }}>
|
||||||
|
{PILLARS.map((p, i) => (
|
||||||
|
<div key={p.n} className="fp-rise" style={{
|
||||||
|
transitionDelay: `${0.1 + i * 0.1}s`,
|
||||||
|
padding: 32, borderRadius: 20, background: '#f9f7f2', border: `1px solid ${p.color}30`,
|
||||||
|
}}>
|
||||||
|
<div style={{ width: 10, height: 10, borderRadius: '50%', background: p.color, marginBottom: 20 }} />
|
||||||
|
<h3 style={{ fontSize: 21, fontWeight: 800, color: '#171512', fontFamily: 'Sora, sans-serif', margin: '0 0 12px', letterSpacing: '-0.02em' }}>{p.title}</h3>
|
||||||
|
<p style={{ fontSize: 14.5, lineHeight: 1.7, color: '#4f463a', fontFamily: 'Sora, sans-serif', margin: 0 }}>{p.desc}</p>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>{`
|
||||||
|
@media (max-width: 900px) {
|
||||||
|
.fp-pillar-cols { grid-template-columns: 1fr !important; }
|
||||||
|
}
|
||||||
|
`}</style>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -153,6 +153,31 @@ export default function ProblemSection({ isLoaded = true }: ProblemSectionProps)
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* India retail market stats strip */}
|
||||||
|
<div className="relative z-10 mx-auto problem-india-stats" style={{
|
||||||
|
maxWidth: 1200,
|
||||||
|
marginBottom: 'clamp(32px, 4vw, 48px)',
|
||||||
|
display: 'grid',
|
||||||
|
gridTemplateColumns: 'repeat(5, 1fr)',
|
||||||
|
gap: 'clamp(8px, 1.2vw, 14px)',
|
||||||
|
}}>
|
||||||
|
{[
|
||||||
|
{ val: '$2 Tn', label: 'India retail market by 2032, 25% CAGR' },
|
||||||
|
{ val: '5th', label: 'Largest retail destination globally' },
|
||||||
|
{ val: '10%', label: "Of India's GDP from retail" },
|
||||||
|
{ val: '12%', label: 'Of retail is organised, the rest is offline' },
|
||||||
|
{ val: '500M', label: 'Indians shopping online by 2030, up from 220M' },
|
||||||
|
].map((s, i) => (
|
||||||
|
<div key={i} style={{
|
||||||
|
padding: 'clamp(14px, 1.8vw, 20px)', borderRadius: 16,
|
||||||
|
background: '#f9f7f2', border: '1px solid rgba(23,21,18,0.08)',
|
||||||
|
}}>
|
||||||
|
<div style={{ fontSize: 'clamp(1.3rem, 2vw, 1.7rem)', fontWeight: 900, color: '#171512', fontFamily: 'Sora, sans-serif', letterSpacing: '-0.03em', lineHeight: 1 }}>{s.val}</div>
|
||||||
|
<div style={{ marginTop: 6, fontSize: '0.72rem', color: '#4f463a', fontFamily: 'Sora, sans-serif', lineHeight: 1.4 }}>{s.label}</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* Grid wrapper */}
|
{/* Grid wrapper */}
|
||||||
<div className="relative z-10 mx-auto" style={{ maxWidth: 1200 }}>
|
<div className="relative z-10 mx-auto" style={{ maxWidth: 1200 }}>
|
||||||
{/* Row 1: Red Stat Cards */}
|
{/* Row 1: Red Stat Cards */}
|
||||||
@@ -429,6 +454,7 @@ export default function ProblemSection({ isLoaded = true }: ProblemSectionProps)
|
|||||||
#problem .problem-stats-row { grid-template-columns: 1fr !important; }
|
#problem .problem-stats-row { grid-template-columns: 1fr !important; }
|
||||||
#problem .dark-bento-grid { grid-template-columns: 1fr !important; }
|
#problem .dark-bento-grid { grid-template-columns: 1fr !important; }
|
||||||
#problem .dark-bento-card-4 { grid-column: span 1; }
|
#problem .dark-bento-card-4 { grid-column: span 1; }
|
||||||
|
#problem .problem-india-stats { grid-template-columns: repeat(2, 1fr) !important; }
|
||||||
}
|
}
|
||||||
`}</style>
|
`}</style>
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
Reference in New Issue
Block a user