updated sections design and content
This commit is contained in:
@@ -87,27 +87,65 @@ export default function AboutUsPage() {
|
||||
</section>
|
||||
|
||||
{/* ── MISSION & VISION ── */}
|
||||
<section style={{ padding: '0 8% 20px', background: '#ffffff' }}>
|
||||
<div className="au-mv-grid" style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 20, alignItems: 'stretch' }}>
|
||||
<section style={{ position: 'relative', overflow: 'hidden', padding: 'clamp(60px, 9vh, 104px) 8%', background: '#07070d', margin: '0 20px 20px', borderRadius: 28 }}>
|
||||
{/* 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.',
|
||||
},
|
||||
{
|
||||
label: 'Vision', bg: '#f4be28', textColor: '#111', accent: '#c9960f',
|
||||
body: 'Empowering every neighbourhood, making exceptional in-store experiences and real rewards accessible to all.',
|
||||
label: 'Vision', emoji: '🔮', bg: 'linear-gradient(160deg, #fff7e2 0%, #ffe6a8 100%)', textColor: '#171512',
|
||||
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) => (
|
||||
<Reveal key={i} delay={i * 0.15}>
|
||||
<div style={{
|
||||
padding: '72px 56px', borderRadius: 24, background: mv.bg,
|
||||
<div className="au-mv-card" style={{
|
||||
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,
|
||||
display: 'flex', flexDirection: 'column', justifyContent: 'flex-start', gap: 28,
|
||||
margin: '0 20px 20px', boxSizing: 'border-box',
|
||||
display: 'flex', flexDirection: 'column', justifyContent: 'flex-start', gap: 24,
|
||||
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>
|
||||
<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' }}>
|
||||
{/* Animated background orbs (clipped to the card) */}
|
||||
<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}
|
||||
</p>
|
||||
</div>
|
||||
@@ -178,6 +216,46 @@ export default function AboutUsPage() {
|
||||
</section>
|
||||
|
||||
<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) {
|
||||
.au-story-grid { grid-template-columns: 1fr !important; gap: 36px !important; }
|
||||
.au-market-grid { grid-template-columns: 1fr !important; gap: 36px !important; }
|
||||
|
||||
@@ -264,3 +264,24 @@ body.is-home-page.scroll-up .sticky-active {
|
||||
/* Hero carousel layout lives in HeroCarousel.tsx as a scoped <style> tag,
|
||||
matching every other home-page section — keeps it working even if this
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ const PRODUCTS = [
|
||||
'Entry-to-purchase funnel tracking that flags where shoppers drop off',
|
||||
],
|
||||
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',
|
||||
@@ -63,12 +63,12 @@ const PRODUCTS = [
|
||||
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, Loyaly’s 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: [
|
||||
'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',
|
||||
'Instant offline redemption at any partner store, no card required',
|
||||
],
|
||||
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',
|
||||
}}>
|
||||
Meet the<br />
|
||||
<span style={{ color: '#f4be28' }}>Crew.</span>
|
||||
<span style={{ color: '#f4be28' }}>Agents.</span>
|
||||
</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' }}>
|
||||
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>
|
||||
|
||||
<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) => (
|
||||
<ScrollStackItem key={i}>
|
||||
<div style={{
|
||||
background: `linear-gradient(155deg, #14141c 0%, #0c0c12 100%)`,
|
||||
border: `1px solid ${p.color}40`,
|
||||
borderRadius: 28, padding: 'clamp(28px, 3.2vw, 48px)', height: '100%', boxSizing: 'border-box',
|
||||
position: 'relative', overflow: 'hidden',
|
||||
background: `radial-gradient(130% 80% at 100% 0%, ${p.color}22 0%, transparent 46%), linear-gradient(155deg, #16161f 0%, #0a0a10 100%)`,
|
||||
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 */}
|
||||
<div>
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 14, marginBottom: 20 }}>
|
||||
<span style={{ fontSize: 13, 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.7rem', fontWeight: 700, letterSpacing: '0.1em', textTransform: 'uppercase', color: p.color, fontFamily: 'Sora, sans-serif' }}>{p.subtitle}</span>
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 14, marginBottom: 24 }}>
|
||||
<span style={{ fontSize: 15, fontWeight: 800, color: p.color, fontFamily: 'Sora, sans-serif', letterSpacing: '0.05em' }}>{p.n}</span>
|
||||
<span style={{ fontSize: '0.74rem', fontWeight: 700, letterSpacing: '0.12em', textTransform: 'uppercase', color: p.color, fontFamily: 'Sora, sans-serif' }}>{p.subtitle}</span>
|
||||
</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>
|
||||
<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>
|
||||
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 8 }}>
|
||||
<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: '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: 10 }}>
|
||||
{p.tags.map((tag) => (
|
||||
<span key={tag} style={{
|
||||
padding: '6px 14px', borderRadius: 100, fontSize: '0.72rem', fontWeight: 600,
|
||||
color: 'rgba(255,255,255,0.7)', background: 'rgba(255,255,255,0.05)',
|
||||
border: '1px solid rgba(255,255,255,0.1)', fontFamily: 'Sora, sans-serif',
|
||||
padding: '8px 16px', borderRadius: 100, fontSize: '0.76rem', fontWeight: 700,
|
||||
color: '#fff', background: `${p.color}1a`,
|
||||
border: `1px solid ${p.color}3d`, fontFamily: 'Sora, sans-serif',
|
||||
}}>{tag}</span>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Right — metric + capabilities */}
|
||||
{/* Right — metric hero + capabilities */}
|
||||
<div>
|
||||
<div style={{
|
||||
padding: 'clamp(18px, 2vw, 24px)', borderRadius: 18, marginBottom: 18,
|
||||
background: `${p.color}12`, border: `1px solid ${p.color}35`,
|
||||
padding: 'clamp(24px, 2.6vw, 34px)', borderRadius: 22, marginBottom: 24,
|
||||
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: 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: '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, 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 style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
|
||||
<div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
|
||||
{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={{
|
||||
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',
|
||||
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 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>
|
||||
|
||||
@@ -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 = [
|
||||
{
|
||||
title: 'Get Online', color: '#f4be28',
|
||||
desc: 'Your store, visible to thousands of local shoppers, without building a website.',
|
||||
title: 'Get Discovered', color: '#f4be28',
|
||||
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>,
|
||||
},
|
||||
{
|
||||
title: 'Get Noticed', color: '#a78bfa',
|
||||
desc: "Push real-time offers and proximity alerts that reach customers the moment they're nearby.",
|
||||
title: 'Drive Footfall', color: '#a78bfa',
|
||||
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>,
|
||||
},
|
||||
{
|
||||
title: 'Get Simplified', color: '#34d399',
|
||||
desc: 'One dashboard. All your deals, customers, and performance, managed in one place.',
|
||||
title: 'Understand Everything', color: '#34d399',
|
||||
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>,
|
||||
},
|
||||
];
|
||||
@@ -155,19 +132,26 @@ export default function ForBusinessPage() {
|
||||
letterSpacing: '-0.05em', lineHeight: 0.9,
|
||||
color: '#ffffff', margin: '0 0 32px', fontFamily: 'Sora, sans-serif',
|
||||
}}>
|
||||
Turn Footfall<br />
|
||||
Turn Every Visit<br />
|
||||
<span style={{
|
||||
background: 'linear-gradient(105deg,#f4be28 0%,#fff8e0 45%,#f4be28 60%,#ff9500 100%)',
|
||||
backgroundSize: '200% auto', WebkitBackgroundClip: 'text', WebkitTextFillColor: 'transparent',
|
||||
animation: 'shimmer 3s linear infinite',
|
||||
}}>Into Revenue.</span>
|
||||
}}>Into A Relationship.</span>
|
||||
</h1>
|
||||
|
||||
<p data-gsap="text" style={{
|
||||
fontSize: 'clamp(16px, 1.6vw, 21px)', lineHeight: 1.7, color: 'rgba(255,255,255,0.45)',
|
||||
fontFamily: 'Sora, sans-serif', maxWidth: 560, margin: '0 auto 52px',
|
||||
fontSize: 'clamp(16px, 1.6vw, 21px)', lineHeight: 1.7, color: 'rgba(255,255,255,0.55)',
|
||||
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>
|
||||
|
||||
<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',
|
||||
fontSize: 16, fontWeight: 800, borderRadius: 100, textDecoration: 'none',
|
||||
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={{
|
||||
display: 'inline-flex', alignItems: 'center', gap: 10,
|
||||
padding: '18px 40px', background: 'rgba(255,255,255,0.06)', color: '#fff',
|
||||
fontSize: 16, fontWeight: 700, borderRadius: 100, textDecoration: 'none',
|
||||
fontFamily: 'Sora, sans-serif', border: '1px solid rgba(255,255,255,0.12)',
|
||||
backdropFilter: 'blur(12px)',
|
||||
}}>Talk to Sales</Link>
|
||||
}}>Book a Demo</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -232,13 +216,13 @@ export default function ForBusinessPage() {
|
||||
<RevealBlock>
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-end', marginBottom: 80, flexWrap: 'wrap', gap: 24 }}>
|
||||
<div>
|
||||
<div style={{ fontSize: 11, fontWeight: 700, letterSpacing: '0.2em', textTransform: 'uppercase', color: '#f4be28', fontFamily: 'Sora, sans-serif', marginBottom: 16 }}>Capabilities</div>
|
||||
<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' }}>
|
||||
Four tools.<br />One merchant platform.
|
||||
Four agents.<br />One AI.
|
||||
</h2>
|
||||
</div>
|
||||
<p style={{ fontSize: 16, color: 'rgba(0,0,0,0.45)', fontFamily: 'Sora, sans-serif', maxWidth: 360, lineHeight: 1.7 }}>
|
||||
Every tool works independently and amplifies the others, giving merchants a complete system to attract, engage, and retain customers.
|
||||
Every agent works independently and amplifies the others, giving merchants a complete system to attract, engage, and retain customers.
|
||||
</p>
|
||||
</div>
|
||||
</RevealBlock>
|
||||
@@ -282,49 +266,6 @@ export default function ForBusinessPage() {
|
||||
<RevealBlock>
|
||||
<div style={{ fontSize: 11, fontWeight: 700, letterSpacing: '0.2em', textTransform: 'uppercase', color: '#f4be28', fontFamily: 'Sora, sans-serif', marginBottom: 20, position: 'relative' }}>How It Works</div>
|
||||
<h2 style={{ fontSize: 'clamp(36px, 5vw, 72px)', fontWeight: 800, letterSpacing: '-0.04em', lineHeight: 0.95, color: '#fff', margin: '0 0 80px', fontFamily: 'Sora, sans-serif', maxWidth: 700, position: 'relative' }}>
|
||||
Live in five steps.
|
||||
</h2>
|
||||
</RevealBlock>
|
||||
<div className="uc-timeline" style={{ position: 'relative', maxWidth: 880 }}>
|
||||
<div className="uc-timeline-line" aria-hidden style={{ position: 'absolute', left: 27, top: 8, bottom: 8, width: 2, background: 'linear-gradient(180deg, rgba(255,255,255,0.18) 0%, rgba(255,255,255,0.04) 100%)' }} />
|
||||
{STEPS.map((step, i) => (
|
||||
<RevealBlock key={step.n} delay={i * 0.08}>
|
||||
<div className="uc-timeline-row" style={{
|
||||
display: 'grid', gridTemplateColumns: '56px 1fr', gap: 28,
|
||||
paddingBottom: i < STEPS.length - 1 ? 48 : 0,
|
||||
position: 'relative',
|
||||
}}>
|
||||
<div style={{
|
||||
width: 56, height: 56, borderRadius: '50%', flexShrink: 0,
|
||||
background: '#0c0c12', border: `2px solid ${step.color}`,
|
||||
display: 'flex', alignItems: 'center', justifyContent: 'center',
|
||||
color: step.color, position: 'relative', zIndex: 1,
|
||||
boxShadow: `0 0 0 6px #07070d, 0 8px 24px -8px ${step.color}80`,
|
||||
}}>
|
||||
{step.icon}
|
||||
</div>
|
||||
<div className="uc-timeline-card" style={{
|
||||
background: 'rgba(255,255,255,0.03)', borderRadius: 18, padding: '26px 30px',
|
||||
border: '1px solid rgba(255,255,255,0.08)', backdropFilter: 'blur(12px)',
|
||||
display: 'flex', flexDirection: 'column', gap: 6,
|
||||
}}>
|
||||
<div style={{ display: 'flex', alignItems: 'baseline', gap: 12 }}>
|
||||
<span style={{ fontSize: 12, fontWeight: 800, color: step.color, fontFamily: 'Sora, sans-serif', letterSpacing: '0.1em' }}>{step.n}</span>
|
||||
<h3 style={{ fontSize: 'clamp(19px, 2.2vw, 26px)', fontWeight: 800, color: '#fff', fontFamily: 'Sora, sans-serif', margin: 0, letterSpacing: '-0.02em' }}>{step.title}</h3>
|
||||
</div>
|
||||
<p style={{ fontSize: 15, color: 'rgba(255,255,255,0.5)', fontFamily: 'Sora, sans-serif', margin: 0, lineHeight: 1.6 }}>{step.desc}</p>
|
||||
</div>
|
||||
</div>
|
||||
</RevealBlock>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* ── MERCHANT BENEFITS ── */}
|
||||
<section style={{ padding: '140px 8%', background: '#fff', margin: '0 20px 20px', borderRadius: 24, overflow: 'hidden', position: 'relative' }}>
|
||||
<RevealBlock>
|
||||
<div style={{ fontSize: 11, fontWeight: 700, letterSpacing: '0.2em', textTransform: 'uppercase', color: '#f4be28', fontFamily: 'Sora, sans-serif', marginBottom: 20, position: 'relative' }}>Why Merchants Choose Us</div>
|
||||
<h2 style={{ fontSize: 'clamp(36px, 5vw, 72px)', fontWeight: 800, letterSpacing: '-0.04em', lineHeight: 0.95, color: '#0a0a0f', margin: '0 0 80px', fontFamily: 'Sora, sans-serif', maxWidth: 700, position: 'relative' }}>
|
||||
Three ways we grow your store.
|
||||
</h2>
|
||||
</RevealBlock>
|
||||
@@ -332,25 +273,37 @@ export default function ForBusinessPage() {
|
||||
{PILLARS.map((p, i) => (
|
||||
<RevealBlock key={p.title} delay={i * 0.1}>
|
||||
<div className="uc-pillar-card" style={{
|
||||
padding: '36px 32px', borderRadius: 22, height: '100%', boxSizing: 'border-box',
|
||||
background: `linear-gradient(160deg, ${p.color}14 0%, #faf9f6 60%)`,
|
||||
border: `1px solid ${p.color}35`, position: 'relative', overflow: 'hidden',
|
||||
transition: 'transform 0.35s cubic-bezier(0.22,1,0.36,1), border-color 0.35s ease',
|
||||
padding: '34px 30px 30px', borderRadius: 24, height: '100%', boxSizing: 'border-box',
|
||||
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}45`,
|
||||
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={{
|
||||
position: 'absolute', top: -18, right: -10, fontSize: 96, fontWeight: 900,
|
||||
color: 'transparent', WebkitTextStroke: `1px ${p.color}22`, fontFamily: 'Sora, sans-serif',
|
||||
lineHeight: 1, userSelect: 'none', pointerEvents: 'none',
|
||||
}}>0{i + 1}</span>
|
||||
position: 'absolute', top: 22, right: 22,
|
||||
display: 'inline-flex', alignItems: 'center', gap: 5,
|
||||
fontSize: 12.5, fontWeight: 800, letterSpacing: '0.08em',
|
||||
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={{
|
||||
width: 54, height: 54, borderRadius: 16, marginBottom: 24,
|
||||
background: `${p.color}18`, border: `1px solid ${p.color}45`,
|
||||
width: 56, height: 56, borderRadius: 16, marginBottom: 26,
|
||||
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,
|
||||
position: 'relative', zIndex: 1,
|
||||
}}>{p.icon}</div>
|
||||
<h3 style={{ fontSize: 22, fontWeight: 800, color: '#0a0a0f', fontFamily: 'Sora, sans-serif', margin: '0 0 12px', letterSpacing: '-0.02em', position: 'relative', zIndex: 1 }}>{p.title}</h3>
|
||||
<p style={{ fontSize: 15, lineHeight: 1.7, color: 'rgba(0,0,0,0.55)', fontFamily: 'Sora, sans-serif', margin: '0 0 20px', position: 'relative', zIndex: 1 }}>{p.desc}</p>
|
||||
<div style={{ height: 3, width: 40, borderRadius: 2, background: p.color, position: 'relative', zIndex: 1 }} />
|
||||
<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(255,255,255,0.55)', fontFamily: 'Sora, sans-serif', margin: '0 0 22px', position: 'relative', zIndex: 1 }}>{p.desc}</p>
|
||||
<div style={{ height: 4, width: 44, borderRadius: 4, background: p.color, boxShadow: `0 0 14px ${p.color}`, position: 'relative', zIndex: 1 }} />
|
||||
</div>
|
||||
</RevealBlock>
|
||||
))}
|
||||
@@ -358,47 +311,130 @@ export default function ForBusinessPage() {
|
||||
</section>
|
||||
|
||||
{/* ── PROXIMITY MARKETING ── */}
|
||||
<section style={{ padding: '120px 8%', background: '#0c0a06', margin: '0 20px 20px', borderRadius: 24, overflow: 'hidden', position: 'relative' }}>
|
||||
<div style={{ position: 'absolute', inset: 0, backgroundImage: 'linear-gradient(rgba(244,190,40,0.03) 1px,transparent 1px),linear-gradient(90deg,rgba(244,190,40,0.03) 1px,transparent 1px)', backgroundSize: '56px 56px', pointerEvents: 'none' }} />
|
||||
<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(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>
|
||||
<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 */}
|
||||
<div className="uc-radar" style={{ position: 'relative', width: '100%', aspectRatio: '1 / 1', maxWidth: 320, margin: '0 auto' }}>
|
||||
{[0, 1, 2].map((r) => (
|
||||
<div key={r} className="uc-radar-ring" style={{
|
||||
position: 'absolute', inset: 0, borderRadius: '50%',
|
||||
border: '1.5px solid rgba(244,190,40,0.35)',
|
||||
animation: `ucRadarPulse 3s ease-out ${r * 1}s infinite`,
|
||||
}} />
|
||||
))}
|
||||
<div style={{
|
||||
position: 'absolute', top: '50%', left: '50%', transform: 'translate(-50%,-50%)',
|
||||
width: '34%', height: '34%', borderRadius: '50%',
|
||||
background: 'radial-gradient(circle, #f4be28 0%, #c9960f 100%)',
|
||||
display: 'flex', alignItems: 'center', justifyContent: 'center',
|
||||
boxShadow: '0 0 40px rgba(244,190,40,0.5)',
|
||||
{/* Animated city map with proximity pins */}
|
||||
<div className="uc-map-panel" style={{
|
||||
position: 'relative', borderRadius: 28, width: '100%', aspectRatio: '4 / 3', overflow: 'hidden',
|
||||
background: 'linear-gradient(165deg, #fffdf7 0%, #faf3e0 100%)',
|
||||
border: '1px solid rgba(244,190,40,0.28)',
|
||||
boxShadow: '0 34px 80px -34px rgba(201,150,15,0.4), inset 0 1px 0 rgba(255,255,255,0.7)',
|
||||
}}>
|
||||
<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" />
|
||||
</svg>
|
||||
</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 */}
|
||||
<div>
|
||||
<div style={{ fontSize: 11, fontWeight: 700, letterSpacing: '0.2em', textTransform: 'uppercase', color: '#f4be28', fontFamily: 'Sora, sans-serif', marginBottom: 20 }}>Capability Spotlight</div>
|
||||
<h2 style={{ fontSize: 'clamp(28px, 3.6vw, 48px)', fontWeight: 800, letterSpacing: '-0.03em', lineHeight: 1.08, color: '#fff', margin: '0 0 20px', fontFamily: 'Sora, sans-serif' }}>
|
||||
<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)' }}>
|
||||
<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're nearby.
|
||||
</h2>
|
||||
<p style={{ fontSize: 16, lineHeight: 1.8, color: 'rgba(255,255,255,0.5)', fontFamily: 'Sora, sans-serif', margin: '0 0 32px', maxWidth: 480 }}>
|
||||
<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's proximity engine sends instant notifications to shoppers browsing within your store's radius. No ad spend. No guesswork. Just timely, relevant offers delivered at exactly the right moment.
|
||||
</p>
|
||||
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 12 }}>
|
||||
{[{ v: 'Instant', l: 'Notification speed' }, { v: '0', l: 'Ad spend required' }, { v: 'Real-time', l: 'Radius targeting' }].map((s) => (
|
||||
<div key={s.l} style={{ padding: '14px 20px', borderRadius: 14, background: 'rgba(244,190,40,0.08)', border: '1px solid rgba(244,190,40,0.25)' }}>
|
||||
<div style={{ fontSize: 18, fontWeight: 900, color: '#f4be28', fontFamily: 'Sora, sans-serif', letterSpacing: '-0.02em' }}>{s.v}</div>
|
||||
<div style={{ fontSize: 11.5, color: 'rgba(255,255,255,0.45)', fontFamily: 'Sora, sans-serif', marginTop: 3 }}>{s.l}</div>
|
||||
<div className="uc-prox-stats" style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 12, maxWidth: 500 }}>
|
||||
{[
|
||||
{ v: 'Instant', l: 'Notification speed', icon: <path d="M13 2L3 14h9l-1 8 10-12h-9l1-8z" /> },
|
||||
{ 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" /></> },
|
||||
{ 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>
|
||||
@@ -484,7 +520,21 @@ export default function ForBusinessPage() {
|
||||
0% { transform: scale(0.3); opacity: 0.9; }
|
||||
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) {
|
||||
.uc-challenge-grid { grid-template-columns: 1fr !important; gap: 40px !important; }
|
||||
.uc-outcomes-grid { grid-template-columns: repeat(2,1fr) !important; }
|
||||
@@ -504,6 +554,7 @@ export default function ForBusinessPage() {
|
||||
}
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.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>
|
||||
</main>
|
||||
|
||||
@@ -10,7 +10,7 @@ const NAV = [
|
||||
links: [
|
||||
{ label: 'For People', href: '/for_people' },
|
||||
{ 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',
|
||||
}}>
|
||||
{/* Brand */}
|
||||
<div className="ly-footer-brand">
|
||||
<Link href="/" aria-label="Loyaly.AI home">
|
||||
<Image src="/images/logo-dark.png" alt="Loyaly.AI" width={560} height={160} style={{ height: 140, width: 'auto', marginBottom: 24, display: 'block' }} />
|
||||
<div className="ly-footer-brand" style={{ display: 'flex', flexDirection: 'column', alignItems: 'flex-start' }}>
|
||||
<Link href="/" aria-label="Loyaly.AI home" style={{ display: 'block', maxWidth: '100%', marginBottom: 18 }}>
|
||||
{/* logo-dark.png is 250x150 with the wordmark in the middle strip (y 58–107);
|
||||
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>
|
||||
<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.
|
||||
@@ -195,7 +199,7 @@ export default function Footer() {
|
||||
@media (max-width: 560px) {
|
||||
.ly-footer-heading { font-size: clamp(30px, 9vw, 44px) !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 > div { gap: 18px !important; }
|
||||
}
|
||||
|
||||
@@ -9,9 +9,9 @@ const NAV_LINKS = [
|
||||
{ label: 'Home', href: '/' },
|
||||
{ label: 'For People', href: '/for_people' },
|
||||
{ label: 'For Business', href: '/use_cases' },
|
||||
{ label: 'Meet the Crew', href: '/solutions_page' },
|
||||
{ label: 'Blogs', href: '/blog_main' },
|
||||
{ label: 'Meet the Agents', href: '/solutions_page' },
|
||||
{ label: 'About us', href: '/about_us' },
|
||||
{ label: 'Blogs', href: '/blog_main' },
|
||||
];
|
||||
|
||||
const MOBILE_QUERY = '(max-width: 1023px)';
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
-webkit-transform: translateZ(0);
|
||||
transform: translateZ(0);
|
||||
position: relative;
|
||||
transition: opacity 0.35s ease;
|
||||
}
|
||||
|
||||
.scroll-stack-end {
|
||||
|
||||
@@ -27,6 +27,7 @@ interface ScrollStackProps {
|
||||
scaleDuration?: number;
|
||||
rotationAmount?: number;
|
||||
blurAmount?: number;
|
||||
hideBehind?: boolean;
|
||||
useWindowScroll?: boolean;
|
||||
onStackComplete?: () => void;
|
||||
}
|
||||
@@ -42,6 +43,7 @@ const ScrollStack = ({
|
||||
baseScale = 0.85,
|
||||
rotationAmount = 0,
|
||||
blurAmount = 0,
|
||||
hideBehind = false,
|
||||
useWindowScroll = false,
|
||||
onStackComplete,
|
||||
}: ScrollStackProps) => {
|
||||
@@ -122,6 +124,14 @@ const ScrollStack = ({
|
||||
|
||||
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) => {
|
||||
if (!card) return;
|
||||
|
||||
@@ -137,20 +147,14 @@ const ScrollStack = ({
|
||||
const rotation = rotationAmount ? i * rotationAmount * scaleProgress : 0;
|
||||
|
||||
let blur = 0;
|
||||
if (blurAmount) {
|
||||
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) {
|
||||
if (blurAmount && i < topCardIndex) {
|
||||
const depthInStack = topCardIndex - i;
|
||||
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;
|
||||
@@ -207,6 +211,7 @@ const ScrollStack = ({
|
||||
baseScale,
|
||||
rotationAmount,
|
||||
blurAmount,
|
||||
hideBehind,
|
||||
useWindowScroll,
|
||||
onStackComplete,
|
||||
calculateProgress,
|
||||
|
||||
@@ -12,9 +12,9 @@ if (typeof window !== 'undefined') gsap.registerPlugin(ScrollTrigger);
|
||||
const useIsomorphicLayoutEffect = typeof window !== 'undefined' ? useLayoutEffect : useEffect;
|
||||
|
||||
const TAGS = [
|
||||
{ label: 'Live coupons', icon: '🎟️' },
|
||||
{ label: 'Nearby stores', icon: '📍' },
|
||||
{ label: 'Game-based deals', icon: '🎮' },
|
||||
{ label: 'Earn as you live', icon: '⚡' },
|
||||
{ label: 'Play to win', icon: '🎮' },
|
||||
{ label: 'Spend anywhere', icon: '🛍️' },
|
||||
];
|
||||
|
||||
export default function DiscoverDealsSection() {
|
||||
@@ -54,10 +54,10 @@ export default function DiscoverDealsSection() {
|
||||
<section ref={panelRef} className="fp-panel" style={{ background: '#08080f' }}>
|
||||
|
||||
{/* 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={{
|
||||
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 */}
|
||||
@@ -71,37 +71,23 @@ export default function DiscoverDealsSection() {
|
||||
|
||||
{/* Headline column */}
|
||||
<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' }}>
|
||||
<span className="fp-mask"><span>Every</span></span>
|
||||
<span className="fp-mask"><span>deal in</span></span>
|
||||
<span className="fp-mask"><span className="fp-shimmer">your city.</span></span>
|
||||
<span className="fp-mask"><span>The app that</span></span>
|
||||
<span className="fp-mask"><span>rewards you for</span></span>
|
||||
<span className="fp-mask"><span className="fp-shimmer">living your life.</span></span>
|
||||
</h2>
|
||||
|
||||
<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>
|
||||
|
||||
<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) => (
|
||||
<FpTagCard key={tag.label} theme="dark" icon={tag.icon}>{tag.label}</FpTagCard>
|
||||
))}
|
||||
</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>
|
||||
|
||||
{/* Discover GIF */}
|
||||
@@ -117,7 +103,7 @@ export default function DiscoverDealsSection() {
|
||||
{/* eslint-disable-next-line @next/next/no-img-element */}
|
||||
<img
|
||||
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' }}
|
||||
/>
|
||||
|
||||
|
||||
@@ -81,7 +81,7 @@ export default function EarnRewardsSection() {
|
||||
<div ref={phoneRef} style={{ display: 'flex', justifyContent: 'center', opacity: 0, width: '100%' }}>
|
||||
<PhoneMockupImage
|
||||
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"
|
||||
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 }}>
|
||||
{earnTags.map((tag) => (
|
||||
<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>
|
||||
))}
|
||||
</div>
|
||||
|
||||
@@ -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,
|
||||
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>
|
||||
|
||||
<div style={{ display: 'flex', flexDirection: 'column' }}>
|
||||
|
||||
@@ -30,7 +30,7 @@ function useMagnetic() {
|
||||
const PROOF = [
|
||||
{ val: '50K+', label: 'Active users', color: '#f4be28', icon: '👥', iconBg: '#fffbeb' },
|
||||
{ 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' },
|
||||
];
|
||||
|
||||
|
||||
@@ -63,23 +63,33 @@ export default function HeroSection() {
|
||||
fontSize: 'clamp(40px, 5.4vw, 82px)', fontWeight: 800, lineHeight: 1.02,
|
||||
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 className="fp-shimmer">Live More.</span></span>
|
||||
<span className="fp-mask"><span>Earn LYTs.</span></span>
|
||||
<span className="fp-mask"><span className="fp-shimmer">Lit Yourself.</span></span>
|
||||
</h1>
|
||||
|
||||
<p className="fp-content fp-subtext" style={{
|
||||
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>
|
||||
|
||||
<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
|
||||
ref={magSecondary}
|
||||
className="fp-btn fp-btn-ghost fp-magnetic"
|
||||
>
|
||||
See How It Works
|
||||
Explore Nearby
|
||||
</button>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -51,11 +51,11 @@ export default function LytsUniverseSection() {
|
||||
|
||||
<h2 className="fp-h1" style={{ color: '#fff' }}>
|
||||
<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>
|
||||
|
||||
<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>
|
||||
|
||||
<div className="fp-rise" style={{ display: 'flex', flexWrap: 'wrap', gap: 10, marginBottom: 28, maxWidth: 460 }}>
|
||||
|
||||
@@ -11,14 +11,14 @@ const PILLARS = [
|
||||
},
|
||||
{
|
||||
n: '02',
|
||||
title: 'Earn Rewards',
|
||||
title: 'Earn Lyts',
|
||||
desc: 'Every rupee spent earns LYT points. Zero expiry. Redeem anytime, at any partner store.',
|
||||
color: '#16a34a',
|
||||
},
|
||||
{
|
||||
n: '03',
|
||||
title: 'Make It a Pleasure',
|
||||
desc: 'Shopping should feel good. Loyaly makes every trip more rewarding, more fun, and more personal.',
|
||||
desc: 'Shopping should feel good. LytsUp makes every trip more rewarding, more fun, and more personal.',
|
||||
color: '#a78bfa',
|
||||
},
|
||||
];
|
||||
@@ -41,7 +41,7 @@ export default function PillarsSection() {
|
||||
fontSize: 16, lineHeight: 1.8, color: '#4f463a', margin: '0 0 56px',
|
||||
fontFamily: 'Sora, sans-serif', maxWidth: 560,
|
||||
}}>
|
||||
Earn Loyaly rewards on everyday shopping, from groceries to fashion to home essentials. Every purchase brings you closer to your next reward.
|
||||
Earn Lyts on everyday shopping, from groceries to fashion to home essentials. Every purchase brings you closer to your next Lyt.
|
||||
</p>
|
||||
|
||||
<div className="fp-pillar-cols" style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 24 }}>
|
||||
|
||||
@@ -72,7 +72,7 @@ export default function SpendAnywhereSection() {
|
||||
fontSize: 'clamp(17px, 1.7vw, 21px)', lineHeight: 1.3, color: '#fff', fontFamily: 'Sora, sans-serif',
|
||||
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>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -32,7 +32,7 @@ export default function WhyLoyalySection() {
|
||||
const bars = [
|
||||
{ label: 'Online retail rewards', pct: 78, color: '#171512' },
|
||||
{ label: 'Offline retail rewards', pct: 2, color: '#bc7122' },
|
||||
{ label: 'Loyaly target', pct: 60, color: '#f4be28' },
|
||||
{ label: 'LytsUp target', pct: 60, color: '#f4be28' },
|
||||
];
|
||||
|
||||
return (
|
||||
@@ -77,7 +77,7 @@ export default function WhyLoyalySection() {
|
||||
{[
|
||||
{ val: '₹2.1L Cr', label: 'Offline retail market size', accent: '#171512' },
|
||||
{ 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) => (
|
||||
<div key={i} className="fp-rise" style={{
|
||||
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',
|
||||
fontFamily: 'Sora, sans-serif', maxWidth: 440,
|
||||
}}>
|
||||
India'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'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>
|
||||
|
||||
{/* Data bars */}
|
||||
|
||||
@@ -10,7 +10,6 @@ interface HeroContentProps {
|
||||
}
|
||||
|
||||
export default function HeroContent({ slide }: HeroContentProps) {
|
||||
const badgeRef = useRef<HTMLDivElement | null>(null);
|
||||
const headlineRef = useRef<HTMLHeadingElement | null>(null);
|
||||
const descRef = useRef<HTMLParagraphElement | null>(null);
|
||||
const ctaRef = useRef<HTMLDivElement | null>(null);
|
||||
@@ -23,14 +22,11 @@ export default function HeroContent({ slide }: HeroContentProps) {
|
||||
: [];
|
||||
const desc = descRef.current;
|
||||
const cta = ctaRef.current;
|
||||
const badge = badgeRef.current;
|
||||
|
||||
gsap.set(wordEls, { yPercent: 120, opacity: 0, rotateZ: 4 });
|
||||
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' } });
|
||||
tl.to(badge, { opacity: 1, y: 0, scale: 1, duration: 0.6 }, 0);
|
||||
tl.to(
|
||||
wordEls,
|
||||
{ yPercent: 0, opacity: 1, rotateZ: 0, duration: 1, stagger: 0.055 },
|
||||
@@ -44,11 +40,6 @@ export default function HeroContent({ slide }: HeroContentProps) {
|
||||
|
||||
return (
|
||||
<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">
|
||||
{words.map((word, i) => {
|
||||
const isHighlighted = slide.highlightWords.includes(word);
|
||||
|
||||
@@ -43,10 +43,12 @@ export default function LytsUpSection({ isLoaded = true }: LytsUpSectionProps) {
|
||||
const tl = gsap.timeline({
|
||||
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)
|
||||
.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)
|
||||
tl.fromTo('.lytsup-eyebrow', { opacity: 0, y: -12 }, { opacity: 1, y: 0, duration: 0.6, ease: 'power3.out' }, 0)
|
||||
.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-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
|
||||
PROOF_STATS.forEach((stat, i) => {
|
||||
@@ -159,8 +161,12 @@ export default function LytsUpSection({ isLoaded = true }: LytsUpSectionProps) {
|
||||
borderRadius: 32,
|
||||
padding: 'clamp(64px, 8vw, 110px) clamp(20px, 4vw, 64px) clamp(64px, 8vw, 96px)',
|
||||
zIndex: 2,
|
||||
background: 'radial-gradient(ellipse 110% 80% at 50% 0%, #17130d 0%, #0d0b09 55%, #0a0807 100%)',
|
||||
boxShadow: 'inset 0 0 0 1px rgba(244,190,40,0.12)',
|
||||
background:
|
||||
'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 */}
|
||||
@@ -192,6 +198,21 @@ export default function LytsUpSection({ isLoaded = true }: LytsUpSectionProps) {
|
||||
|
||||
{/* 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-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
|
||||
style={{
|
||||
margin: 0,
|
||||
@@ -237,9 +258,26 @@ export default function LytsUpSection({ isLoaded = true }: LytsUpSectionProps) {
|
||||
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>
|
||||
|
||||
{/* 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 */}
|
||||
<div style={{ display: 'flex', flexWrap: 'wrap', justifyContent: 'center', gap: 10, marginTop: 26 }}>
|
||||
{PROOF_STATS.map((stat, i) => (
|
||||
@@ -265,6 +303,22 @@ export default function LytsUpSection({ isLoaded = true }: LytsUpSectionProps) {
|
||||
</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 */}
|
||||
<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) => (
|
||||
@@ -304,42 +358,70 @@ export default function LytsUpSection({ isLoaded = true }: LytsUpSectionProps) {
|
||||
<div
|
||||
className="lytsup-closing relative z-10 mx-auto"
|
||||
style={{
|
||||
maxWidth: 720, textAlign: 'center',
|
||||
padding: 'clamp(36px, 4vw, 52px) clamp(24px, 4vw, 48px)',
|
||||
borderRadius: 26,
|
||||
background: 'linear-gradient(180deg, rgba(255,255,255,0.06) 0%, rgba(255,255,255,0.02) 100%)',
|
||||
border: '1px solid rgba(244,190,40,0.22)',
|
||||
boxShadow: '0 30px 60px -24px rgba(0,0,0,0.6)',
|
||||
position: 'relative', overflow: 'hidden',
|
||||
maxWidth: 680, textAlign: 'center',
|
||||
padding: 'clamp(40px, 4.5vw, 60px) clamp(28px, 4vw, 52px)',
|
||||
borderRadius: 30,
|
||||
background: 'linear-gradient(135deg, #FFE071 0%, #f4be28 46%, #FF9E2C 100%)',
|
||||
border: '3px solid #171512',
|
||||
boxShadow: '10px 10px 0 0 #171512',
|
||||
position: 'relative',
|
||||
}}
|
||||
>
|
||||
<span aria-hidden style={{ position: 'absolute', top: -18, right: 26, fontSize: 34, transform: 'rotate(12deg)' }}>🔥</span>
|
||||
<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' }} />
|
||||
{/* Rotated sticker badge */}
|
||||
<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's get it.
|
||||
</h3>
|
||||
|
||||
<p
|
||||
style={{
|
||||
margin: '0 0 28px', position: 'relative',
|
||||
fontSize: 'clamp(1.05rem, 1.6vw, 1.4rem)', fontWeight: 600,
|
||||
lineHeight: 1.6, color: 'rgba(255,255,255,0.85)',
|
||||
fontFamily: 'Sora, sans-serif', letterSpacing: '-0.01em',
|
||||
margin: '0 auto 24px', maxWidth: 460, position: 'relative',
|
||||
fontSize: 'clamp(0.95rem, 1.3vw, 1.1rem)', fontWeight: 600,
|
||||
lineHeight: 1.55, color: 'rgba(23,21,18,0.72)',
|
||||
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>
|
||||
|
||||
{/* 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
|
||||
ref={ctaRef}
|
||||
href="/contacts"
|
||||
style={{
|
||||
display: 'inline-flex', alignItems: 'center', gap: 10, position: 'relative',
|
||||
padding: '15px 34px', borderRadius: 100,
|
||||
fontSize: '1rem', fontWeight: 800, fontFamily: 'Sora, sans-serif',
|
||||
color: '#171512', textDecoration: 'none',
|
||||
background: 'linear-gradient(135deg, #f4be28 0%, #FF9800 100%)',
|
||||
boxShadow: '0 16px 40px -12px rgba(244,190,40,0.5)',
|
||||
padding: '16px 38px', borderRadius: 100,
|
||||
fontSize: '1.05rem', fontWeight: 800, fontFamily: 'Sora, sans-serif',
|
||||
color: '#FFE071', textDecoration: 'none',
|
||||
background: '#171512', border: '2.5px solid #171512',
|
||||
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">
|
||||
<path d="M14 5l7 7m0 0l-7 7m7-7H3" />
|
||||
</svg>
|
||||
@@ -352,8 +434,73 @@ export default function LytsUpSection({ isLoaded = true }: LytsUpSectionProps) {
|
||||
0%, 100% { transform: scale(1) rotate(0deg); }
|
||||
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) {
|
||||
.lytsup-sticker-spark { animation: none; }
|
||||
.lytsup-sticker-spark,
|
||||
.lytsup-live-dot,
|
||||
.lytsup-marquee-track,
|
||||
.lytsup-sticker-emoji { animation: none; }
|
||||
}
|
||||
@media (max-width: 900px) {
|
||||
.lytsup-flow { max-width: 380px !important; }
|
||||
|
||||
@@ -22,7 +22,7 @@ const DARK_CARDS = [
|
||||
description: 'No compelling reason for customers to visit your store',
|
||||
image: '/problems/4.png',
|
||||
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" />
|
||||
</svg>
|
||||
),
|
||||
@@ -32,7 +32,7 @@ const DARK_CARDS = [
|
||||
description: 'Traditional discounts erode profit margins',
|
||||
image: '/problems/5.png',
|
||||
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" />
|
||||
</svg>
|
||||
),
|
||||
@@ -42,28 +42,28 @@ const DARK_CARDS = [
|
||||
description: 'Digital ads rarely convert into store footfall',
|
||||
image: '/problems/6.png',
|
||||
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" />
|
||||
</svg>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: 'No Real-Time Signal',
|
||||
title: 'No Real-Time Signals',
|
||||
description: 'No real-time connection between online activity and offline shopping',
|
||||
image: '/problems/7.png',
|
||||
wide: true,
|
||||
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" />
|
||||
</svg>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: 'Customer Amnesia',
|
||||
description: 'Customers forget about stores between visits',
|
||||
description: 'Customers forget about brands between visits',
|
||||
image: '/problems/8.png',
|
||||
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" />
|
||||
</svg>
|
||||
),
|
||||
@@ -162,18 +162,45 @@ export default function ProblemSection({ isLoaded = true }: ProblemSectionProps)
|
||||
gap: 'clamp(8px, 1.2vw, 14px)',
|
||||
}}>
|
||||
{[
|
||||
{ val: '$2 Tn', label: 'India retail market by 2032, 25% CAGR' },
|
||||
{ val: '5th', label: 'Largest retail destination globally' },
|
||||
{ val: '10%', label: "Of India's GDP from retail" },
|
||||
{ val: '12%', label: 'Of retail is organised, the rest is offline' },
|
||||
{ val: '500M', label: 'Indians shopping online by 2030, up from 220M' },
|
||||
{
|
||||
val: '$2 Tn', label: 'Indian retail market by 2032, 26% CAGR',
|
||||
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: '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) => (
|
||||
<div key={i} style={{
|
||||
<div key={i} className="problem-india-stat" style={{
|
||||
padding: 'clamp(14px, 1.8vw, 20px)', borderRadius: 16,
|
||||
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={{ 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>
|
||||
@@ -196,28 +223,25 @@ export default function ProblemSection({ isLoaded = true }: ProblemSectionProps)
|
||||
clickEffect={true}
|
||||
particleCount={6}
|
||||
style={{
|
||||
background: '#e12d2d',
|
||||
borderRadius: '24px',
|
||||
padding: 'clamp(20px, 2.4vw, 28px)',
|
||||
border: '1px solid rgba(255, 255, 255, 0.15)',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
minHeight: '230px',
|
||||
boxShadow: '0 10px 30px -12px rgba(225, 45, 45, 0.4)',
|
||||
position: 'relative',
|
||||
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 }}>
|
||||
68%+
|
||||
68%<span style={{ color: '#ffd27a' }}>+</span>
|
||||
</div>
|
||||
<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
|
||||
</div>
|
||||
</div>
|
||||
<div style={{
|
||||
<div className="problem-stat-art" style={{
|
||||
position: 'absolute',
|
||||
right: '-18px',
|
||||
bottom: '-18px',
|
||||
@@ -251,28 +275,25 @@ export default function ProblemSection({ isLoaded = true }: ProblemSectionProps)
|
||||
clickEffect={true}
|
||||
particleCount={6}
|
||||
style={{
|
||||
background: '#e12d2d',
|
||||
borderRadius: '24px',
|
||||
padding: 'clamp(20px, 2.4vw, 28px)',
|
||||
border: '1px solid rgba(255, 255, 255, 0.15)',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
minHeight: '230px',
|
||||
boxShadow: '0 10px 30px -12px rgba(225, 45, 45, 0.4)',
|
||||
position: 'relative',
|
||||
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 }}>
|
||||
0+
|
||||
0<span style={{ color: '#ffd27a' }}>+</span>
|
||||
</div>
|
||||
<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
|
||||
</div>
|
||||
</div>
|
||||
<div style={{
|
||||
<div className="problem-stat-art" style={{
|
||||
position: 'absolute',
|
||||
right: '-18px',
|
||||
bottom: '-18px',
|
||||
@@ -306,28 +327,25 @@ export default function ProblemSection({ isLoaded = true }: ProblemSectionProps)
|
||||
clickEffect={true}
|
||||
particleCount={6}
|
||||
style={{
|
||||
background: '#e12d2d',
|
||||
borderRadius: '24px',
|
||||
padding: 'clamp(20px, 2.4vw, 28px)',
|
||||
border: '1px solid rgba(255, 255, 255, 0.15)',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
minHeight: '230px',
|
||||
boxShadow: '0 10px 30px -12px rgba(225, 45, 45, 0.4)',
|
||||
position: 'relative',
|
||||
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 }}>
|
||||
5+
|
||||
5<span style={{ color: '#ffd27a' }}>+</span>
|
||||
</div>
|
||||
<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
|
||||
</div>
|
||||
</div>
|
||||
<div style={{
|
||||
<div className="problem-stat-art" style={{
|
||||
position: 'absolute',
|
||||
right: '-18px',
|
||||
bottom: '-18px',
|
||||
@@ -365,10 +383,8 @@ export default function ProblemSection({ isLoaded = true }: ProblemSectionProps)
|
||||
clickEffect={true}
|
||||
particleCount={6}
|
||||
style={{
|
||||
background: '#171512',
|
||||
borderRadius: '24px',
|
||||
padding: 'clamp(20px, 2.4vw, 28px)',
|
||||
border: '1px solid rgba(255, 255, 255, 0.12)',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
@@ -377,8 +393,8 @@ export default function ProblemSection({ isLoaded = true }: ProblemSectionProps)
|
||||
overflow: 'hidden',
|
||||
}}
|
||||
>
|
||||
<div style={{ width: card.wide ? '42%' : '52%', paddingRight: '12px', position: 'relative', zIndex: 2 }}>
|
||||
{card.icon}
|
||||
<div className="problem-card-text" style={{ width: card.wide ? '42%' : '52%', paddingRight: '12px', position: 'relative', zIndex: 2 }}>
|
||||
<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' }}>
|
||||
{card.title}
|
||||
</h3>
|
||||
@@ -387,7 +403,7 @@ export default function ProblemSection({ isLoaded = true }: ProblemSectionProps)
|
||||
</p>
|
||||
</div>
|
||||
{card.wide ? (
|
||||
<div style={{
|
||||
<div className="problem-card-art problem-card-art--wide" style={{
|
||||
position: 'absolute',
|
||||
right: '-6px',
|
||||
bottom: '-6px',
|
||||
@@ -410,7 +426,7 @@ export default function ProblemSection({ isLoaded = true }: ProblemSectionProps)
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<div style={{
|
||||
<div className="problem-card-art" style={{
|
||||
position: 'absolute',
|
||||
right: '-22px',
|
||||
bottom: '-22px',
|
||||
@@ -440,6 +456,86 @@ export default function ProblemSection({ isLoaded = true }: ProblemSectionProps)
|
||||
</div>
|
||||
|
||||
<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 {
|
||||
display: grid;
|
||||
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-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) {
|
||||
#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; }
|
||||
|
||||
@@ -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.',
|
||||
accent: '#f4be28',
|
||||
accentRgb: '244, 190, 40',
|
||||
tags: ['Footfall Tracking', 'Heatmaps', 'Behavior Analysis'],
|
||||
tags: ['Footfall Tracking', 'Behavior Analysis'],
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
@@ -63,10 +63,10 @@ const PRODUCTS: Product[] = [
|
||||
title: 'Identiq',
|
||||
subtitle: 'Consumer Loyalty Platform',
|
||||
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',
|
||||
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={{
|
||||
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',
|
||||
}}>A</span>
|
||||
}}>L</span>
|
||||
<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>
|
||||
</div>
|
||||
@@ -288,7 +288,7 @@ function ProductVisual({ product }: { product: Product }) {
|
||||
<div className="pv-sheen" />
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start' }}>
|
||||
<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>
|
||||
<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>
|
||||
|
||||
@@ -19,25 +19,28 @@ interface ShiftSectionProps {
|
||||
const GREEN_CARDS = [
|
||||
{
|
||||
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',
|
||||
},
|
||||
{
|
||||
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',
|
||||
},
|
||||
{
|
||||
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',
|
||||
},
|
||||
];
|
||||
|
||||
const BLACK_CARDS = [
|
||||
{
|
||||
title: 'Earn Daily',
|
||||
description: 'Customers earn LYTs through daily app activities',
|
||||
title: 'Earn LYTs',
|
||||
description: 'Every visit, check-in, and interaction helps you stack more LYTs.',
|
||||
icon: (
|
||||
<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>
|
||||
@@ -49,8 +52,8 @@ const BLACK_CARDS = [
|
||||
image: '/shift/4.png',
|
||||
},
|
||||
{
|
||||
title: 'Game Campaigns',
|
||||
description: 'Game-based campaigns drive footfall with excitement',
|
||||
title: 'LYT Challenges',
|
||||
description: 'Complete missions, discover new places, and unlock exclusive experiences.',
|
||||
icon: (
|
||||
<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>
|
||||
@@ -63,8 +66,8 @@ const BLACK_CARDS = [
|
||||
image: '/shift/5.png',
|
||||
},
|
||||
{
|
||||
title: 'Smart Coupons',
|
||||
description: 'Smart surprise coupons create a daily reason to engage',
|
||||
title: 'LYT Drops',
|
||||
description: 'AI delivers personalized drops and surprises when they matter most.',
|
||||
icon: (
|
||||
<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>
|
||||
@@ -74,8 +77,8 @@ const BLACK_CARDS = [
|
||||
image: '/shift/6.png',
|
||||
},
|
||||
{
|
||||
title: 'Live Discovery',
|
||||
description: 'Real-time discovery of nearby stores and live offers',
|
||||
title: 'Discover Nearby',
|
||||
description: 'Explore local businesses, trending places, and experiences happening around you.',
|
||||
icon: (
|
||||
<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>
|
||||
@@ -85,8 +88,8 @@ const BLACK_CARDS = [
|
||||
image: '/shift/7.png',
|
||||
},
|
||||
{
|
||||
title: 'Deepens Loyalty',
|
||||
description: 'Every store visit earns more rewards and deepens loyalty',
|
||||
title: 'Get LIT',
|
||||
description: 'Spend your LYTs on experiences, unlock perks, and level up your shopping journey.',
|
||||
icon: (
|
||||
<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>
|
||||
@@ -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)' }}>
|
||||
<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>
|
||||
</div>
|
||||
</div>
|
||||
@@ -201,35 +204,48 @@ export default function ShiftSection({ isLoaded = true }: ShiftSectionProps) {
|
||||
clickEffect={true}
|
||||
particleCount={6}
|
||||
>
|
||||
<div style={{ position: 'relative', zIndex: 2, width: '52%', display: 'flex', flexDirection: 'column', height: '100%', justifyContent: 'space-between' }}>
|
||||
<div style={{ display: 'flex', alignItems: 'baseline', gap: 1 }}>
|
||||
<span style={{ fontSize: 'clamp(2.5rem, 3.8vw, 3.5rem)', fontWeight: 900, color: '#ffffff', fontFamily: 'Sora, sans-serif', letterSpacing: '-0.03em', lineHeight: 1 }}>
|
||||
{card.value}+
|
||||
<div style={{ position: 'relative', zIndex: 2, width: '62%', display: 'flex', flexDirection: 'column', height: '100%', justifyContent: 'flex-start' }}>
|
||||
<div style={{ display: 'flex', alignItems: 'baseline', gap: 2 }}>
|
||||
<span style={{ fontSize: 'clamp(2.6rem, 4vw, 3.6rem)', fontWeight: 900, color: '#ffffff', fontFamily: 'Sora, sans-serif', letterSpacing: '-0.04em', lineHeight: 1 }}>
|
||||
{card.value}
|
||||
</span>
|
||||
<span style={{ fontSize: 'clamp(1.6rem, 2.4vw, 2.1rem)', fontWeight: 800, color: accent, fontFamily: 'Sora, sans-serif', lineHeight: 1 }}>+</span>
|
||||
</div>
|
||||
<div style={{ marginTop: 18, maxWidth: '230px' }}>
|
||||
<div style={{
|
||||
marginTop: 'auto',
|
||||
fontSize: '0.68rem',
|
||||
fontSize: '0.7rem',
|
||||
fontWeight: 800,
|
||||
color: 'rgba(255, 255, 255, 0.8)',
|
||||
color: '#ffffff',
|
||||
fontFamily: 'Sora, sans-serif',
|
||||
textTransform: 'uppercase',
|
||||
letterSpacing: '0.06em',
|
||||
lineHeight: 1.4,
|
||||
letterSpacing: '0.07em',
|
||||
lineHeight: 1.35,
|
||||
whiteSpace: 'pre-line',
|
||||
maxWidth: '180px'
|
||||
}}>
|
||||
{card.label}
|
||||
</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>
|
||||
|
||||
{/* Papercraft Image */}
|
||||
<div className="shift-card-art" style={{
|
||||
position: 'absolute',
|
||||
right: i === 2 ? '-12px' : '-16px',
|
||||
bottom: i === 2 ? '-12px' : '-16px',
|
||||
width: i === 2 ? '56%' : '52%',
|
||||
height: '90%',
|
||||
right: '-14px',
|
||||
bottom: '-14px',
|
||||
width: i === 2 ? '46%' : '42%',
|
||||
height: '82%',
|
||||
opacity: 0.96,
|
||||
pointerEvents: 'none',
|
||||
zIndex: 1,
|
||||
}}>
|
||||
@@ -266,7 +282,13 @@ export default function ShiftSection({ isLoaded = true }: ShiftSectionProps) {
|
||||
particleCount={6}
|
||||
>
|
||||
<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}
|
||||
</div>
|
||||
<h3 style={{
|
||||
@@ -380,23 +402,40 @@ export default function ShiftSection({ isLoaded = true }: ShiftSectionProps) {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
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 {
|
||||
background: linear-gradient(135deg, #134e2e 0%, #0d3821 100%);
|
||||
border: 1px solid rgba(255, 255, 255, 0.12);
|
||||
box-shadow: 0 10px 30px -12px rgba(19, 78, 46, 0.35);
|
||||
background: linear-gradient(150deg, #1a6b3e 0%, #124a2b 52%, #0c3620 100%);
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
box-shadow: 0 16px 40px -18px rgba(12, 54, 32, 0.55);
|
||||
}
|
||||
.shift-bento-card--black {
|
||||
background: #171512;
|
||||
border: 1px solid rgba(255, 255, 255, 0.08);
|
||||
box-shadow: 0 10px 30px -12px rgba(0,0,0,0.5);
|
||||
background: linear-gradient(160deg, #1d1b17 0%, #131210 100%);
|
||||
border: 1px solid rgba(255, 255, 255, 0.07);
|
||||
box-shadow: 0 16px 40px -18px rgba(0,0,0,0.6);
|
||||
}
|
||||
.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 {
|
||||
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 */
|
||||
@@ -437,15 +476,16 @@ export default function ShiftSection({ isLoaded = true }: ShiftSectionProps) {
|
||||
/* Pin card art to the bottom-right corner on narrow screens,
|
||||
where full-width cards would otherwise let it sprawl over the text */
|
||||
#shift .shift-card-art {
|
||||
width: 62% !important;
|
||||
height: 100% !important;
|
||||
width: 56% !important;
|
||||
height: 66% !important;
|
||||
right: 0 !important;
|
||||
bottom: 0 !important;
|
||||
}
|
||||
#shift .shift-card-art-img {
|
||||
object-fit: contain !important;
|
||||
object-position: bottom right !important;
|
||||
transform: none !important;
|
||||
transform: scale(1.08) !important;
|
||||
transform-origin: bottom right !important;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ const STAGES: Stage[] = [
|
||||
},
|
||||
{
|
||||
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',
|
||||
icon: (
|
||||
<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;
|
||||
|
||||
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(
|
||||
'.wwd-header-el',
|
||||
{ opacity: 0, y: 36, filter: 'blur(6px)' },
|
||||
{
|
||||
opacity: 1, y: 0, filter: 'blur(0px)',
|
||||
duration: 1, stagger: 0.18, ease: 'expo.out',
|
||||
scrollTrigger: { trigger: '.wwd-header', start: 'top 85%', toggleActions: 'play none none reset' },
|
||||
opacity: 0,
|
||||
y: prefersReducedMotion ? 0 : 30,
|
||||
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
|
||||
// edge, then its inner content cascades in. One scroll-triggered
|
||||
// timeline keeps card + content in sync.
|
||||
// Cards: modern 3D lift + unblur reveal, smoothly staggered across the row
|
||||
const cards = gsap.utils.toArray<HTMLElement>('.wwd-card');
|
||||
const grid = document.querySelector('.wwd-grid-container');
|
||||
|
||||
const revealTl = gsap.timeline({
|
||||
scrollTrigger: { trigger: grid, start: 'top 82%', toggleActions: 'play none none reset' },
|
||||
});
|
||||
|
||||
revealTl.fromTo(cards,
|
||||
{ opacity: 0, y: 90, rotationX: -32, transformOrigin: '50% 100%', transformPerspective: 1100 },
|
||||
{ opacity: 1, y: 0, rotationX: 0, duration: 0.9, ease: 'power4.out', stagger: 0.14 },
|
||||
0
|
||||
if (prefersReducedMotion) {
|
||||
gsap.fromTo(
|
||||
cards,
|
||||
{ opacity: 0 },
|
||||
{
|
||||
opacity: 1,
|
||||
duration: 0.5,
|
||||
stagger: 0.08,
|
||||
scrollTrigger: { trigger: grid, start: 'top 85%', toggleActions: 'play none none reset' },
|
||||
}
|
||||
);
|
||||
|
||||
cards.forEach((card, i) => {
|
||||
const at = i * 0.14 + 0.35;
|
||||
revealTl
|
||||
.fromTo(card.querySelector('.wwd-icon'),
|
||||
{ opacity: 0, scale: 0.4, rotate: -20 },
|
||||
{ opacity: 1, scale: 1, rotate: 0, duration: 0.5, ease: 'back.out(2.2)' }, at)
|
||||
.fromTo(card.querySelector('.wwd-title'),
|
||||
{ opacity: 0, y: 16 },
|
||||
{ opacity: 1, y: 0, duration: 0.45, ease: 'power3.out' }, at + 0.12)
|
||||
.fromTo(card.querySelector('.wwd-tagline'),
|
||||
{ opacity: 0, y: 12 },
|
||||
{ opacity: 1, y: 0, duration: 0.4, ease: 'power3.out' }, at + 0.22)
|
||||
.fromTo(card.querySelector('.wwd-detail'),
|
||||
{ opacity: 0, y: 10 },
|
||||
{ opacity: 1, y: 0, duration: 0.4, ease: 'power3.out' }, at + 0.3);
|
||||
});
|
||||
} else {
|
||||
gsap.fromTo(
|
||||
cards,
|
||||
{
|
||||
opacity: 0,
|
||||
y: 72,
|
||||
scale: 0.92,
|
||||
rotationX: 14,
|
||||
transformOrigin: '50% 100%',
|
||||
transformPerspective: 900,
|
||||
filter: 'blur(10px)',
|
||||
},
|
||||
{
|
||||
opacity: 1,
|
||||
y: 0,
|
||||
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);
|
||||
|
||||
return () => ctx.revert();
|
||||
|
||||
@@ -16,11 +16,11 @@ export interface HeroSlideData {
|
||||
export const HERO_SLIDES: HeroSlideData[] = [
|
||||
{
|
||||
id: 'intro',
|
||||
badge: 'AI-Powered Loyalty',
|
||||
headline: 'Turn Foot Traffic Into Fans',
|
||||
highlightWords: ['Fans'],
|
||||
badge: 'AI-Powered Retail Intelligence',
|
||||
headline: 'Turn Every Visit Into Loyalty',
|
||||
highlightWords: ['Loyalty'],
|
||||
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',
|
||||
ctaHref: '/contacts',
|
||||
secondaryLabel: 'See How It Works',
|
||||
@@ -30,11 +30,11 @@ export const HERO_SLIDES: HeroSlideData[] = [
|
||||
},
|
||||
{
|
||||
id: 'app',
|
||||
badge: 'Built For Every Shopper',
|
||||
headline: 'Shopping, But Make It Rewarding',
|
||||
highlightWords: ['Rewarding'],
|
||||
badge: 'Crafted For Every Shopper',
|
||||
headline: 'Shopping, Elevated To An Experience',
|
||||
highlightWords: ['Experience'],
|
||||
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',
|
||||
ctaHref: '/for_people',
|
||||
secondaryLabel: 'Get Early Access',
|
||||
@@ -44,11 +44,11 @@ export const HERO_SLIDES: HeroSlideData[] = [
|
||||
},
|
||||
{
|
||||
id: 'ecosystem',
|
||||
badge: 'The Full Stack',
|
||||
headline: 'Six Tools. One Mega Brain.',
|
||||
highlightWords: ['Mega', 'Brain.'],
|
||||
badge: 'One Intelligent Platform',
|
||||
headline: 'Six Products. One Brain.',
|
||||
highlightWords: ['One', 'Brain.'],
|
||||
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',
|
||||
ctaHref: '/solutions_page',
|
||||
secondaryLabel: 'Meet the Tools',
|
||||
|
||||
Reference in New Issue
Block a user