updated sections design and content

This commit is contained in:
R-Bharathraj
2026-07-11 12:38:33 +05:30
parent cba47aea2b
commit 03ed08d7dd
24 changed files with 907 additions and 405 deletions

View File

@@ -87,27 +87,65 @@ export default function AboutUsPage() {
</section> </section>
{/* ── MISSION & VISION ── */} {/* ── MISSION & VISION ── */}
<section style={{ padding: '0 8% 20px', background: '#ffffff' }}> <section style={{ position: 'relative', overflow: 'hidden', padding: 'clamp(60px, 9vh, 104px) 8%', background: '#07070d', margin: '0 20px 20px', borderRadius: 28 }}>
<div className="au-mv-grid" style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 20, alignItems: 'stretch' }}> {/* Ambient top glow */}
<div aria-hidden style={{ position: 'absolute', top: '-24%', left: '50%', transform: 'translateX(-50%)', width: 680, height: 420, background: 'radial-gradient(ellipse, rgba(244,190,40,0.12) 0%, transparent 70%)', pointerEvents: 'none' }} />
{/* Section header */}
<div style={{ position: 'relative', zIndex: 1, textAlign: 'center', maxWidth: 640, margin: '0 auto clamp(44px, 6vh, 68px)' }}>
<h2 style={{ margin: 0, fontSize: 'clamp(30px, 4.5vw, 60px)', fontWeight: 800, letterSpacing: '-0.04em', lineHeight: 1, color: '#fff', fontFamily: 'Sora, sans-serif' }}>
What drives <span style={{ color: '#f4be28' }}>everything</span> we do.
</h2>
</div>
<div className="au-mv-grid" style={{ position: 'relative', zIndex: 1, display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 24, alignItems: 'stretch' }}>
{[ {[
{ {
label: 'Mission', bg: '#07070d', textColor: '#fff', accent: '#f4be28', label: 'Mission', emoji: '🎯', bg: 'linear-gradient(160deg, #ffffff 0%, #fdf4e2 100%)', textColor: '#171512',
border: 'rgba(244,190,40,0.45)',
pillBg: 'rgba(244,190,40,0.14)', pillText: '#8a5a14', pillBorder: 'rgba(244,190,40,0.5)',
orb1: 'rgba(244,190,40,0.20)', orb2: 'rgba(255,152,0,0.14)',
gfx: 'rgba(244,190,40,0.38)',
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.', 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', emoji: '🔮', bg: 'linear-gradient(160deg, #fff7e2 0%, #ffe6a8 100%)', textColor: '#171512',
body: 'Empowering every neighbourhood, making exceptional in-store experiences and real rewards accessible to all.', border: 'rgba(244,190,40,0.55)',
pillBg: '#f4be28', pillText: '#171512', pillBorder: 'rgba(201,150,15,0.6)',
orb1: 'rgba(255,255,255,0.7)', orb2: 'rgba(244,190,40,0.3)',
gfx: 'rgba(201,150,15,0.32)',
body: 'Empowering every neighbourhood, making exceptional in-store experiences and real Lyts 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 className="au-mv-card" style={{
padding: '72px 56px', borderRadius: 24, background: mv.bg, position: 'relative',
padding: 'clamp(40px, 4vw, 60px)', borderRadius: 28, background: mv.bg,
border: `1px solid ${mv.border}`,
boxShadow: '0 24px 60px -30px rgba(23,21,18,0.22)',
height: '100%', minHeight: 360, height: '100%', minHeight: 360,
display: 'flex', flexDirection: 'column', justifyContent: 'flex-start', gap: 28, display: 'flex', flexDirection: 'column', justifyContent: 'flex-start', gap: 24,
margin: '0 20px 20px', boxSizing: 'border-box', margin: 0, boxSizing: 'border-box',
}}> }}>
<div style={{ fontSize: 11, fontWeight: 700, letterSpacing: '0.2em', textTransform: 'uppercase', color: mv.accent, fontFamily: 'Sora, sans-serif' }}>{mv.label}</div> {/* Animated background orbs (clipped to the card) */}
<p style={{ fontSize: 'clamp(22px, 2.5vw, 36px)', fontWeight: 800, lineHeight: 1.25, color: mv.textColor, fontFamily: 'Sora, sans-serif', margin: 0, letterSpacing: '-0.02em' }}> <div className="au-mv-bg" aria-hidden style={{ position: 'absolute', inset: 0, borderRadius: 28, overflow: 'hidden', pointerEvents: 'none', zIndex: 0 }}>
<span className="au-mv-orb au-mv-orb-1" style={{ position: 'absolute', top: '-18%', left: '-12%', width: 280, height: 280, borderRadius: '50%', background: `radial-gradient(circle, ${mv.orb1} 0%, transparent 70%)` }} />
<span className="au-mv-orb au-mv-orb-2" style={{ position: 'absolute', bottom: '-20%', right: '-10%', width: 240, height: 240, borderRadius: '50%', background: `radial-gradient(circle, ${mv.orb2} 0%, transparent 70%)` }} />
</div>
{/* Pop-out corner sticker */}
<span aria-hidden style={{ position: 'absolute', top: -22, right: -14, fontSize: 46, transform: 'rotate(12deg)', zIndex: 2 }}>{mv.emoji}</span>
{/* Tilted sticker-pill label */}
<span style={{
position: 'relative', zIndex: 1,
display: 'inline-flex', alignItems: 'center', gap: 7, alignSelf: 'flex-start',
transform: 'rotate(-2deg)', padding: '8px 16px', borderRadius: 100,
background: mv.pillBg, color: mv.pillText, border: `1.5px solid ${mv.pillBorder}`,
fontSize: 12, fontWeight: 700, letterSpacing: '0.12em', textTransform: 'uppercase', fontFamily: 'Sora, sans-serif',
}}>{mv.emoji} {mv.label}</span>
<p style={{ position: 'relative', zIndex: 1, fontSize: 'clamp(21px, 2.4vw, 34px)', fontWeight: 500, lineHeight: 1.3, color: mv.textColor, fontFamily: 'Sora, sans-serif', margin: 0, letterSpacing: '-0.015em' }}>
{mv.body} {mv.body}
</p> </p>
</div> </div>
@@ -178,6 +216,46 @@ export default function AboutUsPage() {
</section> </section>
<style>{` <style>{`
/* Animated gradient glow ring behind each card */
.au-mv-card::before {
content: '';
position: absolute;
inset: -2px;
border-radius: inherit;
background: linear-gradient(130deg, #f4be28, #ff9f1c, #f4be28);
background-size: 220% 220%;
z-index: -1;
filter: blur(11px);
opacity: 0.45;
animation: auMvGlow 7s ease-in-out infinite;
}
@keyframes auMvGlow {
0%, 100% { background-position: 0% 50%; opacity: 0.35; }
50% { background-position: 100% 50%; opacity: 0.6; }
}
.au-mv-orb { filter: blur(26px); will-change: transform; }
.au-mv-orb-1 { animation: auMvDrift1 10s ease-in-out infinite; }
.au-mv-orb-2 { animation: auMvDrift2 13s ease-in-out infinite; }
@keyframes auMvDrift1 { 0%, 100% { transform: translate(0, 0) scale(1); } 50% { transform: translate(44px, -34px) scale(1.2); } }
@keyframes auMvDrift2 { 0%, 100% { transform: translate(0, 0) scale(1); } 50% { transform: translate(-38px, 30px) scale(1.16); } }
.au-mv-gfx { animation: auMvGfxFloat 16s ease-in-out infinite; }
@keyframes auMvGfxFloat {
0%, 100% { transform: translate(0, 0) scale(0.82); }
25% { transform: translate(-34px, -22px) scale(1); }
50% { transform: translate(-14px, -48px) scale(1.22); }
75% { transform: translate(-42px, -14px) scale(1); }
}
.au-mv-ringspin { transform-box: fill-box; transform-origin: center; animation: auMvSpin 12s linear infinite; }
@keyframes auMvSpin { to { transform: rotate(360deg); } }
.au-mv-ringpulse { transform-box: fill-box; transform-origin: center; animation: auMvRingPulse 4.5s ease-in-out infinite; }
@keyframes auMvRingPulse { 0%, 100% { transform: scale(1); opacity: 1; } 50% { transform: scale(1.1); opacity: 0.65; } }
.au-mv-dot { transform-box: fill-box; transform-origin: center; animation: auMvDotPulse 1.8s ease-in-out infinite; }
.au-mv-dot-2 { animation-delay: 0.6s; }
.au-mv-dot-3 { animation-delay: 1.2s; }
@keyframes auMvDotPulse { 0%, 100% { transform: scale(1); opacity: 0.75; } 50% { transform: scale(1.9); opacity: 0.2; } }
@media (prefers-reduced-motion: reduce) {
.au-mv-orb-1, .au-mv-orb-2, .au-mv-card::before, .au-mv-gfx, .au-mv-ringspin, .au-mv-ringpulse, .au-mv-dot { animation: none !important; }
}
@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-market-grid { grid-template-columns: 1fr !important; gap: 36px !important; }

View File

@@ -264,3 +264,24 @@ body.is-home-page.scroll-up .sticky-active {
/* Hero carousel layout lives in HeroCarousel.tsx as a scoped <style> tag, /* Hero carousel layout lives in HeroCarousel.tsx as a scoped <style> tag,
matching every other home-page section — keeps it working even if this matching every other home-page section — keeps it working even if this
global stylesheet has a load/HMR hiccup. */ global stylesheet has a load/HMR hiccup. */
/* Problem section — the wide "No Real-Time Signal" card (dark-bento-card-4).
Its mobile art/copy sizing lives here (not in the component's scoped <style>)
so it reloads reliably, and the extra .dark-bento-card-4 qualifier gives it
higher specificity so it wins over the generic .problem-card-art rules. */
@media (max-width: 640px) {
#problem .dark-bento-card-4 .problem-card-text {
width: 60% !important;
}
#problem .dark-bento-card-4 .problem-card-art--wide {
width: 46% !important;
height: 52% !important;
right: 0 !important;
bottom: 0 !important;
}
#problem .dark-bento-card-4 .problem-card-art--wide img {
transform: scale(1.25) !important;
object-fit: contain !important;
object-position: bottom right !important;
}
}

View File

@@ -35,7 +35,7 @@ const PRODUCTS = [
'Entry-to-purchase funnel tracking that flags where shoppers drop off', 'Entry-to-purchase funnel tracking that flags where shoppers drop off',
], ],
metric: { val: '3.2×', lbl: 'conversion uplift' }, metric: { val: '3.2×', lbl: 'conversion uplift' },
tags: ['Footfall Tracking', 'Heatmaps', 'Behavior Analysis'], tags: ['Footfall Tracking', 'Behavior Analysis'],
}, },
{ {
n: '02', title: 'SpendSense', subtitle: 'Customer Spending Intelligence', color: '#10B981', n: '02', title: 'SpendSense', subtitle: 'Customer Spending Intelligence', color: '#10B981',
@@ -63,12 +63,12 @@ const PRODUCTS = [
n: '04', title: 'Identiq', subtitle: 'Consumer Loyalty Platform', color: '#f4be28', n: '04', title: 'Identiq', subtitle: 'Consumer Loyalty Platform', color: '#f4be28',
desc: 'The consumer-facing app that closes the loop. Identiq turns daily logins, walking challenges, and quick mini-games into LYTs, Loyalys reward tokens, redeemable instantly at any partner store, so every idle moment on a phone becomes a reason to walk into a real one.', desc: 'The consumer-facing app that closes the loop. Identiq turns daily logins, walking challenges, and quick mini-games into LYTs, Loyalys reward tokens, redeemable instantly at any partner store, so every idle moment on a phone becomes a reason to walk into a real one.',
capabilities: [ capabilities: [
'Daily login and step-challenge rewards that build a lasting habit loop', 'Daily login and step-challenge Lyts that build a lasting habit loop',
'Game based offers like Spin Wheel, Scratch Card, and Maze Challenge', 'Game based offers like Spin Wheel, Scratch Card, and Maze Challenge',
'Instant offline redemption at any partner store, no card required', 'Instant offline redemption at any partner store, no card required',
], ],
metric: { val: '50K+', lbl: 'active shoppers' }, metric: { val: '50K+', lbl: 'active shoppers' },
tags: ['Daily Rewards', 'Game Based Offers', 'Offline Redemption'], tags: ['Daily Lyts', 'Game Based Offers', 'Offline Redemption'],
}, },
]; ];
@@ -112,7 +112,7 @@ export default function MeetTheCrewPage() {
color: '#ffffff', margin: '0 0 36px', fontFamily: 'Sora, sans-serif', color: '#ffffff', margin: '0 0 36px', fontFamily: 'Sora, sans-serif',
}}> }}>
Meet the<br /> Meet the<br />
<span style={{ color: '#f4be28' }}>Crew.</span> <span style={{ color: '#f4be28' }}>Agents.</span>
</h1> </h1>
<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' }}> <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' }}>
The builders, thinkers, and retail obsessives behind Loyaly, working every day to make offline shopping as smart as online. The builders, thinkers, and retail obsessives behind Loyaly, working every day to make offline shopping as smart as online.
@@ -160,57 +160,65 @@ export default function MeetTheCrewPage() {
</Reveal> </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} hideBehind>
{PRODUCTS.map((p, i) => ( {PRODUCTS.map((p, i) => (
<ScrollStackItem key={i}> <ScrollStackItem key={i}>
<div style={{ <div style={{
background: `linear-gradient(155deg, #14141c 0%, #0c0c12 100%)`, position: 'relative', overflow: 'hidden',
border: `1px solid ${p.color}40`, background: `radial-gradient(130% 80% at 100% 0%, ${p.color}22 0%, transparent 46%), linear-gradient(155deg, #16161f 0%, #0a0a10 100%)`,
borderRadius: 28, padding: 'clamp(28px, 3.2vw, 48px)', height: '100%', boxSizing: 'border-box', border: `1px solid ${p.color}4d`,
boxShadow: `inset 0 1px 0 rgba(255,255,255,0.06)`,
borderRadius: 28, padding: 'clamp(36px, 4vw, 64px)',
minHeight: 'clamp(380px, 48vh, 500px)', height: '100%', boxSizing: 'border-box',
}}> }}>
<div className="mtc-product-grid" style={{ display: 'grid', gridTemplateColumns: '1.35fr 1fr', gap: 'clamp(28px, 4vw, 56px)', alignItems: 'start' }}> {/* Accent glow blob */}
<div aria-hidden style={{ position: 'absolute', top: '-22%', right: '-8%', width: 360, height: 360, borderRadius: '50%', background: `radial-gradient(circle, ${p.color}26 0%, transparent 70%)`, pointerEvents: 'none' }} />
<div className="mtc-product-grid" style={{ position: 'relative', display: 'grid', gridTemplateColumns: '1.3fr 1fr', gap: 'clamp(32px, 4.5vw, 68px)', alignItems: 'center', height: '100%' }}>
{/* Left — identity + description */} {/* Left — identity + description */}
<div> <div>
<div style={{ display: 'flex', alignItems: 'center', gap: 14, marginBottom: 20 }}> <div style={{ display: 'flex', alignItems: 'center', gap: 14, marginBottom: 24 }}>
<span style={{ fontSize: 13, fontWeight: 800, color: p.color, fontFamily: 'Sora, sans-serif', letterSpacing: '0.05em' }}>{p.n}</span> <span style={{ fontSize: 15, fontWeight: 800, color: p.color, fontFamily: 'Sora, sans-serif', letterSpacing: '0.05em' }}>{p.n}</span>
<span style={{ width: 24, height: 1, background: `${p.color}66`, display: 'block' }} /> <span style={{ fontSize: '0.74rem', fontWeight: 700, letterSpacing: '0.12em', textTransform: 'uppercase', color: p.color, fontFamily: 'Sora, sans-serif' }}>{p.subtitle}</span>
<span style={{ fontSize: '0.7rem', fontWeight: 700, letterSpacing: '0.1em', textTransform: 'uppercase', color: p.color, fontFamily: 'Sora, sans-serif' }}>{p.subtitle}</span>
</div> </div>
<h3 style={{ fontSize: 'clamp(1.8rem, 2.8vw, 2.8rem)', fontWeight: 800, letterSpacing: '-0.03em', color: '#fff', margin: '0 0 16px', fontFamily: 'Sora, sans-serif' }}>{p.title}</h3> <h3 style={{ fontSize: 'clamp(2.1rem, 3.4vw, 3.4rem)', fontWeight: 800, letterSpacing: '-0.035em', color: '#fff', margin: '0 0 20px', fontFamily: 'Sora, sans-serif', lineHeight: 1 }}>{p.title}</h3>
<p style={{ fontSize: 15, lineHeight: 1.75, color: 'rgba(255,255,255,0.5)', fontFamily: 'Sora, sans-serif', margin: '0 0 24px', maxWidth: 480 }}>{p.desc}</p> <p style={{ fontSize: 'clamp(15px, 1.1vw, 17px)', lineHeight: 1.8, color: 'rgba(255,255,255,0.55)', fontFamily: 'Sora, sans-serif', margin: '0 0 30px', maxWidth: 520 }}>{p.desc}</p>
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 8 }}> <div style={{ display: 'flex', flexWrap: 'wrap', gap: 10 }}>
{p.tags.map((tag) => ( {p.tags.map((tag) => (
<span key={tag} style={{ <span key={tag} style={{
padding: '6px 14px', borderRadius: 100, fontSize: '0.72rem', fontWeight: 600, padding: '8px 16px', borderRadius: 100, fontSize: '0.76rem', fontWeight: 700,
color: 'rgba(255,255,255,0.7)', background: 'rgba(255,255,255,0.05)', color: '#fff', background: `${p.color}1a`,
border: '1px solid rgba(255,255,255,0.1)', fontFamily: 'Sora, sans-serif', border: `1px solid ${p.color}3d`, fontFamily: 'Sora, sans-serif',
}}>{tag}</span> }}>{tag}</span>
))} ))}
</div> </div>
</div> </div>
{/* Right — metric + capabilities */} {/* Right — metric hero + capabilities */}
<div> <div>
<div style={{ <div style={{
padding: 'clamp(18px, 2vw, 24px)', borderRadius: 18, marginBottom: 18, padding: 'clamp(24px, 2.6vw, 34px)', borderRadius: 22, marginBottom: 24,
background: `${p.color}12`, border: `1px solid ${p.color}35`, background: `linear-gradient(150deg, ${p.color}2b 0%, ${p.color}0d 100%)`,
border: `1px solid ${p.color}55`,
boxShadow: `0 22px 54px -26px ${p.color}66, inset 0 1px 0 rgba(255,255,255,0.08)`,
}}> }}>
<div style={{ fontSize: 'clamp(1.8rem, 2.6vw, 2.4rem)', fontWeight: 900, color: p.color, fontFamily: 'Sora, sans-serif', letterSpacing: '-0.03em', lineHeight: 1 }}>{p.metric.val}</div> <div style={{ fontSize: 'clamp(2.4rem, 3.4vw, 3.4rem)', fontWeight: 900, color: p.color, fontFamily: 'Sora, sans-serif', letterSpacing: '-0.04em', lineHeight: 1, textShadow: `0 0 30px ${p.color}55` }}>{p.metric.val}</div>
<div style={{ fontSize: 12, color: 'rgba(255,255,255,0.45)', fontFamily: 'Sora, sans-serif', marginTop: 6, textTransform: 'uppercase', letterSpacing: '0.06em' }}>{p.metric.lbl}</div> <div style={{ fontSize: 12, fontWeight: 700, color: 'rgba(255,255,255,0.5)', fontFamily: 'Sora, sans-serif', marginTop: 10, textTransform: 'uppercase', letterSpacing: '0.08em' }}>{p.metric.lbl}</div>
</div> </div>
<div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}> <div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
{p.capabilities.map((cap) => ( {p.capabilities.map((cap) => (
<div key={cap} style={{ display: 'flex', alignItems: 'flex-start', gap: 10 }}> <div key={cap} style={{ display: 'flex', alignItems: 'flex-start', gap: 12 }}>
<span style={{ <span style={{
width: 18, height: 18, borderRadius: '50%', flexShrink: 0, marginTop: 2, width: 22, height: 22, borderRadius: '50%', flexShrink: 0, marginTop: 1,
display: 'flex', alignItems: 'center', justifyContent: 'center', display: 'flex', alignItems: 'center', justifyContent: 'center',
background: `${p.color}18`, border: `1px solid ${p.color}45`, background: `${p.color}22`, border: `1px solid ${p.color}66`,
boxShadow: `0 0 14px -2px ${p.color}77`,
}}> }}>
<svg width="9" height="9" viewBox="0 0 24 24" fill="none" stroke={p.color} strokeWidth="3" strokeLinecap="round" strokeLinejoin="round"><path d="M20 6L9 17l-5-5" /></svg> <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke={p.color} strokeWidth="3.2" strokeLinecap="round" strokeLinejoin="round"><path d="M20 6L9 17l-5-5" /></svg>
</span> </span>
<span style={{ fontSize: 13.5, lineHeight: 1.55, color: 'rgba(255,255,255,0.65)', fontFamily: 'Sora, sans-serif' }}>{cap}</span> <span style={{ fontSize: 14.5, lineHeight: 1.55, color: 'rgba(255,255,255,0.72)', fontFamily: 'Sora, sans-serif' }}>{cap}</span>
</div> </div>
))} ))}
</div> </div>

View File

@@ -37,43 +37,20 @@ const CAPS = [
}, },
]; ];
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 = [ const PILLARS = [
{ {
title: 'Get Online', color: '#f4be28', title: 'Get Discovered', color: '#f4be28',
desc: 'Your store, visible to thousands of local shoppers, without building a website.', desc: 'List your store on Loyaly and get found by thousands of nearby shoppers — no website, no complex setup.',
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>, 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', title: 'Drive Footfall', color: '#a78bfa',
desc: "Push real-time offers and proximity alerts that reach customers the moment they're nearby.", desc: 'Launch game-based campaigns and LYT drops that turn phone time into real, in-store visits.',
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>, 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', title: 'Understand Everything', color: '#34d399',
desc: 'One dashboard. All your deals, customers, and performance, managed in one place.', desc: 'Run campaigns, track live footfall, and read AI customer insights — all from one dashboard.',
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>, 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>,
}, },
]; ];
@@ -155,19 +132,26 @@ export default function ForBusinessPage() {
letterSpacing: '-0.05em', lineHeight: 0.9, letterSpacing: '-0.05em', lineHeight: 0.9,
color: '#ffffff', margin: '0 0 32px', fontFamily: 'Sora, sans-serif', color: '#ffffff', margin: '0 0 32px', fontFamily: 'Sora, sans-serif',
}}> }}>
Turn Footfall<br /> Turn Every Visit<br />
<span style={{ <span style={{
background: 'linear-gradient(105deg,#f4be28 0%,#fff8e0 45%,#f4be28 60%,#ff9500 100%)', background: 'linear-gradient(105deg,#f4be28 0%,#fff8e0 45%,#f4be28 60%,#ff9500 100%)',
backgroundSize: '200% auto', WebkitBackgroundClip: 'text', WebkitTextFillColor: 'transparent', backgroundSize: '200% auto', WebkitBackgroundClip: 'text', WebkitTextFillColor: 'transparent',
animation: 'shimmer 3s linear infinite', animation: 'shimmer 3s linear infinite',
}}>Into Revenue.</span> }}>Into A Relationship.</span>
</h1> </h1>
<p data-gsap="text" style={{ <p data-gsap="text" style={{
fontSize: 'clamp(16px, 1.6vw, 21px)', lineHeight: 1.7, color: 'rgba(255,255,255,0.45)', fontSize: 'clamp(16px, 1.6vw, 21px)', lineHeight: 1.7, color: 'rgba(255,255,255,0.55)',
fontFamily: 'Sora, sans-serif', maxWidth: 560, margin: '0 auto 52px', fontFamily: 'Sora, sans-serif', maxWidth: 620, margin: '0 auto 18px',
}}> }}>
Loyaly.ai gives you complete visibility and control over your retail operations, understanding customers from entry to purchase. Loyaly.ai understands customer behavior in real time and helps businesses earn loyalty through personalized experiences powered by AI.
</p>
<p data-gsap="text" style={{
fontSize: 'clamp(14px, 1.3vw, 17px)', lineHeight: 1.7, color: 'rgba(255,255,255,0.4)',
fontFamily: 'Sora, sans-serif', maxWidth: 540, margin: '0 auto 52px',
}}>
Engage customers, understand what they love, and create moments that keep them coming back.
</p> </p>
<div style={{ display: 'flex', gap: 14, flexWrap: 'wrap', justifyContent: 'center' }}> <div style={{ display: 'flex', gap: 14, flexWrap: 'wrap', justifyContent: 'center' }}>
@@ -176,14 +160,14 @@ export default function ForBusinessPage() {
padding: '18px 40px', background: '#f4be28', color: '#111', padding: '18px 40px', background: '#f4be28', color: '#111',
fontSize: 16, fontWeight: 800, borderRadius: 100, textDecoration: 'none', fontSize: 16, fontWeight: 800, borderRadius: 100, textDecoration: 'none',
fontFamily: 'Sora, sans-serif', boxShadow: '0 16px 60px rgba(244,190,40,0.3)', fontFamily: 'Sora, sans-serif', boxShadow: '0 16px 60px rgba(244,190,40,0.3)',
}}>Book a Demo </Link> }}>Get Started </Link>
<Link href="/contacts" style={{ <Link href="/contacts" style={{
display: 'inline-flex', alignItems: 'center', gap: 10, display: 'inline-flex', alignItems: 'center', gap: 10,
padding: '18px 40px', background: 'rgba(255,255,255,0.06)', color: '#fff', padding: '18px 40px', background: 'rgba(255,255,255,0.06)', color: '#fff',
fontSize: 16, fontWeight: 700, borderRadius: 100, textDecoration: 'none', fontSize: 16, fontWeight: 700, borderRadius: 100, textDecoration: 'none',
fontFamily: 'Sora, sans-serif', border: '1px solid rgba(255,255,255,0.12)', fontFamily: 'Sora, sans-serif', border: '1px solid rgba(255,255,255,0.12)',
backdropFilter: 'blur(12px)', backdropFilter: 'blur(12px)',
}}>Talk to Sales</Link> }}>Book a Demo</Link>
</div> </div>
</div> </div>
</div> </div>
@@ -232,13 +216,13 @@ export default function ForBusinessPage() {
<RevealBlock> <RevealBlock>
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-end', marginBottom: 80, flexWrap: 'wrap', gap: 24 }}> <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-end', marginBottom: 80, flexWrap: 'wrap', gap: 24 }}>
<div> <div>
<div style={{ fontSize: 11, fontWeight: 700, letterSpacing: '0.2em', textTransform: 'uppercase', color: '#f4be28', fontFamily: 'Sora, sans-serif', marginBottom: 16 }}>Capabilities</div> <div style={{ fontSize: 11, fontWeight: 700, letterSpacing: '0.2em', textTransform: 'uppercase', color: '#f4be28', fontFamily: 'Sora, sans-serif', marginBottom: 16 }}>The AI Agents</div>
<h2 style={{ fontSize: 'clamp(36px, 5vw, 72px)', fontWeight: 800, letterSpacing: '-0.04em', lineHeight: 0.95, color: '#0a0a0f', margin: 0, fontFamily: 'Sora, sans-serif' }}> <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. Four agents.<br />One AI.
</h2> </h2>
</div> </div>
<p style={{ fontSize: 16, color: 'rgba(0,0,0,0.45)', fontFamily: 'Sora, sans-serif', maxWidth: 360, lineHeight: 1.7 }}> <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. Every agent works independently and amplifies the others, giving merchants a complete system to attract, engage, and retain customers.
</p> </p>
</div> </div>
</RevealBlock> </RevealBlock>
@@ -282,49 +266,6 @@ export default function ForBusinessPage() {
<RevealBlock> <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> <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' }}> <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. Three ways we grow your store.
</h2> </h2>
</RevealBlock> </RevealBlock>
@@ -332,25 +273,37 @@ export default function ForBusinessPage() {
{PILLARS.map((p, i) => ( {PILLARS.map((p, i) => (
<RevealBlock key={p.title} delay={i * 0.1}> <RevealBlock key={p.title} delay={i * 0.1}>
<div className="uc-pillar-card" style={{ <div className="uc-pillar-card" style={{
padding: '36px 32px', borderRadius: 22, height: '100%', boxSizing: 'border-box', padding: '34px 30px 30px', borderRadius: 24, height: '100%', boxSizing: 'border-box',
background: `linear-gradient(160deg, ${p.color}14 0%, #faf9f6 60%)`, background: `radial-gradient(130% 90% at 12% 0%, ${p.color}26 0%, transparent 55%), linear-gradient(180deg, rgba(255,255,255,0.055) 0%, rgba(255,255,255,0.015) 100%)`,
border: `1px solid ${p.color}35`, position: 'relative', overflow: 'hidden', border: `1px solid ${p.color}45`,
transition: 'transform 0.35s cubic-bezier(0.22,1,0.36,1), border-color 0.35s ease', boxShadow: `0 26px 60px -30px ${p.color}66, inset 0 1px 0 rgba(255,255,255,0.08)`,
backdropFilter: 'blur(10px)',
position: 'relative', overflow: 'hidden',
transition: 'transform 0.4s cubic-bezier(0.22,1,0.36,1), filter 0.35s ease',
}}> }}>
<span style={{ <span style={{
position: 'absolute', top: -18, right: -10, fontSize: 96, fontWeight: 900, position: 'absolute', top: 22, right: 22,
color: 'transparent', WebkitTextStroke: `1px ${p.color}22`, fontFamily: 'Sora, sans-serif', display: 'inline-flex', alignItems: 'center', gap: 5,
lineHeight: 1, userSelect: 'none', pointerEvents: 'none', fontSize: 12.5, fontWeight: 800, letterSpacing: '0.08em',
}}>0{i + 1}</span> color: p.color, fontFamily: 'Sora, sans-serif', lineHeight: 1,
padding: '6px 12px', borderRadius: 100,
background: `${p.color}1a`, border: `1px solid ${p.color}55`,
boxShadow: `0 0 18px -6px ${p.color}88`,
userSelect: 'none', pointerEvents: 'none', zIndex: 1,
}}>
<span style={{ width: 5, height: 5, borderRadius: '50%', background: p.color, boxShadow: `0 0 8px ${p.color}` }} />
STEP 0{i + 1}
</span>
<div style={{ <div style={{
width: 54, height: 54, borderRadius: 16, marginBottom: 24, width: 56, height: 56, borderRadius: 16, marginBottom: 26,
background: `${p.color}18`, border: `1px solid ${p.color}45`, background: `${p.color}22`, border: `1px solid ${p.color}66`,
boxShadow: `0 0 26px -6px ${p.color}99, inset 0 1px 0 rgba(255,255,255,0.14)`,
display: 'flex', alignItems: 'center', justifyContent: 'center', color: p.color, display: 'flex', alignItems: 'center', justifyContent: 'center', color: p.color,
position: 'relative', zIndex: 1, position: 'relative', zIndex: 1,
}}>{p.icon}</div> }}>{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> <h3 style={{ fontSize: 23, fontWeight: 800, color: '#ffffff', 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> <p style={{ fontSize: 15, lineHeight: 1.7, color: 'rgba(255,255,255,0.55)', fontFamily: 'Sora, sans-serif', margin: '0 0 22px', position: 'relative', zIndex: 1 }}>{p.desc}</p>
<div style={{ height: 3, width: 40, borderRadius: 2, background: p.color, position: 'relative', zIndex: 1 }} /> <div style={{ height: 4, width: 44, borderRadius: 4, background: p.color, boxShadow: `0 0 14px ${p.color}`, position: 'relative', zIndex: 1 }} />
</div> </div>
</RevealBlock> </RevealBlock>
))} ))}
@@ -358,47 +311,130 @@ export default function ForBusinessPage() {
</section> </section>
{/* ── PROXIMITY MARKETING ── */} {/* ── PROXIMITY MARKETING ── */}
<section style={{ padding: '120px 8%', background: '#0c0a06', margin: '0 20px 20px', borderRadius: 24, overflow: 'hidden', position: 'relative' }}> <section style={{ padding: '120px 8%', background: '#ffffff', 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' }} /> <div style={{ position: 'absolute', inset: 0, backgroundImage: 'linear-gradient(rgba(23,21,18,0.035) 1px,transparent 1px),linear-gradient(90deg,rgba(23,21,18,0.035) 1px,transparent 1px)', backgroundSize: '56px 56px', pointerEvents: 'none' }} />
<RevealBlock> <RevealBlock>
<div className="uc-proximity-grid" style={{ display: 'grid', gridTemplateColumns: '0.85fr 1.15fr', gap: '6vw', alignItems: 'center', position: 'relative' }}> <div className="uc-proximity-grid" style={{ display: 'grid', gridTemplateColumns: '0.9fr 1.1fr', gap: '5vw', alignItems: 'center', position: 'relative' }}>
{/* Radar visual */} {/* Animated city map with proximity pins */}
<div className="uc-radar" style={{ position: 'relative', width: '100%', aspectRatio: '1 / 1', maxWidth: 320, margin: '0 auto' }}> <div className="uc-map-panel" style={{
{[0, 1, 2].map((r) => ( position: 'relative', borderRadius: 28, width: '100%', aspectRatio: '4 / 3', overflow: 'hidden',
<div key={r} className="uc-radar-ring" style={{ background: 'linear-gradient(165deg, #fffdf7 0%, #faf3e0 100%)',
position: 'absolute', inset: 0, borderRadius: '50%', border: '1px solid rgba(244,190,40,0.28)',
border: '1.5px solid rgba(244,190,40,0.35)', boxShadow: '0 34px 80px -34px rgba(201,150,15,0.4), inset 0 1px 0 rgba(255,255,255,0.7)',
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%' }}> <svg viewBox="0 0 400 300" preserveAspectRatio="xMidYMid meet" style={{ position: 'absolute', inset: 0, width: '100%', height: '100%' }}>
{/* Building blocks */}
<g fill="#f6edd4">
<rect x="18" y="18" width="66" height="44" rx="6" />
<rect x="316" y="22" width="62" height="60" rx="6" />
<rect x="22" y="196" width="74" height="86" rx="6" />
<rect x="322" y="200" width="56" height="82" rx="6" />
<rect x="150" y="18" width="40" height="40" rx="5" />
<rect x="236" y="238" width="54" height="46" rx="6" />
</g>
{/* Main roads */}
<g stroke="#efe3c6" strokeLinecap="round">
<line x1="0" y1="80" x2="400" y2="80" strokeWidth="8" />
<line x1="0" y1="150" x2="400" y2="150" strokeWidth="9" />
<line x1="0" y1="222" x2="400" y2="222" strokeWidth="8" />
<line x1="120" y1="0" x2="120" y2="300" strokeWidth="8" />
<line x1="200" y1="0" x2="200" y2="300" strokeWidth="9" />
<line x1="300" y1="0" x2="300" y2="300" strokeWidth="8" />
</g>
{/* Secondary streets */}
<g stroke="#ece0c0" strokeWidth="1.4">
<line x1="0" y1="40" x2="400" y2="40" />
<line x1="0" y1="118" x2="400" y2="118" />
<line x1="0" y1="190" x2="400" y2="190" />
<line x1="0" y1="262" x2="400" y2="262" />
<line x1="60" y1="0" x2="60" y2="300" />
<line x1="252" y1="0" x2="252" y2="300" />
<line x1="350" y1="0" x2="350" y2="300" />
</g>
{/* Proximity radar rings from the store */}
<g fill="none" stroke="#f4be28">
<circle className="uc-map-ring" cx="200" cy="150" r="18" strokeWidth="1.6" />
<circle className="uc-map-ring" cx="200" cy="150" r="18" strokeWidth="1.6" style={{ animationDelay: '1.1s' }} />
<circle className="uc-map-ring" cx="200" cy="150" r="18" strokeWidth="1.6" style={{ animationDelay: '2.2s' }} />
</g>
{/* Routes to nearby shoppers */}
<g stroke="#d9a72a" strokeWidth="1.8" fill="none" strokeLinecap="round">
{[[120, 80], [300, 105], [150, 240], [312, 220]].map(([x, y], i) => (
<line key={i} className="uc-map-link" x1="200" y1="150" x2={x} y2={y} style={{ animationDelay: `${i * 0.3}s` }} />
))}
</g>
{/* Store glow */}
<circle cx="200" cy="150" r="42" fill="#f4be28" opacity="0.16" />
{/* Shopper pins */}
{[[120, 80], [300, 105], [150, 240], [312, 220]].map(([x, y], i) => (
<g key={i}>
<circle className="uc-map-shopper" cx={x} cy={y} r="6" fill="#f4be28" style={{ animationDelay: `${i * 0.5}s` }} />
<circle cx={x} cy={y} r="5" fill="#171512" stroke="#fffdf7" strokeWidth="2" />
</g>
))}
</svg>
{/* Store pin (centered, matches SVG store at 200,150) */}
<div style={{ position: 'absolute', top: '50%', left: '50%', transform: 'translate(-50%,-50%)', width: 76, height: 76 }}>
<span className="uc-pin-halo" aria-hidden style={{ position: 'absolute', inset: '-24%', borderRadius: '50%', background: 'radial-gradient(circle, rgba(244,190,40,0.5) 0%, transparent 70%)' }} />
<div style={{
position: 'absolute', inset: 0, borderRadius: '50%',
background: 'radial-gradient(circle at 35% 30%, #ffd75e 0%, #f4be28 45%, #c9960f 100%)',
display: 'flex', alignItems: 'center', justifyContent: 'center',
boxShadow: '0 14px 34px -8px rgba(201,150,15,0.65), inset 0 2px 4px rgba(255,255,255,0.55)',
border: '3px solid #fffdf7',
}}>
<svg viewBox="0 0 24 24" fill="#171512" style={{ width: 30, height: 30 }}>
<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" /> <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> </svg>
</div> </div>
</div> </div>
{/* Live counter chip */}
<div style={{
position: 'absolute', left: 16, bottom: 16, display: 'inline-flex', alignItems: 'center', gap: 8,
padding: '8px 14px', borderRadius: 100, background: 'rgba(255,255,255,0.92)',
border: '1px solid rgba(244,190,40,0.35)', boxShadow: '0 8px 22px -12px rgba(23,21,18,0.3)', backdropFilter: 'blur(6px)',
}}>
<span className="uc-map-livedot" style={{ width: 7, height: 7, borderRadius: '50%', background: '#16a34a', display: 'block' }} />
<span style={{ fontSize: 12, fontWeight: 800, color: '#171512', fontFamily: 'Sora, sans-serif' }}>18 shoppers nearby</span>
</div>
</div>
{/* Content */} {/* Content */}
<div> <div>
<div style={{ fontSize: 11, fontWeight: 700, letterSpacing: '0.2em', textTransform: 'uppercase', color: '#f4be28', fontFamily: 'Sora, sans-serif', marginBottom: 20 }}>Capability Spotlight</div> <div style={{ display: 'inline-flex', alignItems: 'center', gap: 9, marginBottom: 22, padding: '6px 15px 6px 6px', borderRadius: 100, background: 'rgba(244,190,40,0.1)', border: '1px solid rgba(244,190,40,0.3)' }}>
<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' }}> <span style={{ width: 22, height: 22, borderRadius: '50%', background: '#f4be28', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="#171512" strokeWidth="2.5" 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>
</span>
<span style={{ fontSize: 11, fontWeight: 800, letterSpacing: '0.16em', textTransform: 'uppercase', color: '#8a5a14', fontFamily: 'Sora, sans-serif' }}>Capability Spotlight</span>
</div>
<h2 style={{ fontSize: 'clamp(28px, 3.6vw, 48px)', fontWeight: 800, letterSpacing: '-0.03em', lineHeight: 1.08, color: '#0a0a0f', margin: '0 0 20px', fontFamily: 'Sora, sans-serif' }}>
Reach customers the moment they&apos;re nearby. Reach customers the moment they&apos;re nearby.
</h2> </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 }}> <p style={{ fontSize: 16, lineHeight: 1.8, color: 'rgba(0,0,0,0.55)', fontFamily: 'Sora, sans-serif', margin: '0 0 32px', maxWidth: 480 }}>
Loyaly&apos;s proximity engine sends instant notifications to shoppers browsing within your store&apos;s radius. No ad spend. No guesswork. Just timely, relevant offers delivered at exactly the right moment. Loyaly&apos;s proximity engine sends instant notifications to shoppers browsing within your store&apos;s radius. No ad spend. No guesswork. Just timely, relevant offers delivered at exactly the right moment.
</p> </p>
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 12 }}> <div className="uc-prox-stats" style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 12, maxWidth: 500 }}>
{[{ 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)' }}> { v: 'Instant', l: 'Notification speed', icon: <path d="M13 2L3 14h9l-1 8 10-12h-9l1-8z" /> },
<div style={{ fontSize: 18, fontWeight: 900, color: '#f4be28', fontFamily: 'Sora, sans-serif', letterSpacing: '-0.02em' }}>{s.v}</div> { v: '0', l: 'Ad spend required', icon: <><line x1="12" y1="1" x2="12" y2="23" /><path d="M17 5H9.5a3.5 3.5 0 000 7h5a3.5 3.5 0 010 7H6" /></> },
<div style={{ fontSize: 11.5, color: 'rgba(255,255,255,0.45)', fontFamily: 'Sora, sans-serif', marginTop: 3 }}>{s.l}</div> { v: 'Real-time', l: 'Radius targeting', icon: <><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-7z" /><circle cx="12" cy="9" r="2.5" /></> },
].map((s) => (
<div key={s.l} className="uc-prox-stat" style={{
padding: '18px', borderRadius: 16, background: '#ffffff',
border: '1px solid rgba(23,21,18,0.08)', boxShadow: '0 10px 30px -18px rgba(23,21,18,0.3)',
}}>
<div style={{
width: 34, height: 34, borderRadius: 10, marginBottom: 12,
background: 'rgba(244,190,40,0.14)', border: '1px solid rgba(244,190,40,0.32)',
display: 'flex', alignItems: 'center', justifyContent: 'center', color: '#c9960f',
}}>
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round">{s.icon}</svg>
</div>
<div style={{ fontSize: 18, fontWeight: 900, color: '#171512', fontFamily: 'Sora, sans-serif', letterSpacing: '-0.02em' }}>{s.v}</div>
<div style={{ fontSize: 11.5, color: 'rgba(0,0,0,0.5)', fontFamily: 'Sora, sans-serif', marginTop: 3 }}>{s.l}</div>
</div> </div>
))} ))}
</div> </div>
@@ -484,7 +520,21 @@ export default function ForBusinessPage() {
0% { transform: scale(0.3); opacity: 0.9; } 0% { transform: scale(0.3); opacity: 0.9; }
100% { transform: scale(1.7); opacity: 0; } 100% { transform: scale(1.7); opacity: 0; }
} }
.uc-pillar-card:hover { transform: translateY(-6px); } .uc-pillar-card:hover { transform: translateY(-8px) scale(1.015); filter: brightness(1.12) saturate(1.08); }
.uc-radar-dot { animation: ucDotPulse 2s ease-in-out infinite; }
@keyframes ucDotPulse { 0%, 100% { transform: scale(1); opacity: 0.85; } 50% { transform: scale(1.25); opacity: 1; } }
.uc-pin-halo { animation: ucHaloPulse 2.6s ease-in-out infinite; }
@keyframes ucHaloPulse { 0%, 100% { transform: scale(1); opacity: 0.75; } 50% { transform: scale(1.28); opacity: 0.35; } }
.uc-prox-stat { transition: transform 0.3s cubic-bezier(0.22,1,0.36,1), box-shadow 0.3s ease, border-color 0.3s ease; }
.uc-prox-stat:hover { transform: translateY(-4px); box-shadow: 0 20px 42px -22px rgba(23,21,18,0.4); border-color: rgba(244,190,40,0.5); }
.uc-map-ring { animation: ucMapRing 3.4s ease-out infinite; }
@keyframes ucMapRing { 0% { r: 18px; opacity: 0.5; } 100% { r: 118px; opacity: 0; } }
.uc-map-link { stroke-dasharray: 5 7; animation: ucMapDash 1s linear infinite; }
@keyframes ucMapDash { to { stroke-dashoffset: -24; } }
.uc-map-shopper { animation: ucMapPing 2s ease-in-out infinite; }
@keyframes ucMapPing { 0%, 100% { r: 6px; opacity: 0.5; } 50% { r: 13px; opacity: 0.12; } }
.uc-map-livedot { animation: ucMapLive 1.5s ease-in-out infinite; }
@keyframes ucMapLive { 0% { box-shadow: 0 0 0 0 rgba(22,163,74,0.5); } 70% { box-shadow: 0 0 0 6px rgba(22,163,74,0); } 100% { box-shadow: 0 0 0 0 rgba(22,163,74,0); } }
@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; }
@@ -504,6 +554,7 @@ export default function ForBusinessPage() {
} }
@media (prefers-reduced-motion: reduce) { @media (prefers-reduced-motion: reduce) {
.uc-radar-ring { animation: none !important; opacity: 0.4 !important; } .uc-radar-ring { animation: none !important; opacity: 0.4 !important; }
.uc-radar-dot, .uc-pin-halo, .uc-map-ring, .uc-map-link, .uc-map-shopper, .uc-map-livedot { animation: none !important; }
} }
`}</style> `}</style>
</main> </main>

View File

@@ -10,7 +10,7 @@ const NAV = [
links: [ links: [
{ label: 'For People', href: '/for_people' }, { label: 'For People', href: '/for_people' },
{ label: 'For Business', href: '/use_cases' }, { label: 'For Business', href: '/use_cases' },
{ label: 'Meet the Crew', href: '/solutions_page' }, { label: 'Meet the Agents', href: '/solutions_page' },
], ],
}, },
{ {
@@ -119,9 +119,13 @@ export default function Footer() {
alignItems: 'start', alignItems: 'start',
}}> }}>
{/* Brand */} {/* Brand */}
<div className="ly-footer-brand"> <div className="ly-footer-brand" style={{ display: 'flex', flexDirection: 'column', alignItems: 'flex-start' }}>
<Link href="/" aria-label="Loyaly.AI home"> <Link href="/" aria-label="Loyaly.AI home" style={{ display: 'block', maxWidth: '100%', marginBottom: 18 }}>
<Image src="/images/logo-dark.png" alt="Loyaly.AI" width={560} height={160} style={{ height: 140, width: 'auto', marginBottom: 24, display: 'block' }} /> {/* logo-dark.png is 250x150 with the wordmark in the middle strip (y 58107);
an overflow box crops the transparent top/bottom padding so it fills at size */}
<span className="ly-footer-logo" style={{ display: 'block', width: 300, maxWidth: '100%', aspectRatio: '250 / 58', overflow: 'hidden' }}>
<Image src="/images/logo-dark.png" alt="Loyaly.AI" width={250} height={150} style={{ width: '100%', height: '100%', objectFit: 'cover', objectPosition: 'center 55%', display: 'block' }} />
</span>
</Link> </Link>
<p style={{ fontSize: 14, lineHeight: 1.75, color: 'rgba(255,255,255,0.35)', fontFamily: 'Sora, sans-serif', margin: '0 0 28px', maxWidth: 280 }}> <p style={{ fontSize: 14, lineHeight: 1.75, color: 'rgba(255,255,255,0.35)', fontFamily: 'Sora, sans-serif', margin: '0 0 28px', maxWidth: 280 }}>
AI powered retail intelligence that turns every walk in into a loyal customer. AI powered retail intelligence that turns every walk in into a loyal customer.
@@ -195,7 +199,7 @@ export default function Footer() {
@media (max-width: 560px) { @media (max-width: 560px) {
.ly-footer-heading { font-size: clamp(30px, 9vw, 44px) !important; } .ly-footer-heading { font-size: clamp(30px, 9vw, 44px) !important; }
.ly-footer-columns { grid-template-columns: 1fr !important; gap: 32px !important; } .ly-footer-columns { grid-template-columns: 1fr !important; gap: 32px !important; }
.ly-footer-brand img { height: 110px !important; } .ly-footer-logo { width: 260px !important; }
.ly-footer-bottom { gap: 16px !important; } .ly-footer-bottom { gap: 16px !important; }
.ly-footer-bottom > div { gap: 18px !important; } .ly-footer-bottom > div { gap: 18px !important; }
} }

View File

@@ -9,9 +9,9 @@ const NAV_LINKS = [
{ label: 'Home', href: '/' }, { label: 'Home', href: '/' },
{ label: 'For People', href: '/for_people' }, { label: 'For People', href: '/for_people' },
{ label: 'For Business', href: '/use_cases' }, { label: 'For Business', href: '/use_cases' },
{ label: 'Meet the Crew', href: '/solutions_page' }, { label: 'Meet the Agents', href: '/solutions_page' },
{ label: 'Blogs', href: '/blog_main' },
{ label: 'About us', href: '/about_us' }, { label: 'About us', href: '/about_us' },
{ label: 'Blogs', href: '/blog_main' },
]; ];
const MOBILE_QUERY = '(max-width: 1023px)'; const MOBILE_QUERY = '(max-width: 1023px)';

View File

@@ -31,6 +31,7 @@
-webkit-transform: translateZ(0); -webkit-transform: translateZ(0);
transform: translateZ(0); transform: translateZ(0);
position: relative; position: relative;
transition: opacity 0.35s ease;
} }
.scroll-stack-end { .scroll-stack-end {

View File

@@ -27,6 +27,7 @@ interface ScrollStackProps {
scaleDuration?: number; scaleDuration?: number;
rotationAmount?: number; rotationAmount?: number;
blurAmount?: number; blurAmount?: number;
hideBehind?: boolean;
useWindowScroll?: boolean; useWindowScroll?: boolean;
onStackComplete?: () => void; onStackComplete?: () => void;
} }
@@ -42,6 +43,7 @@ const ScrollStack = ({
baseScale = 0.85, baseScale = 0.85,
rotationAmount = 0, rotationAmount = 0,
blurAmount = 0, blurAmount = 0,
hideBehind = false,
useWindowScroll = false, useWindowScroll = false,
onStackComplete, onStackComplete,
}: ScrollStackProps) => { }: ScrollStackProps) => {
@@ -122,6 +124,14 @@ const ScrollStack = ({
const endElementTop = endTopRef.current; const endElementTop = endTopRef.current;
// Which card is currently on top of the stack (used for blur + hide-behind)
let topCardIndex = 0;
for (let j = 0; j < cardsRef.current.length; j++) {
const jCardTop = cardTopsRef.current[j] ?? 0;
const jTriggerStart = jCardTop - stackPositionPx - itemStackDistance * j;
if (scrollTop >= jTriggerStart) topCardIndex = j;
}
cardsRef.current.forEach((card, i) => { cardsRef.current.forEach((card, i) => {
if (!card) return; if (!card) return;
@@ -137,20 +147,14 @@ const ScrollStack = ({
const rotation = rotationAmount ? i * rotationAmount * scaleProgress : 0; const rotation = rotationAmount ? i * rotationAmount * scaleProgress : 0;
let blur = 0; let blur = 0;
if (blurAmount) { if (blurAmount && i < topCardIndex) {
let topCardIndex = 0;
for (let j = 0; j < cardsRef.current.length; j++) {
const jCardTop = cardTopsRef.current[j] ?? 0;
const jTriggerStart = jCardTop - stackPositionPx - itemStackDistance * j;
if (scrollTop >= jTriggerStart) {
topCardIndex = j;
}
}
if (i < topCardIndex) {
const depthInStack = topCardIndex - i; const depthInStack = topCardIndex - i;
blur = Math.max(0, depthInStack * blurAmount); blur = Math.max(0, depthInStack * blurAmount);
} }
// Hide cards stacked behind the current top card entirely
if (hideBehind) {
card.style.opacity = i < topCardIndex ? '0' : '1';
} }
let translateY = 0; let translateY = 0;
@@ -207,6 +211,7 @@ const ScrollStack = ({
baseScale, baseScale,
rotationAmount, rotationAmount,
blurAmount, blurAmount,
hideBehind,
useWindowScroll, useWindowScroll,
onStackComplete, onStackComplete,
calculateProgress, calculateProgress,

View File

@@ -12,9 +12,9 @@ if (typeof window !== 'undefined') gsap.registerPlugin(ScrollTrigger);
const useIsomorphicLayoutEffect = typeof window !== 'undefined' ? useLayoutEffect : useEffect; const useIsomorphicLayoutEffect = typeof window !== 'undefined' ? useLayoutEffect : useEffect;
const TAGS = [ const TAGS = [
{ label: 'Live coupons', icon: '🎟️' }, { label: 'Earn as you live', icon: '' },
{ label: 'Nearby stores', icon: '📍' }, { label: 'Play to win', icon: '🎮' },
{ label: 'Game-based deals', icon: '🎮' }, { label: 'Spend anywhere', icon: '🛍️' },
]; ];
export default function DiscoverDealsSection() { export default function DiscoverDealsSection() {
@@ -54,10 +54,10 @@ export default function DiscoverDealsSection() {
<section ref={panelRef} className="fp-panel" style={{ background: '#08080f' }}> <section ref={panelRef} className="fp-panel" style={{ background: '#08080f' }}>
{/* Background photo */} {/* Background photo */}
<Image src="/images/stock/discover.png" alt="" fill style={{ objectFit: 'cover', opacity: 0.16, zIndex: 0 }} /> <Image src="/images/stock/discover.png" alt="" fill style={{ objectFit: 'cover', opacity: 0.72, zIndex: 0 }} />
<div style={{ <div style={{
position: 'absolute', inset: 0, zIndex: 0, position: 'absolute', inset: 0, zIndex: 0,
background: 'linear-gradient(100deg, rgba(8,8,15,0.96) 0%, rgba(8,8,15,0.65) 42%, rgba(8,8,15,0.5) 68%, rgba(8,8,15,0.85) 100%), linear-gradient(180deg, rgba(8,8,15,0.2) 0%, rgba(8,8,15,0.8) 85%)', background: 'linear-gradient(100deg, rgba(8,8,15,0.72) 0%, rgba(8,8,15,0.32) 42%, rgba(8,8,15,0.12) 70%, rgba(8,8,15,0.24) 100%), linear-gradient(180deg, rgba(8,8,15,0) 0%, rgba(8,8,15,0.28) 90%)',
}} /> }} />
{/* Soft radial — drifts with parallax for depth */} {/* Soft radial — drifts with parallax for depth */}
@@ -71,37 +71,23 @@ export default function DiscoverDealsSection() {
{/* Headline column */} {/* Headline column */}
<div> <div>
<div style={{ marginBottom: 28 }}><span className="fp-kicker fp-rise">Discover<span className="fp-kicker-num">01</span></span></div> <div style={{ marginBottom: 28 }}><span className="fp-kicker fp-rise">Meet LytsUp<span className="fp-kicker-num">01</span></span></div>
<h2 className="fp-h1" style={{ color: '#fff' }}> <h2 className="fp-h1" style={{ color: '#fff' }}>
<span className="fp-mask"><span>Every</span></span> <span className="fp-mask"><span>The app that</span></span>
<span className="fp-mask"><span>deal in</span></span> <span className="fp-mask"><span>rewards you for</span></span>
<span className="fp-mask"><span className="fp-shimmer">your city.</span></span> <span className="fp-mask"><span className="fp-shimmer">living your life.</span></span>
</h2> </h2>
<p className="fp-rise fp-desc" style={{ color: 'rgba(255,255,255,0.45)', maxWidth: 380 }}> <p className="fp-rise fp-desc" style={{ color: 'rgba(255,255,255,0.45)', maxWidth: 380 }}>
Find participating stores nearby and see their active game based discount campaigns, live coupons, and LYTs earning opportunities, all surfaced in real time so you never miss a deal. LytsUp turns everyday moments walking, playing, exploring, shopping into LYTs you can spend instantly at the brands you love.
</p> </p>
<div ref={tagsRef} style={{ display: 'flex', flexWrap: 'wrap', gap: 10, marginBottom: 20, maxWidth: 460 }}> <div ref={tagsRef} style={{ display: 'flex', flexWrap: 'wrap', gap: 10, maxWidth: 460 }}>
{TAGS.map((tag) => ( {TAGS.map((tag) => (
<FpTagCard key={tag.label} theme="dark" icon={tag.icon}>{tag.label}</FpTagCard> <FpTagCard key={tag.label} theme="dark" icon={tag.icon}>{tag.label}</FpTagCard>
))} ))}
</div> </div>
<FpTagCard
theme="dark"
className="fp-rise"
style={{ display: 'inline-flex' }}
icon={(
<svg width="13" height="13" viewBox="0 0 24 24" fill="none">
<circle cx="12" cy="10" r="3" stroke="#f4be28" strokeWidth="2" />
<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-7z" stroke="#f4be28" strokeWidth="2" fill="none" />
</svg>
)}
>
Coimbatore, TN
</FpTagCard>
</div> </div>
{/* Discover GIF */} {/* Discover GIF */}
@@ -117,7 +103,7 @@ export default function DiscoverDealsSection() {
{/* eslint-disable-next-line @next/next/no-img-element */} {/* eslint-disable-next-line @next/next/no-img-element */}
<img <img
src="/images/stock/discover.gif" src="/images/stock/discover.gif"
alt="Discover deals in the Loyaly.AI app" alt="Discover deals in the LytsUp app"
style={{ position: 'relative', zIndex: 1, width: '100%', aspectRatio: '1465 / 1074', objectFit: 'cover', borderRadius: 20, display: 'block' }} style={{ position: 'relative', zIndex: 1, width: '100%', aspectRatio: '1465 / 1074', objectFit: 'cover', borderRadius: 20, display: 'block' }}
/> />

View File

@@ -81,7 +81,7 @@ export default function EarnRewardsSection() {
<div ref={phoneRef} style={{ display: 'flex', justifyContent: 'center', opacity: 0, width: '100%' }}> <div ref={phoneRef} style={{ display: 'flex', justifyContent: 'center', opacity: 0, width: '100%' }}>
<PhoneMockupImage <PhoneMockupImage
src="/For_people/01_earn-cropped.png" src="/For_people/01_earn-cropped.png"
alt="Loyaly.AI Earn screen showing Lyts balance and activity feed" alt="LytsUp Earn screen showing Lyts balance and activity feed"
floatClassName="erm-phone-shell" floatClassName="erm-phone-shell"
aspectRatio={1684 / 3196} aspectRatio={1684 / 3196}
/> />
@@ -103,7 +103,7 @@ export default function EarnRewardsSection() {
<div ref={tagsRef} style={{ display: 'flex', flexWrap: 'wrap', gap: 10, marginBottom: 20, maxWidth: 460 }}> <div ref={tagsRef} style={{ display: 'flex', flexWrap: 'wrap', gap: 10, marginBottom: 20, maxWidth: 460 }}>
{earnTags.map((tag) => ( {earnTags.map((tag) => (
<FpTagCard key={tag.label} theme="light" icon={tag.icon} iconBg={tag.bg}> <FpTagCard key={tag.label} theme="light" icon={tag.icon} iconBg={tag.bg}>
{tag.label} <span style={{ color: '#9a9184', fontWeight: 600 }}>Lyts</span> {tag.label}
</FpTagCard> </FpTagCard>
))} ))}
</div> </div>

View File

@@ -83,7 +83,7 @@ export default function ExperienceSection() {
fontSize: 16, lineHeight: 1.85, color: 'rgba(7, 7, 13, 0.75)', fontFamily: 'Sora, sans-serif', margin: '0 0 36px', maxWidth: 360, fontSize: 16, lineHeight: 1.85, color: 'rgba(7, 7, 13, 0.75)', fontFamily: 'Sora, sans-serif', margin: '0 0 36px', maxWidth: 360,
fontWeight: 500, 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. LytsUp 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' }}>

View File

@@ -30,7 +30,7 @@ function useMagnetic() {
const PROOF = [ const PROOF = [
{ val: '50K+', label: 'Active users', color: '#f4be28', icon: '👥', iconBg: '#fffbeb' }, { val: '50K+', label: 'Active users', color: '#f4be28', icon: '👥', iconBg: '#fffbeb' },
{ val: '10K+', label: 'Partner stores', color: '#16a34a', icon: '🏬', iconBg: '#f0fdf4' }, { val: '10K+', label: 'Partner stores', color: '#16a34a', icon: '🏬', iconBg: '#f0fdf4' },
{ val: '₹28L+', label: 'Rewards given', color: '#2563eb', icon: '🎁', iconBg: '#eff6ff' }, { val: '₹28L+', label: 'Lyts given', color: '#2563eb', icon: '🎁', iconBg: '#eff6ff' },
{ val: '4.9★', label: 'App rating', color: '#9333ea', icon: '⭐', iconBg: '#faf5ff' }, { val: '4.9★', label: 'App rating', color: '#9333ea', icon: '⭐', iconBg: '#faf5ff' },
]; ];

View File

@@ -63,23 +63,33 @@ export default function HeroSection() {
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: '50px 0 28px', fontFamily: 'Sora, sans-serif', letterSpacing: '-0.045em', color: '#fff', margin: '50px 0 28px', fontFamily: 'Sora, sans-serif',
}}> }}>
<span className="fp-mask"><span>Get Lit.</span></span> <span className="fp-mask"><span>Earn LYTs.</span></span>
<span className="fp-mask"><span className="fp-shimmer">Live More.</span></span> <span className="fp-mask"><span className="fp-shimmer">Lit Yourself.</span></span>
</h1> </h1>
<p className="fp-content fp-subtext" style={{ <p className="fp-content fp-subtext" style={{
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.6)', maxWidth: 640, margin: '0 auto 16px', fontFamily: 'Sora, sans-serif',
}}> }}>
Meet <strong>Lyts</strong>: rewards for the things you already do. Walk, play, explore, shop, or complete a challenge, then spend your Lyts instantly at the brands you love. No waiting. No cashback. No complicated redemption. Every purchase unlocks more than points. Earn <strong>LYTs</strong>, discover experiences, and make every shopping trip count.
</p>
<p className="fp-content fp-subtext" style={{
fontSize: 'clamp(14px, 1.2vw, 16px)', lineHeight: 1.7, fontWeight: 400,
color: 'rgba(255,255,255,0.45)', maxWidth: 560, margin: '0 auto 40px', fontFamily: 'Sora, sans-serif',
}}>
Shop nearby, collect LYTs, unlock exclusive drops, and become part of a living ecosystem designed around you.
</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' }}>
<button className="fp-btn fp-btn-primary">
Start Earning LYTs
</button>
<button <button
ref={magSecondary} ref={magSecondary}
className="fp-btn fp-btn-ghost fp-magnetic" className="fp-btn fp-btn-ghost fp-magnetic"
> >
See How It Works Explore Nearby
</button> </button>
</div> </div>

View File

@@ -51,11 +51,11 @@ export default function LytsUniverseSection() {
<h2 className="fp-h1" style={{ color: '#fff' }}> <h2 className="fp-h1" style={{ color: '#fff' }}>
<span className="fp-mask"><span>Welcome to the</span></span> <span className="fp-mask"><span>Welcome to the</span></span>
<span className="fp-mask"><span className="fp-shimmer">World of Lyts.</span></span> <span className="fp-mask"><span className="fp-shimmer">World of Lytians.</span></span>
</h2> </h2>
<p className="fp-rise" style={{ fontSize: 15, lineHeight: 1.8, color: 'rgba(255,255,255,0.5)', fontFamily: 'Sora, sans-serif', maxWidth: 420, margin: '0 0 24px' }}> <p className="fp-rise" style={{ fontSize: 15, lineHeight: 1.8, color: 'rgba(255,255,255,0.5)', fontFamily: 'Sora, sans-serif', maxWidth: 420, margin: '0 0 24px' }}>
A world where every action has value. Meet the Lytians, real people with real stories and real rewards, straight from the app. A world where every action has value. Meet the Lytians, real people with real stories and real Lyts, straight from the app.
</p> </p>
<div className="fp-rise" style={{ display: 'flex', flexWrap: 'wrap', gap: 10, marginBottom: 28, maxWidth: 460 }}> <div className="fp-rise" style={{ display: 'flex', flexWrap: 'wrap', gap: 10, marginBottom: 28, maxWidth: 460 }}>

View File

@@ -11,14 +11,14 @@ const PILLARS = [
}, },
{ {
n: '02', n: '02',
title: 'Earn Rewards', title: 'Earn Lyts',
desc: 'Every rupee spent earns LYT points. Zero expiry. Redeem anytime, at any partner store.', desc: 'Every rupee spent earns LYT points. Zero expiry. Redeem anytime, at any partner store.',
color: '#16a34a', color: '#16a34a',
}, },
{ {
n: '03', n: '03',
title: 'Make It a Pleasure', title: 'Make It a Pleasure',
desc: 'Shopping should feel good. Loyaly makes every trip more rewarding, more fun, and more personal.', desc: 'Shopping should feel good. LytsUp makes every trip more rewarding, more fun, and more personal.',
color: '#a78bfa', color: '#a78bfa',
}, },
]; ];
@@ -41,7 +41,7 @@ export default function PillarsSection() {
fontSize: 16, lineHeight: 1.8, color: '#4f463a', margin: '0 0 56px', fontSize: 16, lineHeight: 1.8, color: '#4f463a', margin: '0 0 56px',
fontFamily: 'Sora, sans-serif', maxWidth: 560, 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. Earn Lyts on everyday shopping, from groceries to fashion to home essentials. Every purchase brings you closer to your next Lyt.
</p> </p>
<div className="fp-pillar-cols" style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 24 }}> <div className="fp-pillar-cols" style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 24 }}>

View File

@@ -72,7 +72,7 @@ export default function SpendAnywhereSection() {
fontSize: 'clamp(17px, 1.7vw, 21px)', lineHeight: 1.3, color: '#fff', fontFamily: 'Sora, sans-serif', fontSize: 'clamp(17px, 1.7vw, 21px)', lineHeight: 1.3, color: '#fff', fontFamily: 'Sora, sans-serif',
margin: 0, fontWeight: 800, letterSpacing: '-0.02em', margin: 0, fontWeight: 800, letterSpacing: '-0.02em',
}}> }}>
One Wallet. <span style={{ color: '#f4be28' }}>Thousands of Rewards.</span> One Wallet. <span style={{ color: '#f4be28' }}>Thousands of Lyts.</span>
</p> </p>
</div> </div>
</div> </div>

View File

@@ -32,7 +32,7 @@ export default function WhyLoyalySection() {
const bars = [ const bars = [
{ label: 'Online retail rewards', pct: 78, color: '#171512' }, { label: 'Online retail rewards', pct: 78, color: '#171512' },
{ label: 'Offline retail rewards', pct: 2, color: '#bc7122' }, { label: 'Offline retail rewards', pct: 2, color: '#bc7122' },
{ label: 'Loyaly target', pct: 60, color: '#f4be28' }, { label: 'LytsUp target', pct: 60, color: '#f4be28' },
]; ];
return ( return (
@@ -77,7 +77,7 @@ export default function WhyLoyalySection() {
{[ {[
{ val: '₹2.1L Cr', label: 'Offline retail market size', accent: '#171512' }, { val: '₹2.1L Cr', label: 'Offline retail market size', accent: '#171512' },
{ val: '<2%', label: 'Currently getting rewards', accent: '#bc7122' }, { val: '<2%', label: 'Currently getting rewards', accent: '#bc7122' },
{ val: '10Cr+', label: 'Shoppers Loyaly can reach', accent: '#16a34a' }, { val: '10Cr+', label: 'Shoppers LytsUp can reach', accent: '#16a34a' },
].map((m, i) => ( ].map((m, i) => (
<div key={i} className="fp-rise" style={{ <div key={i} className="fp-rise" style={{
display: 'flex', alignItems: 'center', gap: 16, padding: '14px 18px', display: 'flex', alignItems: 'center', gap: 16, padding: '14px 18px',
@@ -116,7 +116,7 @@ export default function WhyLoyalySection() {
fontSize: 16, lineHeight: 1.8, color: '#4f463a', margin: '0 0 36px', fontSize: 16, lineHeight: 1.8, color: '#4f463a', margin: '0 0 36px',
fontFamily: 'Sora, sans-serif', maxWidth: 440, fontFamily: 'Sora, sans-serif', maxWidth: 440,
}}> }}>
India&apos;s offline retail market is worth 2.1 lakh crore. Yet rewards penetration sits at effectively zero. Loyaly exists to close that gap, permanently. India&apos;s offline retail market is worth 2.1 lakh crore. Yet rewards penetration sits at effectively zero. LytsUp exists to close that gap, permanently.
</p> </p>
{/* Data bars */} {/* Data bars */}

View File

@@ -10,7 +10,6 @@ interface HeroContentProps {
} }
export default function HeroContent({ slide }: HeroContentProps) { export default function HeroContent({ slide }: HeroContentProps) {
const badgeRef = useRef<HTMLDivElement | null>(null);
const headlineRef = useRef<HTMLHeadingElement | null>(null); const headlineRef = useRef<HTMLHeadingElement | null>(null);
const descRef = useRef<HTMLParagraphElement | null>(null); const descRef = useRef<HTMLParagraphElement | null>(null);
const ctaRef = useRef<HTMLDivElement | null>(null); const ctaRef = useRef<HTMLDivElement | null>(null);
@@ -23,14 +22,11 @@ export default function HeroContent({ slide }: HeroContentProps) {
: []; : [];
const desc = descRef.current; const desc = descRef.current;
const cta = ctaRef.current; const cta = ctaRef.current;
const badge = badgeRef.current;
gsap.set(wordEls, { yPercent: 120, opacity: 0, rotateZ: 4 }); gsap.set(wordEls, { yPercent: 120, opacity: 0, rotateZ: 4 });
gsap.set([desc, cta], { opacity: 0, y: 24 }); gsap.set([desc, cta], { opacity: 0, y: 24 });
gsap.set(badge, { opacity: 0, y: -12, scale: 0.92 });
const tl = gsap.timeline({ defaults: { ease: 'power4.out' } }); const tl = gsap.timeline({ defaults: { ease: 'power4.out' } });
tl.to(badge, { opacity: 1, y: 0, scale: 1, duration: 0.6 }, 0);
tl.to( tl.to(
wordEls, wordEls,
{ yPercent: 0, opacity: 1, rotateZ: 0, duration: 1, stagger: 0.055 }, { yPercent: 0, opacity: 1, rotateZ: 0, duration: 1, stagger: 0.055 },
@@ -44,11 +40,6 @@ export default function HeroContent({ slide }: HeroContentProps) {
return ( return (
<div className="hero-carousel-content"> <div className="hero-carousel-content">
<div ref={badgeRef} className="hero-carousel-badge">
<span className="hero-carousel-badge-dot" />
{slide.badge}
</div>
<h1 ref={headlineRef} className="hero-carousel-headline"> <h1 ref={headlineRef} className="hero-carousel-headline">
{words.map((word, i) => { {words.map((word, i) => {
const isHighlighted = slide.highlightWords.includes(word); const isHighlighted = slide.highlightWords.includes(word);

View File

@@ -43,10 +43,12 @@ export default function LytsUpSection({ isLoaded = true }: LytsUpSectionProps) {
const tl = gsap.timeline({ const tl = gsap.timeline({
scrollTrigger: { trigger: '.lytsup-header', start: 'top 85%', toggleActions: 'play none none none' }, scrollTrigger: { trigger: '.lytsup-header', start: 'top 85%', toggleActions: 'play none none none' },
}); });
tl.fromTo('.lytsup-word-inner', { yPercent: 115, rotate: 4 }, { yPercent: 0, rotate: 0, duration: 0.85, stagger: 0.08, ease: 'expo.out' }, 0) tl.fromTo('.lytsup-eyebrow', { opacity: 0, y: -12 }, { opacity: 1, y: 0, duration: 0.6, ease: 'power3.out' }, 0)
.fromTo('.lytsup-sticker-wrap', { opacity: 0, scale: 0.4, rotate: 16 }, { opacity: 1, scale: 1, rotate: -4, duration: 0.7, ease: 'back.out(2.2)' }, 0.18) .fromTo('.lytsup-word-inner', { yPercent: 115, rotate: 4 }, { yPercent: 0, rotate: 0, duration: 0.85, stagger: 0.08, ease: 'expo.out' }, 0.05)
.fromTo('.lytsup-sticker-wrap', { opacity: 0, scale: 0.4, rotate: 16 }, { opacity: 1, scale: 1, rotate: -4, duration: 0.7, ease: 'back.out(2.2)' }, 0.22)
.fromTo('.lytsup-header-sub', { opacity: 0, y: 24, filter: 'blur(6px)' }, { opacity: 1, y: 0, filter: 'blur(0px)', duration: 0.8, ease: 'expo.out' }, 0.45) .fromTo('.lytsup-header-sub', { opacity: 0, y: 24, filter: 'blur(6px)' }, { opacity: 1, y: 0, filter: 'blur(0px)', duration: 0.8, ease: 'expo.out' }, 0.45)
.fromTo('.lytsup-stat-chip', { opacity: 0, y: 18, scale: 0.85 }, { opacity: 1, y: 0, scale: 1, duration: 0.55, stagger: 0.1, ease: 'back.out(1.8)' }, 0.6); .fromTo('.lytsup-tag', { opacity: 0, y: 12, scale: 0.9 }, { opacity: 1, y: 0, scale: 1, duration: 0.5, stagger: 0.07, ease: 'back.out(1.8)' }, 0.55)
.fromTo('.lytsup-stat-chip', { opacity: 0, y: 18, scale: 0.85 }, { opacity: 1, y: 0, scale: 1, duration: 0.55, stagger: 0.1, ease: 'back.out(1.8)' }, 0.68);
// Stat numbers count up once the chips have landed // Stat numbers count up once the chips have landed
PROOF_STATS.forEach((stat, i) => { PROOF_STATS.forEach((stat, i) => {
@@ -159,8 +161,12 @@ export default function LytsUpSection({ isLoaded = true }: LytsUpSectionProps) {
borderRadius: 32, borderRadius: 32,
padding: 'clamp(64px, 8vw, 110px) clamp(20px, 4vw, 64px) clamp(64px, 8vw, 96px)', padding: 'clamp(64px, 8vw, 110px) clamp(20px, 4vw, 64px) clamp(64px, 8vw, 96px)',
zIndex: 2, zIndex: 2,
background: 'radial-gradient(ellipse 110% 80% at 50% 0%, #17130d 0%, #0d0b09 55%, #0a0807 100%)', background:
boxShadow: 'inset 0 0 0 1px rgba(244,190,40,0.12)', 'radial-gradient(120% 90% at 50% -12%, rgba(244,194,26,0.24) 0%, rgba(244,194,26,0) 52%),' +
'radial-gradient(90% 70% at 86% 16%, rgba(255,217,90,0.14) 0%, rgba(255,217,90,0) 55%),' +
'radial-gradient(80% 80% at 10% 96%, rgba(244,194,26,0.09) 0%, rgba(244,194,26,0) 50%),' +
'linear-gradient(180deg, #17140a 0%, #121009 42%, #0b0906 100%)',
boxShadow: 'inset 0 0 0 1px rgba(244,194,26,0.16)',
}} }}
> >
{/* Faint dot-grid texture for depth, matching the light sections elsewhere */} {/* Faint dot-grid texture for depth, matching the light sections elsewhere */}
@@ -192,6 +198,21 @@ export default function LytsUpSection({ isLoaded = true }: LytsUpSectionProps) {
{/* Header */} {/* Header */}
<div className="lytsup-header relative z-10 text-center max-w-3xl mx-auto mb-12 flex flex-col items-center"> <div className="lytsup-header relative z-10 text-center max-w-3xl mx-auto mb-12 flex flex-col items-center">
<div
className="lytsup-eyebrow"
style={{
display: 'inline-flex', alignItems: 'center', gap: 9,
padding: '7px 16px 7px 12px', borderRadius: 100, marginBottom: 24,
background: 'rgba(244,190,40,0.08)', border: '1px solid rgba(244,190,40,0.28)',
backdropFilter: 'blur(8px)',
}}
>
<span className="lytsup-live-dot" style={{ width: 8, height: 8, borderRadius: '50%', background: '#f4be28' }} />
<span style={{ fontSize: 11, fontWeight: 800, letterSpacing: '0.16em', textTransform: 'uppercase', color: '#f4be28', fontFamily: 'Sora, sans-serif' }}>
Earn as you live
</span>
</div>
<h2 <h2
style={{ style={{
margin: 0, margin: 0,
@@ -237,9 +258,26 @@ export default function LytsUpSection({ isLoaded = true }: LytsUpSectionProps) {
color: 'rgba(255,255,255,0.62)', fontFamily: 'Sora, sans-serif', color: 'rgba(255,255,255,0.62)', fontFamily: 'Sora, sans-serif',
}} }}
> >
LytsUp transforms your everyday activities into real shopping rewards. Walk, play, explore, visit your favorite places, complete fun challenges, and earn Lyts that you can spend instantly at participating brands. Walk. Play. Explore. Earn <strong style={{ color: 'rgba(255,255,255,0.9)', fontWeight: 700 }}>Lyts</strong> just by living your life then spend them instantly at the brands you already love.
</p> </p>
{/* Gen-Z vibe tags */}
<div className="lytsup-tags" style={{ display: 'flex', flexWrap: 'wrap', justifyContent: 'center', gap: 8, marginTop: 22 }}>
{['#WalkToEarn', '#PlayDaily', '#ExploreMore', '#LevelUp'].map((t) => (
<span
key={t}
className="lytsup-tag"
style={{
fontSize: '0.8rem', fontWeight: 700, fontFamily: 'Sora, sans-serif',
color: 'rgba(255,255,255,0.8)', padding: '6px 14px', borderRadius: 100,
background: 'rgba(255,255,255,0.04)', border: '1px solid rgba(255,255,255,0.1)',
}}
>
{t}
</span>
))}
</div>
{/* Social-proof stat chips — numbers count up on reveal */} {/* Social-proof stat chips — numbers count up on reveal */}
<div style={{ display: 'flex', flexWrap: 'wrap', justifyContent: 'center', gap: 10, marginTop: 26 }}> <div style={{ display: 'flex', flexWrap: 'wrap', justifyContent: 'center', gap: 10, marginTop: 26 }}>
{PROOF_STATS.map((stat, i) => ( {PROOF_STATS.map((stat, i) => (
@@ -265,6 +303,22 @@ export default function LytsUpSection({ isLoaded = true }: LytsUpSectionProps) {
</div> </div>
</div> </div>
{/* Gen-Z gradient marquee ticker */}
<div className="lytsup-marquee relative z-10" aria-hidden>
<div className="lytsup-marquee-track">
{[0, 1].map((dup) => (
<div key={dup} style={{ display: 'inline-flex', gap: '2.5rem', alignItems: 'center' }}>
{['Earn Lyts', 'Play Daily', 'Explore', 'Level Up', 'Spend Instantly'].map((w) => (
<React.Fragment key={w}>
<span className="lytsup-marquee-item">{w}</span>
<span className="lytsup-marquee-star"></span>
</React.Fragment>
))}
</div>
))}
</div>
</div>
{/* Visual flow — numbered stepper; active step + connectors are driven by scroll position */} {/* Visual flow — numbered stepper; active step + connectors are driven by scroll position */}
<div ref={flowRef} className="lytsup-flow relative z-10 flex items-start justify-center gap-2 sm:gap-4 mb-16 sm:mb-20 max-w-xl mx-auto"> <div ref={flowRef} className="lytsup-flow relative z-10 flex items-start justify-center gap-2 sm:gap-4 mb-16 sm:mb-20 max-w-xl mx-auto">
{['Earn', 'Spend', 'Live More'].map((step, i) => ( {['Earn', 'Spend', 'Live More'].map((step, i) => (
@@ -304,42 +358,70 @@ export default function LytsUpSection({ isLoaded = true }: LytsUpSectionProps) {
<div <div
className="lytsup-closing relative z-10 mx-auto" className="lytsup-closing relative z-10 mx-auto"
style={{ style={{
maxWidth: 720, textAlign: 'center', maxWidth: 680, textAlign: 'center',
padding: 'clamp(36px, 4vw, 52px) clamp(24px, 4vw, 48px)', padding: 'clamp(40px, 4.5vw, 60px) clamp(28px, 4vw, 52px)',
borderRadius: 26, borderRadius: 30,
background: 'linear-gradient(180deg, rgba(255,255,255,0.06) 0%, rgba(255,255,255,0.02) 100%)', background: 'linear-gradient(135deg, #FFE071 0%, #f4be28 46%, #FF9E2C 100%)',
border: '1px solid rgba(244,190,40,0.22)', border: '3px solid #171512',
boxShadow: '0 30px 60px -24px rgba(0,0,0,0.6)', boxShadow: '10px 10px 0 0 #171512',
position: 'relative', overflow: 'hidden', position: 'relative',
}} }}
> >
<span aria-hidden style={{ position: 'absolute', top: -18, right: 26, fontSize: 34, transform: 'rotate(12deg)' }}>🔥</span> {/* Rotated sticker badge */}
<div style={{ position: 'absolute', inset: 0, background: 'radial-gradient(ellipse 70% 60% at 30% 0%, rgba(244,190,40,0.14) 0%, transparent 70%)', pointerEvents: 'none' }} /> <span style={{
display: 'inline-block', transform: 'rotate(-3deg)', marginBottom: 18,
background: '#171512', color: '#FFE071', fontFamily: 'Sora, sans-serif',
fontSize: 12, fontWeight: 800, letterSpacing: '0.12em', textTransform: 'uppercase',
padding: '7px 16px', borderRadius: 100, border: '2px solid #FFE071',
}}>
🚀 Join 50K+ vibing
</span>
<h3 style={{
margin: '0 0 14px', position: 'relative',
fontSize: 'clamp(1.7rem, 3.6vw, 2.7rem)', fontWeight: 900,
lineHeight: 1.02, color: '#171512', letterSpacing: '-0.03em',
fontFamily: 'Sora, sans-serif',
}}>
Your life. Your Lyts.<br />Let&apos;s get it.
</h3>
<p <p
style={{ style={{
margin: '0 0 28px', position: 'relative', margin: '0 auto 24px', maxWidth: 460, position: 'relative',
fontSize: 'clamp(1.05rem, 1.6vw, 1.4rem)', fontWeight: 600, fontSize: 'clamp(0.95rem, 1.3vw, 1.1rem)', fontWeight: 600,
lineHeight: 1.6, color: 'rgba(255,255,255,0.85)', lineHeight: 1.55, color: 'rgba(23,21,18,0.72)',
fontFamily: 'Sora, sans-serif', letterSpacing: '-0.01em', fontFamily: 'Sora, sans-serif',
}} }}
> >
The more you live, the more you earn. Every step, every visit, and every adventure brings you closer to your next reward. The more you live, the more you earn every step, visit, and adventure drops fresh Lyts straight into your pocket.
</p> </p>
{/* Logo in a sticker chip so it pops on the amber card */}
<div style={{ marginBottom: 22, position: 'relative' }}>
<span style={{
display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
padding: '9px 18px', background: '#ffffff',
border: '2.5px solid #171512', borderRadius: 16, boxShadow: '4px 4px 0 0 #171512',
}}>
{/* eslint-disable-next-line @next/next/no-img-element */}
<img src="/images/lyts.png" alt="LytsUp" style={{ height: 32, width: 'auto', display: 'block', objectFit: 'contain' }} />
</span>
</div>
<Link <Link
ref={ctaRef} ref={ctaRef}
href="/contacts" href="/contacts"
style={{ style={{
display: 'inline-flex', alignItems: 'center', gap: 10, position: 'relative', display: 'inline-flex', alignItems: 'center', gap: 10, position: 'relative',
padding: '15px 34px', borderRadius: 100, padding: '16px 38px', borderRadius: 100,
fontSize: '1rem', fontWeight: 800, fontFamily: 'Sora, sans-serif', fontSize: '1.05rem', fontWeight: 800, fontFamily: 'Sora, sans-serif',
color: '#171512', textDecoration: 'none', color: '#FFE071', textDecoration: 'none',
background: 'linear-gradient(135deg, #f4be28 0%, #FF9800 100%)', background: '#171512', border: '2.5px solid #171512',
boxShadow: '0 16px 40px -12px rgba(244,190,40,0.5)', boxShadow: '5px 5px 0 0 rgba(23,21,18,0.3)',
}} }}
> >
Download LytsUp Download
<svg width="17" height="17" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.6" strokeLinecap="round" strokeLinejoin="round"> <svg width="17" height="17" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.6" strokeLinecap="round" strokeLinejoin="round">
<path d="M14 5l7 7m0 0l-7 7m7-7H3" /> <path d="M14 5l7 7m0 0l-7 7m7-7H3" />
</svg> </svg>
@@ -352,8 +434,73 @@ export default function LytsUpSection({ isLoaded = true }: LytsUpSectionProps) {
0%, 100% { transform: scale(1) rotate(0deg); } 0%, 100% { transform: scale(1) rotate(0deg); }
50% { transform: scale(1.25) rotate(-12deg); } 50% { transform: scale(1.25) rotate(-12deg); }
} }
/* Live pulsing dot on the eyebrow badge */
.lytsup-live-dot { animation: lytsupPulse 1.8s ease-out infinite; }
@keyframes lytsupPulse {
0% { box-shadow: 0 0 0 0 rgba(244,190,40,0.6); }
70% { box-shadow: 0 0 0 8px rgba(244,190,40,0); }
100% { box-shadow: 0 0 0 0 rgba(244,190,40,0); }
}
/* Vibe tags */
.lytsup-tag { transition: background 0.25s ease, border-color 0.25s ease, color 0.25s ease, transform 0.25s ease; cursor: default; }
.lytsup-tag:hover {
background: rgba(244,190,40,0.12);
border-color: rgba(244,190,40,0.45);
color: #ffffff;
transform: translateY(-2px);
}
/* Scrolling gradient marquee */
.lytsup-marquee {
overflow: hidden;
margin: 10px 0 46px;
-webkit-mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);
mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);
}
.lytsup-marquee-track {
display: inline-flex;
gap: 2.5rem;
white-space: nowrap;
will-change: transform;
animation: lytsupMarquee 24s linear infinite;
}
@keyframes lytsupMarquee {
from { transform: translateX(0); }
to { transform: translateX(-50%); }
}
.lytsup-marquee-item {
font-family: 'Sora', sans-serif;
font-weight: 900;
font-size: clamp(1.1rem, 2vw, 1.7rem);
letter-spacing: -0.02em;
text-transform: uppercase;
background: linear-gradient(135deg, #f4be28 0%, #FF9800 100%);
-webkit-background-clip: text;
background-clip: text;
-webkit-text-fill-color: transparent;
}
.lytsup-marquee-star {
color: rgba(244,190,40,0.5);
font-size: clamp(0.9rem, 1.4vw, 1.2rem);
}
/* Funky sticker emojis bob gently */
.lytsup-sticker-emoji { animation: lytsupBob 3.2s ease-in-out infinite; }
.lytsup-sticker-emoji:nth-of-type(2) { animation-delay: 0.5s; }
.lytsup-sticker-emoji:nth-of-type(3) { animation-delay: 1s; }
.lytsup-sticker-emoji:nth-of-type(4) { animation-delay: 1.5s; }
@keyframes lytsupBob {
0%, 100% { margin-top: 0; }
50% { margin-top: -7px; }
}
@media (prefers-reduced-motion: reduce) { @media (prefers-reduced-motion: reduce) {
.lytsup-sticker-spark { animation: none; } .lytsup-sticker-spark,
.lytsup-live-dot,
.lytsup-marquee-track,
.lytsup-sticker-emoji { animation: none; }
} }
@media (max-width: 900px) { @media (max-width: 900px) {
.lytsup-flow { max-width: 380px !important; } .lytsup-flow { max-width: 380px !important; }

View File

@@ -22,7 +22,7 @@ const DARK_CARDS = [
description: 'No compelling reason for customers to visit your store', description: 'No compelling reason for customers to visit your store',
image: '/problems/4.png', image: '/problems/4.png',
icon: ( icon: (
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#ef4444" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round" style={{ marginBottom: 12 }}> <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#ef4444" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round">
<circle cx="12" cy="12" r="10" /><line x1="4.93" y1="4.93" x2="19.07" y2="19.07" /> <circle cx="12" cy="12" r="10" /><line x1="4.93" y1="4.93" x2="19.07" y2="19.07" />
</svg> </svg>
), ),
@@ -32,7 +32,7 @@ const DARK_CARDS = [
description: 'Traditional discounts erode profit margins', description: 'Traditional discounts erode profit margins',
image: '/problems/5.png', image: '/problems/5.png',
icon: ( icon: (
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#ef4444" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round" style={{ marginBottom: 12 }}> <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#ef4444" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round">
<polyline points="23 18 13.5 8.5 8.5 13.5 1 6" /><polyline points="17 18 23 18 23 12" /> <polyline points="23 18 13.5 8.5 8.5 13.5 1 6" /><polyline points="17 18 23 18 23 12" />
</svg> </svg>
), ),
@@ -42,28 +42,28 @@ const DARK_CARDS = [
description: 'Digital ads rarely convert into store footfall', description: 'Digital ads rarely convert into store footfall',
image: '/problems/6.png', image: '/problems/6.png',
icon: ( icon: (
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#ef4444" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round" style={{ marginBottom: 12 }}> <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#ef4444" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round">
<path d="M11 5L6 9H2v6h4l5 4V5z" /><path d="M19.07 4.93a10 10 0 0 1 0 14.14M15.54 8.46a5 5 0 0 1 0 7.07" /> <path d="M11 5L6 9H2v6h4l5 4V5z" /><path d="M19.07 4.93a10 10 0 0 1 0 14.14M15.54 8.46a5 5 0 0 1 0 7.07" />
</svg> </svg>
), ),
}, },
{ {
title: 'No Real-Time Signal', title: 'No Real-Time Signals',
description: 'No real-time connection between online activity and offline shopping', description: 'No real-time connection between online activity and offline shopping',
image: '/problems/7.png', image: '/problems/7.png',
wide: true, wide: true,
icon: ( icon: (
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#ef4444" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round" style={{ marginBottom: 12 }}> <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#ef4444" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round">
<line x1="1" y1="1" x2="23" y2="23" /><path d="M16.72 11.06A10.94 10.94 0 0 1 19 12.5M5 12.5a10.94 10.94 0 0 1 5.83-2.84M8.59 16.11a5.11 5.11 0 0 1 6.82 0" /><line x1="12" y1="20" x2="12.01" y2="20" /> <line x1="1" y1="1" x2="23" y2="23" /><path d="M16.72 11.06A10.94 10.94 0 0 1 19 12.5M5 12.5a10.94 10.94 0 0 1 5.83-2.84M8.59 16.11a5.11 5.11 0 0 1 6.82 0" /><line x1="12" y1="20" x2="12.01" y2="20" />
</svg> </svg>
), ),
}, },
{ {
title: 'Customer Amnesia', title: 'Customer Amnesia',
description: 'Customers forget about stores between visits', description: 'Customers forget about brands between visits',
image: '/problems/8.png', image: '/problems/8.png',
icon: ( icon: (
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#ef4444" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round" style={{ marginBottom: 12 }}> <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#ef4444" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round">
<circle cx="12" cy="12" r="10" /><path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3" /><line x1="12" y1="17" x2="12.01" y2="17" /> <circle cx="12" cy="12" r="10" /><path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3" /><line x1="12" y1="17" x2="12.01" y2="17" />
</svg> </svg>
), ),
@@ -162,18 +162,45 @@ export default function ProblemSection({ isLoaded = true }: ProblemSectionProps)
gap: 'clamp(8px, 1.2vw, 14px)', 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: '$2 Tn', label: 'Indian retail market by 2032, 26% CAGR',
{ val: '10%', label: "Of India's GDP from retail" }, icon: (<><line x1="12" y1="1" x2="12" y2="23" /><path d="M17 5H9.5a3.5 3.5 0 0 0 0 7h5a3.5 3.5 0 0 1 0 7H6" /></>),
{ val: '12%', label: 'Of retail is organised, the rest is offline' }, },
{ val: '500M', label: 'Indians shopping online by 2030, up from 220M' }, {
val: '5th', label: 'Largest retail destination globally',
icon: (<><circle cx="12" cy="12" r="10" /><line x1="2" y1="12" x2="22" y2="12" /><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z" /></>),
},
{
val: '10%', label: "Of India's GDP from retail",
icon: (<><path d="M21.21 15.89A10 10 0 1 1 8 2.83" /><path d="M22 12A10 10 0 0 0 12 2v10z" /></>),
},
{
val: '12%', label: 'Of retail is organized, the rest is offline',
icon: (<><path d="M3 9l1.5-5h15L21 9" /><path d="M5 9v10a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1V9" /><path d="M9 21v-6h6v6" /></>),
},
{
val: '500M', label: "India's online shoppers by 2030, up from 250M",
icon: (<><polyline points="23 6 13.5 16.5 8.5 11.5 1 19" /><polyline points="17 6 23 6 23 12" /></>),
},
].map((s, i) => ( ].map((s, i) => (
<div key={i} style={{ <div key={i} className="problem-india-stat" style={{
padding: 'clamp(14px, 1.8vw, 20px)', borderRadius: 16, padding: 'clamp(14px, 1.8vw, 20px)', borderRadius: 16,
background: '#f9f7f2', border: '1px solid rgba(23,21,18,0.08)', background: '#f9f7f2', border: '1px solid rgba(23,21,18,0.08)',
}}> }}>
<div style={{ display: 'flex', alignItems: 'center', gap: 10, marginBottom: 10 }}>
<span style={{
width: 38, height: 38, borderRadius: '50%', flexShrink: 0,
display: 'flex', alignItems: 'center', justifyContent: 'center',
background: 'linear-gradient(150deg, #ee3a34 0%, #c81e1e 100%)',
boxShadow: '0 6px 14px -6px rgba(200,30,30,0.6)',
}}>
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#ffffff" strokeWidth="2.3" strokeLinecap="round" strokeLinejoin="round">
{s.icon}
</svg>
</span>
<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={{ 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 style={{ fontSize: '0.72rem', color: '#4f463a', fontFamily: 'Sora, sans-serif', lineHeight: 1.4 }}>{s.label}</div>
</div> </div>
))} ))}
</div> </div>
@@ -196,28 +223,25 @@ export default function ProblemSection({ isLoaded = true }: ProblemSectionProps)
clickEffect={true} clickEffect={true}
particleCount={6} particleCount={6}
style={{ style={{
background: '#e12d2d',
borderRadius: '24px', borderRadius: '24px',
padding: 'clamp(20px, 2.4vw, 28px)', padding: 'clamp(20px, 2.4vw, 28px)',
border: '1px solid rgba(255, 255, 255, 0.15)',
display: 'flex', display: 'flex',
alignItems: 'center', alignItems: 'center',
justifyContent: 'space-between', justifyContent: 'space-between',
minHeight: '230px', minHeight: '230px',
boxShadow: '0 10px 30px -12px rgba(225, 45, 45, 0.4)',
position: 'relative', position: 'relative',
overflow: 'hidden', overflow: 'hidden',
}} }}
> >
<div style={{ width: '60%', paddingRight: '12px', position: 'relative', zIndex: 2 }}> <div className="problem-stat-text" style={{ width: '60%', paddingRight: '12px', position: 'relative', zIndex: 2 }}>
<div style={{ fontSize: 'clamp(2rem, 3.2vw, 3rem)', fontWeight: 900, color: '#ffffff', fontFamily: 'Sora, sans-serif', letterSpacing: '-0.03em', lineHeight: 1 }}> <div style={{ fontSize: 'clamp(2rem, 3.2vw, 3rem)', fontWeight: 900, color: '#ffffff', fontFamily: 'Sora, sans-serif', letterSpacing: '-0.03em', lineHeight: 1 }}>
68%+ 68%<span style={{ color: '#ffd27a' }}>+</span>
</div> </div>
<div style={{ marginTop: 8, fontSize: '0.75rem', fontWeight: 800, color: '#ffffff', fontFamily: 'Sora, sans-serif', textTransform: 'uppercase', letterSpacing: '0.06em', lineHeight: 1.3 }}> <div style={{ marginTop: 8, fontSize: '0.75rem', fontWeight: 800, color: '#ffffff', fontFamily: 'Sora, sans-serif', textTransform: 'uppercase', letterSpacing: '0.06em', lineHeight: 1.3 }}>
Walk in once,<br />never return Walk in once,<br />never return
</div> </div>
</div> </div>
<div style={{ <div className="problem-stat-art" style={{
position: 'absolute', position: 'absolute',
right: '-18px', right: '-18px',
bottom: '-18px', bottom: '-18px',
@@ -251,28 +275,25 @@ export default function ProblemSection({ isLoaded = true }: ProblemSectionProps)
clickEffect={true} clickEffect={true}
particleCount={6} particleCount={6}
style={{ style={{
background: '#e12d2d',
borderRadius: '24px', borderRadius: '24px',
padding: 'clamp(20px, 2.4vw, 28px)', padding: 'clamp(20px, 2.4vw, 28px)',
border: '1px solid rgba(255, 255, 255, 0.15)',
display: 'flex', display: 'flex',
alignItems: 'center', alignItems: 'center',
justifyContent: 'space-between', justifyContent: 'space-between',
minHeight: '230px', minHeight: '230px',
boxShadow: '0 10px 30px -12px rgba(225, 45, 45, 0.4)',
position: 'relative', position: 'relative',
overflow: 'hidden', overflow: 'hidden',
}} }}
> >
<div style={{ width: '60%', paddingRight: '12px', position: 'relative', zIndex: 2 }}> <div className="problem-stat-text" style={{ width: '60%', paddingRight: '12px', position: 'relative', zIndex: 2 }}>
<div style={{ fontSize: 'clamp(2rem, 3.2vw, 3rem)', fontWeight: 900, color: '#ffffff', fontFamily: 'Sora, sans-serif', letterSpacing: '-0.03em', lineHeight: 1 }}> <div style={{ fontSize: 'clamp(2rem, 3.2vw, 3rem)', fontWeight: 900, color: '#ffffff', fontFamily: 'Sora, sans-serif', letterSpacing: '-0.03em', lineHeight: 1 }}>
0+ 0<span style={{ color: '#ffd27a' }}>+</span>
</div> </div>
<div style={{ marginTop: 8, fontSize: '0.75rem', fontWeight: 800, color: '#ffffff', fontFamily: 'Sora, sans-serif', textTransform: 'uppercase', letterSpacing: '0.06em', lineHeight: 1.3 }}> <div style={{ marginTop: 8, fontSize: '0.75rem', fontWeight: 800, color: '#ffffff', fontFamily: 'Sora, sans-serif', textTransform: 'uppercase', letterSpacing: '0.06em', lineHeight: 1.3 }}>
Visibility<br />after they leave Visibility<br />after they leave
</div> </div>
</div> </div>
<div style={{ <div className="problem-stat-art" style={{
position: 'absolute', position: 'absolute',
right: '-18px', right: '-18px',
bottom: '-18px', bottom: '-18px',
@@ -306,28 +327,25 @@ export default function ProblemSection({ isLoaded = true }: ProblemSectionProps)
clickEffect={true} clickEffect={true}
particleCount={6} particleCount={6}
style={{ style={{
background: '#e12d2d',
borderRadius: '24px', borderRadius: '24px',
padding: 'clamp(20px, 2.4vw, 28px)', padding: 'clamp(20px, 2.4vw, 28px)',
border: '1px solid rgba(255, 255, 255, 0.15)',
display: 'flex', display: 'flex',
alignItems: 'center', alignItems: 'center',
justifyContent: 'space-between', justifyContent: 'space-between',
minHeight: '230px', minHeight: '230px',
boxShadow: '0 10px 30px -12px rgba(225, 45, 45, 0.4)',
position: 'relative', position: 'relative',
overflow: 'hidden', overflow: 'hidden',
}} }}
> >
<div style={{ width: '60%', paddingRight: '12px', position: 'relative', zIndex: 2 }}> <div className="problem-stat-text" style={{ width: '60%', paddingRight: '12px', position: 'relative', zIndex: 2 }}>
<div style={{ fontSize: 'clamp(2rem, 3.2vw, 3rem)', fontWeight: 900, color: '#ffffff', fontFamily: 'Sora, sans-serif', letterSpacing: '-0.03em', lineHeight: 1 }}> <div style={{ fontSize: 'clamp(2rem, 3.2vw, 3rem)', fontWeight: 900, color: '#ffffff', fontFamily: 'Sora, sans-serif', letterSpacing: '-0.03em', lineHeight: 1 }}>
5+ 5<span style={{ color: '#ffd27a' }}>+</span>
</div> </div>
<div style={{ marginTop: 8, fontSize: '0.75rem', fontWeight: 800, color: '#ffffff', fontFamily: 'Sora, sans-serif', textTransform: 'uppercase', letterSpacing: '0.06em', lineHeight: 1.3 }}> <div style={{ marginTop: 8, fontSize: '0.75rem', fontWeight: 800, color: '#ffffff', fontFamily: 'Sora, sans-serif', textTransform: 'uppercase', letterSpacing: '0.06em', lineHeight: 1.3 }}>
Recurring pain points,<br />every quarter Recurring pain points,<br />every quarter
</div> </div>
</div> </div>
<div style={{ <div className="problem-stat-art" style={{
position: 'absolute', position: 'absolute',
right: '-18px', right: '-18px',
bottom: '-18px', bottom: '-18px',
@@ -365,10 +383,8 @@ export default function ProblemSection({ isLoaded = true }: ProblemSectionProps)
clickEffect={true} clickEffect={true}
particleCount={6} particleCount={6}
style={{ style={{
background: '#171512',
borderRadius: '24px', borderRadius: '24px',
padding: 'clamp(20px, 2.4vw, 28px)', padding: 'clamp(20px, 2.4vw, 28px)',
border: '1px solid rgba(255, 255, 255, 0.12)',
display: 'flex', display: 'flex',
alignItems: 'center', alignItems: 'center',
justifyContent: 'space-between', justifyContent: 'space-between',
@@ -377,8 +393,8 @@ export default function ProblemSection({ isLoaded = true }: ProblemSectionProps)
overflow: 'hidden', overflow: 'hidden',
}} }}
> >
<div style={{ width: card.wide ? '42%' : '52%', paddingRight: '12px', position: 'relative', zIndex: 2 }}> <div className="problem-card-text" style={{ width: card.wide ? '42%' : '52%', paddingRight: '12px', position: 'relative', zIndex: 2 }}>
{card.icon} <div className="problem-icon-chip">{card.icon}</div>
<h3 style={{ fontSize: '1.1rem', fontWeight: 800, color: '#ffffff', fontFamily: 'Sora, sans-serif', margin: '0 0 6px' }}> <h3 style={{ fontSize: '1.1rem', fontWeight: 800, color: '#ffffff', fontFamily: 'Sora, sans-serif', margin: '0 0 6px' }}>
{card.title} {card.title}
</h3> </h3>
@@ -387,7 +403,7 @@ export default function ProblemSection({ isLoaded = true }: ProblemSectionProps)
</p> </p>
</div> </div>
{card.wide ? ( {card.wide ? (
<div style={{ <div className="problem-card-art problem-card-art--wide" style={{
position: 'absolute', position: 'absolute',
right: '-6px', right: '-6px',
bottom: '-6px', bottom: '-6px',
@@ -410,7 +426,7 @@ export default function ProblemSection({ isLoaded = true }: ProblemSectionProps)
/> />
</div> </div>
) : ( ) : (
<div style={{ <div className="problem-card-art" style={{
position: 'absolute', position: 'absolute',
right: '-22px', right: '-22px',
bottom: '-22px', bottom: '-22px',
@@ -440,6 +456,86 @@ export default function ProblemSection({ isLoaded = true }: ProblemSectionProps)
</div> </div>
<style>{` <style>{`
/* Shared modern card surface treatment */
.problem-stat-chip, .dark-bento-card {
transition: border-color 0.3s ease, box-shadow 0.4s ease;
}
/* Glassy top-edge highlight for a crisp, premium finish */
.problem-stat-chip::before, .dark-bento-card::before {
content: '';
position: absolute;
inset: 0;
border-radius: inherit;
padding: 1px;
background: linear-gradient(180deg, rgba(255,255,255,0.18), rgba(255,255,255,0) 42%);
-webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
-webkit-mask-composite: xor;
mask-composite: exclude;
pointer-events: none;
z-index: 3;
}
.problem-stat-chip {
background:
radial-gradient(130% 130% at 12% 8%, rgba(255,255,255,0.22) 0%, rgba(255,255,255,0) 46%),
linear-gradient(150deg, #f24a3d 0%, #dc2323 52%, #a81515 100%);
border: 1px solid rgba(255, 255, 255, 0.16);
box-shadow:
0 20px 48px -20px rgba(178, 20, 20, 0.6),
inset 0 1px 0 rgba(255,255,255,0.16);
}
.problem-stat-chip:hover {
border-color: rgba(255, 255, 255, 0.32);
box-shadow:
0 30px 62px -22px rgba(178, 20, 20, 0.68),
inset 0 1px 0 rgba(255,255,255,0.18);
}
/* Depth on the big stat number */
.problem-stat-chip .problem-stat-text > div:first-child {
text-shadow: 0 2px 12px rgba(120, 0, 0, 0.38);
}
/* Gold divider between the number and its label */
.problem-stat-chip .problem-stat-text > div:nth-child(2)::before {
content: '';
display: block;
width: 26px;
height: 2px;
border-radius: 2px;
background: #ffd27a;
opacity: 0.9;
margin: 4px 0 10px;
}
.dark-bento-card {
background: linear-gradient(160deg, #1d1b17 0%, #131210 100%);
border: 1px solid rgba(255, 255, 255, 0.08);
box-shadow: 0 16px 40px -18px rgba(0,0,0,0.6);
}
.dark-bento-card:hover {
border-color: rgba(239, 68, 68, 0.28);
box-shadow: 0 26px 54px -20px rgba(0,0,0,0.62);
}
/* Icon chip on the dark bento cards */
.problem-icon-chip {
width: 46px;
height: 46px;
border-radius: 13px;
margin-bottom: 16px;
display: flex;
align-items: center;
justify-content: center;
background: rgba(239, 68, 68, 0.12);
border: 1px solid rgba(239, 68, 68, 0.24);
box-shadow: inset 0 1px 0 rgba(255,255,255,0.06);
}
.problem-india-stat {
transition: border-color 0.3s ease, box-shadow 0.3s ease, transform 0.3s cubic-bezier(0.22,1,0.36,1);
}
.problem-india-stat:hover {
border-color: rgba(239, 68, 68, 0.35);
box-shadow: 0 14px 30px -18px rgba(23,21,18,0.28);
transform: translateY(-3px);
}
.dark-bento-grid { .dark-bento-grid {
display: grid; display: grid;
grid-template-columns: repeat(3, 1fr); grid-template-columns: repeat(3, 1fr);
@@ -448,6 +544,48 @@ export default function ProblemSection({ isLoaded = true }: ProblemSectionProps)
.dark-bento-card-4 { grid-column: span 2; } .dark-bento-card-4 { grid-column: span 2; }
.dark-bento-card-5 { grid-column: span 1; } .dark-bento-card-5 { grid-column: span 1; }
/* Mobile: papercraft art was overflowing onto the copy — pin it small
to the bottom-right corner and give the text room to breathe */
@media (max-width: 640px) {
/* Tighten the tall cards so art + copy fill them instead of leaving gaps */
#problem .problem-stat-chip { min-height: 190px !important; }
#problem .dark-bento-card { min-height: 210px !important; }
#problem .problem-stat-text {
width: 50% !important;
padding-right: 8px !important;
}
#problem .problem-card-text {
width: 56% !important;
padding-right: 8px !important;
}
/* Red stat art — larger, anchored to the corner so it reads clearly */
#problem .problem-stat-art {
width: 58% !important;
height: 96% !important;
right: -8px !important;
bottom: -8px !important;
}
#problem .problem-card-art {
width: 54% !important;
height: 74% !important;
right: -10px !important;
bottom: -10px !important;
}
/* Wide card (No Real-Time Signal) mobile art + copy sizing lives in
globals.css — kept there so it reliably reloads (see comment there) */
#problem .problem-stat-art img {
transform: scale(1.55) !important;
object-fit: contain !important;
object-position: bottom right !important;
}
#problem .problem-card-art img {
transform: scale(1.65) !important;
object-fit: contain !important;
object-position: bottom right !important;
}
}
@media (max-width: 900px) { @media (max-width: 900px) {
#problem .problem-header-grid { grid-template-columns: 1fr; } #problem .problem-header-grid { grid-template-columns: 1fr; }
#problem .problem-header-right { border-left: none; padding-left: 0; border-top: 2px solid rgba(23,21,18,0.1); padding-top: 20px; margin-top: 20px; } #problem .problem-header-right { border-left: none; padding-left: 0; border-top: 2px solid rgba(23,21,18,0.1); padding-top: 20px; margin-top: 20px; }

View File

@@ -33,7 +33,7 @@ const PRODUCTS: Product[] = [
'AI powered footfall analytics and behavioral intelligence. Understand how customers move, dwell, and engage, turning raw foot traffic into rich, actionable insights.', 'AI powered footfall analytics and behavioral intelligence. Understand how customers move, dwell, and engage, turning raw foot traffic into rich, actionable insights.',
accent: '#f4be28', accent: '#f4be28',
accentRgb: '244, 190, 40', accentRgb: '244, 190, 40',
tags: ['Footfall Tracking', 'Heatmaps', 'Behavior Analysis'], tags: ['Footfall Tracking', 'Behavior Analysis'],
}, },
{ {
id: 2, id: 2,
@@ -63,10 +63,10 @@ const PRODUCTS: Product[] = [
title: 'Identiq', title: 'Identiq',
subtitle: 'Consumer Loyalty Platform', subtitle: 'Consumer Loyalty Platform',
description: description:
'Earn LYTs through daily logins and games, then redeem rewards at real offline stores.', 'Earn LYTs through daily logins and games, then redeem Lyts at real offline stores.',
accent: '#f4be28', accent: '#f4be28',
accentRgb: '244, 190, 40', accentRgb: '244, 190, 40',
tags: ['Daily Rewards', 'Game Based Offers', 'Offline Redemption'], tags: ['Daily Lyts', 'Game Based Offers', 'Offline Redemption'],
}, },
]; ];
@@ -272,9 +272,9 @@ function ProductVisual({ product }: { product: Product }) {
<span style={{ <span style={{
width: 34, height: 34, borderRadius: '50%', display: 'flex', alignItems: 'center', justifyContent: 'center', width: 34, height: 34, borderRadius: '50%', display: 'flex', alignItems: 'center', justifyContent: 'center',
background: `linear-gradient(135deg, ${accent} 0%, #e09820 100%)`, color: '#111', fontWeight: 800, fontSize: 13, fontFamily: 'Sora, sans-serif', background: `linear-gradient(135deg, ${accent} 0%, #e09820 100%)`, color: '#111', fontWeight: 800, fontSize: 13, fontFamily: 'Sora, sans-serif',
}}>A</span> }}>L</span>
<div> <div>
<div style={{ fontSize: 13, fontWeight: 800, color: '#fff', fontFamily: 'Sora, sans-serif', lineHeight: 1.1 }}>Loyaly</div> <div style={{ fontSize: 13, fontWeight: 800, color: '#fff', fontFamily: 'Sora, sans-serif', lineHeight: 1.1 }}>LytsUp</div>
<div style={{ fontSize: 10, color: 'rgba(255,255,255,0.4)', fontFamily: 'Sora, sans-serif' }}>Member since 2024</div> <div style={{ fontSize: 10, color: 'rgba(255,255,255,0.4)', fontFamily: 'Sora, sans-serif' }}>Member since 2024</div>
</div> </div>
</div> </div>
@@ -288,7 +288,7 @@ function ProductVisual({ product }: { product: Product }) {
<div className="pv-sheen" /> <div className="pv-sheen" />
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start' }}> <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start' }}>
<div> <div>
<div style={{ fontSize: 10, fontWeight: 700, letterSpacing: '0.1em', textTransform: 'uppercase', color: 'rgba(0,0,0,0.6)', fontFamily: 'Sora, sans-serif' }}>Reward LYTs</div> <div style={{ fontSize: 10, fontWeight: 700, letterSpacing: '0.1em', textTransform: 'uppercase', color: 'rgba(0,0,0,0.6)', fontFamily: 'Sora, sans-serif' }}>Lyts Balance</div>
<div style={{ fontSize: 32, fontWeight: 900, color: '#111', fontFamily: 'Sora, sans-serif', letterSpacing: '-0.03em', marginTop: 2 }}>284</div> <div style={{ fontSize: 32, fontWeight: 900, color: '#111', fontFamily: 'Sora, sans-serif', letterSpacing: '-0.03em', marginTop: 2 }}>284</div>
</div> </div>
<span style={{ width: 34, height: 34, borderRadius: 10, background: 'rgba(255,255,255,0.35)', display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: 15, fontWeight: 900, color: '#111', fontFamily: 'Sora, sans-serif' }}></span> <span style={{ width: 34, height: 34, borderRadius: 10, background: 'rgba(255,255,255,0.35)', display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: 15, fontWeight: 900, color: '#111', fontFamily: 'Sora, sans-serif' }}></span>

View File

@@ -19,25 +19,28 @@ interface ShiftSectionProps {
const GREEN_CARDS = [ const GREEN_CARDS = [
{ {
value: '3.4x', value: '3.4x',
label: 'MORE REPEAT VISITS', label: 'MORE RETURN VISITS',
description: 'Businesses using LYTs see customers come back more often and stay engaged longer.',
image: '/shift/1.png', image: '/shift/1.png',
}, },
{ {
value: '20%', value: '20%',
label: 'LIVE IN-APP OFFER', label: 'MORE CUSTOMER ENGAGEMENT',
description: 'AI-powered LYT experiences turn everyday shopping into something worth coming back for.',
image: '/shift/2.png', image: '/shift/2.png',
}, },
{ {
value: '5', value: '5',
label: "EVERYDAY MOMENTS,\nTURNED INTO LOYALTY", label: 'LYT EXPERIENCES EVERY DAY',
description: 'From check-ins to surprise drops, there is always a new way to earn LYTs.',
image: '/shift/3.png', image: '/shift/3.png',
}, },
]; ];
const BLACK_CARDS = [ const BLACK_CARDS = [
{ {
title: 'Earn Daily', title: 'Earn LYTs',
description: 'Customers earn LYTs through daily app activities', description: 'Every visit, check-in, and interaction helps you stack more LYTs.',
icon: ( icon: (
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#22c55e" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"> <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#22c55e" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round">
<rect x="3" y="4" width="18" height="18" rx="2" ry="2"></rect> <rect x="3" y="4" width="18" height="18" rx="2" ry="2"></rect>
@@ -49,8 +52,8 @@ const BLACK_CARDS = [
image: '/shift/4.png', image: '/shift/4.png',
}, },
{ {
title: 'Game Campaigns', title: 'LYT Challenges',
description: 'Game-based campaigns drive footfall with excitement', description: 'Complete missions, discover new places, and unlock exclusive experiences.',
icon: ( icon: (
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#22c55e" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"> <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#22c55e" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round">
<line x1="6" y1="12" x2="10" y2="12"></line> <line x1="6" y1="12" x2="10" y2="12"></line>
@@ -63,8 +66,8 @@ const BLACK_CARDS = [
image: '/shift/5.png', image: '/shift/5.png',
}, },
{ {
title: 'Smart Coupons', title: 'LYT Drops',
description: 'Smart surprise coupons create a daily reason to engage', description: 'AI delivers personalized drops and surprises when they matter most.',
icon: ( icon: (
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#22c55e" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"> <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#22c55e" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round">
<path d="M20.59 13.41l-7.17 7.17a2 2 0 0 1-2.83 0L2 12V2h10l8.59 8.59a2 2 0 0 1 0 2.82z"></path> <path d="M20.59 13.41l-7.17 7.17a2 2 0 0 1-2.83 0L2 12V2h10l8.59 8.59a2 2 0 0 1 0 2.82z"></path>
@@ -74,8 +77,8 @@ const BLACK_CARDS = [
image: '/shift/6.png', image: '/shift/6.png',
}, },
{ {
title: 'Live Discovery', title: 'Discover Nearby',
description: 'Real-time discovery of nearby stores and live offers', description: 'Explore local businesses, trending places, and experiences happening around you.',
icon: ( icon: (
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#22c55e" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"> <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#22c55e" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round">
<path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z"></path> <path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z"></path>
@@ -85,8 +88,8 @@ const BLACK_CARDS = [
image: '/shift/7.png', image: '/shift/7.png',
}, },
{ {
title: 'Deepens Loyalty', title: 'Get LIT',
description: 'Every store visit earns more rewards and deepens loyalty', description: 'Spend your LYTs on experiences, unlock perks, and level up your shopping journey.',
icon: ( icon: (
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#22c55e" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"> <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#22c55e" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round">
<polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"></polygon> <polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"></polygon>
@@ -182,7 +185,7 @@ export default function ShiftSection({ isLoaded = true }: ShiftSectionProps) {
<div className="shift-header-right" style={{ paddingBottom: 'clamp(4px, 1vw, 10px)', borderLeft: `2px solid ${accent}44`, paddingLeft: 'clamp(20px, 2.4vw, 32px)' }}> <div className="shift-header-right" style={{ paddingBottom: 'clamp(4px, 1vw, 10px)', borderLeft: `2px solid ${accent}44`, paddingLeft: 'clamp(20px, 2.4vw, 32px)' }}>
<p className="shift-subtitle" style={{ color: '#4f463a', fontSize: 'clamp(1rem, 1.2vw, 1.15rem)', fontWeight: 500, margin: 0, lineHeight: 1.7, fontFamily: 'Sora, sans-serif' }}> <p className="shift-subtitle" style={{ color: '#4f463a', fontSize: 'clamp(1rem, 1.2vw, 1.15rem)', fontWeight: 500, margin: 0, lineHeight: 1.7, fontFamily: 'Sora, sans-serif' }}>
Loyaly bridges digital engagement and offline shopping, with daily rewards, interactive games, and surprise coupons redeemable in person. Loyaly bridges digital engagement and offline shopping, with daily Lyts, interactive games, and surprise coupons redeemable in person.
</p> </p>
</div> </div>
</div> </div>
@@ -201,35 +204,48 @@ export default function ShiftSection({ isLoaded = true }: ShiftSectionProps) {
clickEffect={true} clickEffect={true}
particleCount={6} particleCount={6}
> >
<div style={{ position: 'relative', zIndex: 2, width: '52%', display: 'flex', flexDirection: 'column', height: '100%', justifyContent: 'space-between' }}> <div style={{ position: 'relative', zIndex: 2, width: '62%', display: 'flex', flexDirection: 'column', height: '100%', justifyContent: 'flex-start' }}>
<div style={{ display: 'flex', alignItems: 'baseline', gap: 1 }}> <div style={{ display: 'flex', alignItems: 'baseline', gap: 2 }}>
<span style={{ fontSize: 'clamp(2.5rem, 3.8vw, 3.5rem)', fontWeight: 900, color: '#ffffff', fontFamily: 'Sora, sans-serif', letterSpacing: '-0.03em', lineHeight: 1 }}> <span style={{ fontSize: 'clamp(2.6rem, 4vw, 3.6rem)', fontWeight: 900, color: '#ffffff', fontFamily: 'Sora, sans-serif', letterSpacing: '-0.04em', lineHeight: 1 }}>
{card.value}+ {card.value}
</span> </span>
<span style={{ fontSize: 'clamp(1.6rem, 2.4vw, 2.1rem)', fontWeight: 800, color: accent, fontFamily: 'Sora, sans-serif', lineHeight: 1 }}>+</span>
</div> </div>
<div style={{ marginTop: 18, maxWidth: '230px' }}>
<div style={{ <div style={{
marginTop: 'auto', fontSize: '0.7rem',
fontSize: '0.68rem',
fontWeight: 800, fontWeight: 800,
color: 'rgba(255, 255, 255, 0.8)', color: '#ffffff',
fontFamily: 'Sora, sans-serif', fontFamily: 'Sora, sans-serif',
textTransform: 'uppercase', textTransform: 'uppercase',
letterSpacing: '0.06em', letterSpacing: '0.07em',
lineHeight: 1.4, lineHeight: 1.35,
whiteSpace: 'pre-line', whiteSpace: 'pre-line',
maxWidth: '180px'
}}> }}>
{card.label} {card.label}
</div> </div>
<div style={{ width: 26, height: 2, borderRadius: 2, background: accent, margin: '10px 0 10px', opacity: 0.85 }} />
<p style={{
margin: 0,
fontSize: '0.74rem',
fontWeight: 500,
color: 'rgba(255, 255, 255, 0.66)',
fontFamily: 'Sora, sans-serif',
lineHeight: 1.5,
}}>
{card.description}
</p>
</div>
</div> </div>
{/* Papercraft Image */} {/* Papercraft Image */}
<div className="shift-card-art" style={{ <div className="shift-card-art" style={{
position: 'absolute', position: 'absolute',
right: i === 2 ? '-12px' : '-16px', right: '-14px',
bottom: i === 2 ? '-12px' : '-16px', bottom: '-14px',
width: i === 2 ? '56%' : '52%', width: i === 2 ? '46%' : '42%',
height: '90%', height: '82%',
opacity: 0.96,
pointerEvents: 'none', pointerEvents: 'none',
zIndex: 1, zIndex: 1,
}}> }}>
@@ -266,7 +282,13 @@ export default function ShiftSection({ isLoaded = true }: ShiftSectionProps) {
particleCount={6} particleCount={6}
> >
<div style={{ position: 'relative', zIndex: 2, width: cardNumber === 7 ? '36%' : (cardNumber === 8 ? '42%' : '48%'), display: 'flex', flexDirection: 'column', height: '100%' }}> <div style={{ position: 'relative', zIndex: 2, width: cardNumber === 7 ? '36%' : (cardNumber === 8 ? '42%' : '48%'), display: 'flex', flexDirection: 'column', height: '100%' }}>
<div style={{ color: iconAccent, marginBottom: 14, display: 'flex', alignItems: 'center' }}> <div style={{
width: 44, height: 44, borderRadius: 13, marginBottom: 16,
background: 'rgba(34,197,94,0.12)',
border: '1px solid rgba(34,197,94,0.22)',
boxShadow: 'inset 0 1px 0 rgba(255,255,255,0.06)',
color: iconAccent, display: 'flex', alignItems: 'center', justifyContent: 'center',
}}>
{card.icon} {card.icon}
</div> </div>
<h3 style={{ <h3 style={{
@@ -380,23 +402,40 @@ export default function ShiftSection({ isLoaded = true }: ShiftSectionProps) {
position: relative; position: relative;
overflow: hidden; overflow: hidden;
box-shadow: 0 4px 20px rgba(0,0,0,0.03); box-shadow: 0 4px 20px rgba(0,0,0,0.03);
transition: border-color 0.3s ease, box-shadow 0.3s ease; transition: border-color 0.3s ease, box-shadow 0.4s ease;
}
/* Glassy top highlight for a crisp, modern edge */
.shift-bento-card::before {
content: '';
position: absolute;
inset: 0;
border-radius: inherit;
padding: 1px;
background: linear-gradient(180deg, rgba(255,255,255,0.16), rgba(255,255,255,0) 42%);
-webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
-webkit-mask-composite: xor;
mask-composite: exclude;
pointer-events: none;
z-index: 3;
opacity: 0.9;
} }
.shift-bento-card--green { .shift-bento-card--green {
background: linear-gradient(135deg, #134e2e 0%, #0d3821 100%); background: linear-gradient(150deg, #1a6b3e 0%, #124a2b 52%, #0c3620 100%);
border: 1px solid rgba(255, 255, 255, 0.12); border: 1px solid rgba(255, 255, 255, 0.1);
box-shadow: 0 10px 30px -12px rgba(19, 78, 46, 0.35); box-shadow: 0 16px 40px -18px rgba(12, 54, 32, 0.55);
} }
.shift-bento-card--black { .shift-bento-card--black {
background: #171512; background: linear-gradient(160deg, #1d1b17 0%, #131210 100%);
border: 1px solid rgba(255, 255, 255, 0.08); border: 1px solid rgba(255, 255, 255, 0.07);
box-shadow: 0 10px 30px -12px rgba(0,0,0,0.5); box-shadow: 0 16px 40px -18px rgba(0,0,0,0.6);
} }
.shift-bento-card--green:hover { .shift-bento-card--green:hover {
border-color: rgba(255, 255, 255, 0.24); border-color: rgba(255, 255, 255, 0.22);
box-shadow: 0 26px 54px -20px rgba(12, 54, 32, 0.6);
} }
.shift-bento-card--black:hover { .shift-bento-card--black:hover {
border-color: rgba(255, 255, 255, 0.16); border-color: rgba(34, 197, 94, 0.28);
box-shadow: 0 26px 54px -20px rgba(0,0,0,0.62);
} }
/* Card column mappings */ /* Card column mappings */
@@ -437,15 +476,16 @@ export default function ShiftSection({ isLoaded = true }: ShiftSectionProps) {
/* Pin card art to the bottom-right corner on narrow screens, /* Pin card art to the bottom-right corner on narrow screens,
where full-width cards would otherwise let it sprawl over the text */ where full-width cards would otherwise let it sprawl over the text */
#shift .shift-card-art { #shift .shift-card-art {
width: 62% !important; width: 56% !important;
height: 100% !important; height: 66% !important;
right: 0 !important; right: 0 !important;
bottom: 0 !important; bottom: 0 !important;
} }
#shift .shift-card-art-img { #shift .shift-card-art-img {
object-fit: contain !important; object-fit: contain !important;
object-position: bottom right !important; object-position: bottom right !important;
transform: none !important; transform: scale(1.08) !important;
transform-origin: bottom right !important;
} }
} }

View File

@@ -33,7 +33,7 @@ const STAGES: Stage[] = [
}, },
{ {
title: 'Engage', title: 'Engage',
tagline: 'Playable daily rewards turn one visit into a habit.', tagline: 'Playable daily Lyts turn one visit into a habit.',
detail: 'Daily streaks, challenges & mini games', detail: 'Daily streaks, challenges & mini games',
icon: ( icon: (
<svg className="w-6 h-6" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="2.2"> <svg className="w-6 h-6" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="2.2">
@@ -145,49 +145,71 @@ export default function WhatWeDo({ isLoaded = false }: WhatWeDoProps) {
if (typeof window === 'undefined') return; if (typeof window === 'undefined') return;
const ctx = gsap.context(() => { const ctx = gsap.context(() => {
// Header: blur fade-up with stagger const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
// Header: clean fade-up with a refined blur transition
gsap.fromTo( gsap.fromTo(
'.wwd-header-el', '.wwd-header-el',
{ opacity: 0, y: 36, filter: 'blur(6px)' },
{ {
opacity: 1, y: 0, filter: 'blur(0px)', opacity: 0,
duration: 1, stagger: 0.18, ease: 'expo.out', y: prefersReducedMotion ? 0 : 30,
scrollTrigger: { trigger: '.wwd-header', start: 'top 85%', toggleActions: 'play none none reset' }, filter: prefersReducedMotion ? 'none' : 'blur(8px)'
},
{
opacity: 1,
y: 0,
filter: 'blur(0px)',
duration: DEFAULT_DURATION,
stagger: 0.15,
ease: DEFAULT_EASE,
scrollTrigger: {
trigger: '.wwd-header',
start: 'top 85%',
toggleActions: 'play none none reset'
},
} }
); );
// Cards: 3D flip-up reveal — each card rises and unfolds from its bottom // Cards: modern 3D lift + unblur reveal, smoothly staggered across the row
// edge, then its inner content cascades in. One scroll-triggered
// timeline keeps card + content in sync.
const cards = gsap.utils.toArray<HTMLElement>('.wwd-card'); const cards = gsap.utils.toArray<HTMLElement>('.wwd-card');
const grid = document.querySelector('.wwd-grid-container'); const grid = document.querySelector('.wwd-grid-container');
const revealTl = gsap.timeline({ if (prefersReducedMotion) {
scrollTrigger: { trigger: grid, start: 'top 82%', toggleActions: 'play none none reset' }, gsap.fromTo(
}); cards,
{ opacity: 0 },
revealTl.fromTo(cards, {
{ opacity: 0, y: 90, rotationX: -32, transformOrigin: '50% 100%', transformPerspective: 1100 }, opacity: 1,
{ opacity: 1, y: 0, rotationX: 0, duration: 0.9, ease: 'power4.out', stagger: 0.14 }, duration: 0.5,
0 stagger: 0.08,
scrollTrigger: { trigger: grid, start: 'top 85%', toggleActions: 'play none none reset' },
}
); );
} else {
cards.forEach((card, i) => { gsap.fromTo(
const at = i * 0.14 + 0.35; cards,
revealTl {
.fromTo(card.querySelector('.wwd-icon'), opacity: 0,
{ opacity: 0, scale: 0.4, rotate: -20 }, y: 72,
{ opacity: 1, scale: 1, rotate: 0, duration: 0.5, ease: 'back.out(2.2)' }, at) scale: 0.92,
.fromTo(card.querySelector('.wwd-title'), rotationX: 14,
{ opacity: 0, y: 16 }, transformOrigin: '50% 100%',
{ opacity: 1, y: 0, duration: 0.45, ease: 'power3.out' }, at + 0.12) transformPerspective: 900,
.fromTo(card.querySelector('.wwd-tagline'), filter: 'blur(10px)',
{ opacity: 0, y: 12 }, },
{ opacity: 1, y: 0, duration: 0.4, ease: 'power3.out' }, at + 0.22) {
.fromTo(card.querySelector('.wwd-detail'), opacity: 1,
{ opacity: 0, y: 10 }, y: 0,
{ opacity: 1, y: 0, duration: 0.4, ease: 'power3.out' }, at + 0.3); scale: 1,
}); rotationX: 0,
filter: 'blur(0px)',
duration: 1,
ease: 'power3.out',
stagger: 0.13,
scrollTrigger: { trigger: grid, start: 'top 82%', toggleActions: 'play none none reset' },
}
);
}
}, containerRef); }, containerRef);
return () => ctx.revert(); return () => ctx.revert();

View File

@@ -16,11 +16,11 @@ export interface HeroSlideData {
export const HERO_SLIDES: HeroSlideData[] = [ export const HERO_SLIDES: HeroSlideData[] = [
{ {
id: 'intro', id: 'intro',
badge: 'AI-Powered Loyalty', badge: 'AI-Powered Retail Intelligence',
headline: 'Turn Foot Traffic Into Fans', headline: 'Turn Every Visit Into Loyalty',
highlightWords: ['Fans'], highlightWords: ['Loyalty'],
description: description:
'Loyaly reads shopper behavior in real time and turns every visit into a reason to come back.', 'Loyaly understands shopper behavior in real time turning everyday footfall into lasting relationships and measurable growth.',
ctaLabel: 'Book a Demo', ctaLabel: 'Book a Demo',
ctaHref: '/contacts', ctaHref: '/contacts',
secondaryLabel: 'See How It Works', secondaryLabel: 'See How It Works',
@@ -30,11 +30,11 @@ export const HERO_SLIDES: HeroSlideData[] = [
}, },
{ {
id: 'app', id: 'app',
badge: 'Built For Every Shopper', badge: 'Crafted For Every Shopper',
headline: 'Shopping, But Make It Rewarding', headline: 'Shopping, Elevated To An Experience',
highlightWords: ['Rewarding'], highlightWords: ['Experience'],
description: description:
'Find stores nearby, stack LYTs, unlock drops made for you, and turn every trip into a game.', 'Discover stores near you, earn LYTs as you live, and unlock experiences designed around you — every trip effortless and rewarding.',
ctaLabel: 'Explore the App', ctaLabel: 'Explore the App',
ctaHref: '/for_people', ctaHref: '/for_people',
secondaryLabel: 'Get Early Access', secondaryLabel: 'Get Early Access',
@@ -44,11 +44,11 @@ export const HERO_SLIDES: HeroSlideData[] = [
}, },
{ {
id: 'ecosystem', id: 'ecosystem',
badge: 'The Full Stack', badge: 'One Intelligent Platform',
headline: 'Six Tools. One Mega Brain.', headline: 'Six Products. One Brain.',
highlightWords: ['Mega', 'Brain.'], highlightWords: ['One', 'Brain.'],
description: description:
'Behavision, SpendSense, Dyscount, Identiq, Flowmind, and the Loyaly App — built to know your customers better than they know themselves.', 'Behavision, SpendSense, Dyscount, Identiq, Flowmind, and the Loyaly App — a connected AI suite that knows your customers inside out.',
ctaLabel: 'Explore Platform', ctaLabel: 'Explore Platform',
ctaHref: '/solutions_page', ctaHref: '/solutions_page',
secondaryLabel: 'Meet the Tools', secondaryLabel: 'Meet the Tools',