updated sections design and content

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

View File

@@ -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 58107);
an overflow box crops the transparent top/bottom padding so it fills at size */}
<span className="ly-footer-logo" style={{ display: 'block', width: 300, maxWidth: '100%', aspectRatio: '250 / 58', overflow: 'hidden' }}>
<Image src="/images/logo-dark.png" alt="Loyaly.AI" width={250} height={150} style={{ width: '100%', height: '100%', objectFit: 'cover', objectPosition: 'center 55%', display: 'block' }} />
</span>
</Link>
<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; }
}

View File

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

View File

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

View File

@@ -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 (blurAmount && i < topCardIndex) {
const depthInStack = topCardIndex - i;
blur = Math.max(0, depthInStack * blurAmount);
}
if (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,

View File

@@ -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' }}
/>

View File

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

View File

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

View File

@@ -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' },
];

View File

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

View File

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

View File

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

View File

@@ -72,7 +72,7 @@ export default function SpendAnywhereSection() {
fontSize: 'clamp(17px, 1.7vw, 21px)', lineHeight: 1.3, color: '#fff', fontFamily: 'Sora, sans-serif',
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>

View File

@@ -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&apos;s offline retail market is worth 2.1 lakh crore. Yet rewards penetration sits at effectively zero. Loyaly exists to close that gap, permanently.
India&apos;s offline retail market is worth 2.1 lakh crore. Yet rewards penetration sits at effectively zero. LytsUp exists to close that gap, permanently.
</p>
{/* Data bars */}

View File

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

View File

@@ -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&apos;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; }

View File

@@ -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={{ 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 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>
<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; }

View File

@@ -33,7 +33,7 @@ const PRODUCTS: Product[] = [
'AI powered footfall analytics and behavioral intelligence. Understand how customers move, dwell, and engage, turning raw foot traffic into rich, actionable insights.',
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>

View File

@@ -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: 'auto',
fontSize: '0.68rem',
fontWeight: 800,
color: 'rgba(255, 255, 255, 0.8)',
fontFamily: 'Sora, sans-serif',
textTransform: 'uppercase',
letterSpacing: '0.06em',
lineHeight: 1.4,
whiteSpace: 'pre-line',
maxWidth: '180px'
}}>
{card.label}
<div style={{ marginTop: 18, maxWidth: '230px' }}>
<div style={{
fontSize: '0.7rem',
fontWeight: 800,
color: '#ffffff',
fontFamily: 'Sora, sans-serif',
textTransform: 'uppercase',
letterSpacing: '0.07em',
lineHeight: 1.35,
whiteSpace: 'pre-line',
}}>
{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;
}
}

View File

@@ -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: 0,
y: prefersReducedMotion ? 0 : 30,
filter: prefersReducedMotion ? 'none' : 'blur(8px)'
},
{
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: 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
);
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);
});
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' },
}
);
} 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();

View File

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