diff --git a/public/logo_icons/apple-round.svg b/public/logo_icons/apple-round.svg new file mode 100644 index 0000000..0c53155 --- /dev/null +++ b/public/logo_icons/apple-round.svg @@ -0,0 +1,11 @@ + + + + + + \ No newline at end of file diff --git a/public/logo_icons/apple.jpg b/public/logo_icons/apple.jpg new file mode 100644 index 0000000..9a90d88 Binary files /dev/null and b/public/logo_icons/apple.jpg differ diff --git a/public/logo_icons/images.png b/public/logo_icons/images.png new file mode 100644 index 0000000..ef12c33 Binary files /dev/null and b/public/logo_icons/images.png differ diff --git a/src/app/about_us/page.tsx b/src/app/about_us/page.tsx index dc50e88..5e52552 100644 --- a/src/app/about_us/page.tsx +++ b/src/app/about_us/page.tsx @@ -17,15 +17,6 @@ function Reveal({ children, delay = 0 }: { children: React.ReactNode; delay?: nu ); } -const VALUES = [ - { n: '01', title: 'Intelligence first', desc: 'Every product decision starts with data, not instinct.' }, - { n: '02', title: 'Merchant obsessed', desc: 'We build for the store owner who works 14-hour days.' }, - { n: '03', title: 'Radical transparency', desc: 'No black boxes. Our AI explains every recommendation.' }, - { n: '04', title: 'Build to last', desc: 'We optimise for long-term impact, not vanity metrics.' }, -]; - -const TEAM: { name: string; role: string; initials: string; color: string }[] = []; - export default function AboutUsPage() { return (
@@ -101,18 +92,18 @@ export default function AboutUsPage() { {[ { label: 'Mission', bg: '#07070d', textColor: '#fff', accent: '#f4be28', - body: 'To transform physical retail with AI-driven intelligence and meaningful customer engagement.', + body: 'Loyaly exists to close the gap between digital discovery and physical purchase. We give local stores the tools to compete, and give shoppers a reason to keep coming back.', }, { label: 'Vision', bg: '#f4be28', textColor: '#111', accent: '#c9960f', - body: 'To become the leading retail intelligence platform across global markets.', + body: 'Empowering every neighbourhood, making exceptional in-store experiences and real rewards accessible to all.', }, ].map((mv, i) => (
{mv.label}
@@ -125,35 +116,39 @@ export default function AboutUsPage() {
- {/* ── VALUES ── */} + {/* ── MARKET OPPORTUNITY ── */}
- -
How We Work
-

- What we believe. -

-
-
- {VALUES.map((v, i) => ( - -
- {v.n} -

{v.title}

-

{v.desc}

-
-
- ))} +
+ +
Market Opportunity
+

+ 13 Million Stores.
One Opportunity. +

+

+ India's retail market is one of the largest and fastest-growing in the world. We're building Loyaly for the stores that power it, and the shoppers who love them. +

+
+ +
+ {[ + { val: '13 Million+', label: 'Total Retail Stores Across India' }, + { val: '2 Million+', label: 'Organised & High-Footfall Stores' }, + { val: '50,000+', label: 'Stores In Our Launch Cities' }, + ].map((m) => ( +
+
{m.val}
+
{m.label}
+
+ ))} +
+
{/* ── TEAM ── */} - {/* ── CULTURE CLOSE ── */} + {/* ── CLOSE: POINT TO THE CREW ── */}
"We're not just building a product. We're redefining retail."

- Join Us → +
+ See Our Products → + Join Us +
diff --git a/src/app/for_people/page.tsx b/src/app/for_people/page.tsx index 8af6f1c..26442f2 100644 --- a/src/app/for_people/page.tsx +++ b/src/app/for_people/page.tsx @@ -3,6 +3,7 @@ import React from 'react'; import VerticalScrollWrapper from '@/components/for-people/VerticalScrollWrapper'; import HeroSection from '@/components/for-people/HeroSection'; +import PillarsSection from '@/components/for-people/PillarsSection'; import WhyLoyalySection from '@/components/for-people/WhyLoyalySection'; import DiscoverDealsSection from '@/components/for-people/DiscoverDealsSection'; import EarnRewardsSection from '@/components/for-people/EarnRewardsSection'; @@ -14,6 +15,7 @@ import FinalCTASection from '@/components/for-people/FinalCTASection'; const SECTIONS = [ 'Intro', 'The Gap', + 'Save More', 'Discover', 'Earn', 'Spend', @@ -28,6 +30,7 @@ export default function ForPeoplePage() { + diff --git a/src/app/page.tsx b/src/app/page.tsx index fb6770c..caf0659 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -319,6 +319,9 @@ export default function IndexPage() { Walk In Into a
Loyal Customer +

+ Offline is the new Online. +

Loyaly.ai turns everyday digital engagement into real world shopping rewards. Customers earn LYTs through games and daily activities, then redeem them at offline stores near them.

@@ -444,6 +447,9 @@ export default function IndexPage() { Walk In Into a
Loyal Customer +

+ Offline is the new Online. +

Loyaly.ai turns everyday digital engagement into real world shopping rewards. Customers earn LYTs through games and daily activities, then redeem them at offline stores near them.

diff --git a/src/app/solutions_page/page.tsx b/src/app/solutions_page/page.tsx index 9833af1..ac98abc 100644 --- a/src/app/solutions_page/page.tsx +++ b/src/app/solutions_page/page.tsx @@ -1,23 +1,30 @@ 'use client'; -import React, { useState } from 'react'; +import React from 'react'; import Link from 'next/link'; import Image from 'next/image'; -import GSAPAnimator from '@/components/GSAPAnimator'; import { useReveal } from '@/hooks/useReveal'; +import GSAPAnimator from '@/components/GSAPAnimator'; import ScrollStack, { ScrollStackItem } from '@/components/ScrollStack'; -function RevealBlock({ children, delay = 0 }: { children: React.ReactNode; delay?: number }) { +function Reveal({ children, delay = 0 }: { children: React.ReactNode; delay?: number }) { const { ref, visible } = useReveal(); return (
{children}
); } +const VALUES = [ + { n: '01', title: 'Intelligence first', desc: 'Every product decision starts with data, not instinct.' }, + { n: '02', title: 'Merchant obsessed', desc: 'We build for the store owner who works 14-hour days.' }, + { n: '03', title: 'Radical transparency', desc: 'No black boxes. Our AI explains every recommendation.' }, + { n: '04', title: 'Build to last', desc: 'We optimise for long-term impact, not vanity metrics.' }, +]; + const PRODUCTS = [ { n: '01', title: 'Behavision', subtitle: 'AI Powered Footfall Analytics', color: '#f4be28', @@ -65,124 +72,76 @@ const PRODUCTS = [ }, ]; -const CAPS = [ - { - n: '01', title: 'Merchant Campaign Platform', color: '#f4be28', - desc: 'Register your store, upload products and inventory, then launch interactive promotional campaigns in minutes. Define maximum discounts per product and track performance in real time.', - metrics: [{ val: '5+', lbl: 'Game formats' }, { val: '1-click', lbl: 'Campaign setup' }], - }, - { - n: '02', title: 'Game Based Discount Engine', color: '#a78bfa', - desc: 'Select a product, choose a game (Maze, Spin Wheel, Scratch Card, or Match Master) and set a maximum discount. Customers play once and discover their reward only after completing the game.', - metrics: [{ val: '4×', lbl: 'Engagement lift' }, { val: '100%', lbl: 'Margin controlled' }], - }, - { - n: '03', title: 'Smart Coupon System', color: '#34d399', - desc: 'Generate daily surprise coupons through the Battery Challenge and other activities. Offer flat discounts, BOGO, percentage-off deals, festival specials, and brand promotions, fresh every day.', - metrics: [{ val: '6', lbl: 'Coupon types' }, { val: 'Daily', lbl: 'Fresh surprises' }], - }, - { - n: '04', title: 'Footfall & Campaign Analytics', color: '#f97316', - desc: 'Track which campaigns drove store visits, measure conversion rates, monitor repeat footfall, and optimize your promotional budget with a real-time analytics dashboard.', - metrics: [{ val: '98%', lbl: 'Count accuracy' }, { val: '<9ms', lbl: 'Real-time latency' }], - }, -]; - -export default function SolutionsPage() { - const [hovered, setHovered] = useState(null); - +export default function MeetTheCrewPage() { return (
{/* ── HERO ── */}
{/* Background photo */} - -
+ +
{/* Accent blobs */} -
-
- {/* Animated rings */} - {[600, 900, 1200].map((s, i) => ( -
- ))} +
+
+ {/* Big ghost text */} +
LOYALY
-
+
-

- Built for
Modern
- Retail Growth. +

+ Meet the
+ Crew.

-

- Instead of waiting for customers to walk in, create exciting reasons for them to come, with game based campaigns, smart coupons, and a loyalty ecosystem that rewards every visit. +

+ The builders, thinkers, and retail obsessives behind Loyaly, working every day to make offline shopping as smart as online.

-
- Explore Solutions → - Book Demo -
- {/* ── CAPABILITIES ── */} + {/* ── VALUES ── */}
- -
-
-
Capabilities
-

- Four tools.
One merchant platform. -

-
-

- Every tool works independently and amplifies the others, giving merchants a complete system to attract, engage, and retain customers. -

-
-
- -
- {CAPS.map((cap, i) => ( - -
setHovered(i)} - onMouseLeave={() => setHovered(null)} - className="sp-cap-row" - style={{ - display: 'grid', gridTemplateColumns: '80px 1fr 1fr auto', - alignItems: 'center', gap: '4vw', - padding: '40px 0', - borderBottom: '1px solid rgba(0,0,0,0.07)', - cursor: 'default', - transition: 'all 0.3s ease', - }} - > - {cap.n} -

{cap.title}

-

{cap.desc}

-
- {cap.metrics.map((m, j) => ( -
-
{m.val}
-
{m.lbl}
-
- ))} -
+ +
How We Work
+

+ What we believe. +

+
+
+ {VALUES.map((v, i) => ( + +
+ {v.n} +

{v.title}

+

{v.desc}

- +
))}
@@ -190,15 +149,15 @@ export default function SolutionsPage() { {/* ── OUR PRODUCTS ── */}
- -
Our Products
+ +
Meet the Products

Four products.
One ecosystem.

- Each product solves a distinct part of the retail journey, and together they form one connected platform, from footfall to spend to loyalty. + Behavision, SpendSense, Dyscount, and Identiq, each solves a distinct part of the retail journey, and together they form one connected platform, from footfall to spend to loyalty.

-
+
@@ -209,7 +168,7 @@ export default function SolutionsPage() { border: `1px solid ${p.color}40`, borderRadius: 28, padding: 'clamp(28px, 3.2vw, 48px)', height: '100%', boxSizing: 'border-box', }}> -
+
{/* Left — identity + description */}
@@ -264,63 +223,31 @@ export default function SolutionsPage() {
- {/* ── WHY IT MATTERS ── */} -
-
- -
- "Every digital interaction should lead to a{' '} - meaningful in-store experience." -
-
-

Loyaly.ai, 2025

- -
- - {/* ── FINAL CTA ── */} -
- -

- See every solution working together. -

-

- Get a tailored walkthrough of how Loyaly.ai's merchant platform, game campaigns, and coupon engine fit your specific retail format. + {/* ── CULTURE CLOSE ── */} +

+
+ +

+ "We're not just building a product. We're redefining retail."

-
- Book Demo → - Explore Solutions -
- - -
- {[ - { v: '10K+', l: 'Partner stores' }, { v: '50K+', l: 'Active users' }, - { v: '98%', l: 'Uptime SLA' }, { v: '<9ms', l: 'Response time' }, - ].map((s, i) => ( -
-
{s.v}
-
{s.l}
-
- ))} -
-
+ Join Us → +
diff --git a/src/app/use_cases/page.tsx b/src/app/use_cases/page.tsx index 36f6926..32761f2 100644 --- a/src/app/use_cases/page.tsx +++ b/src/app/use_cases/page.tsx @@ -14,6 +14,70 @@ const OUTCOMES = [ { stat: '9ms', label: 'Real-time decision latency' }, ]; +const CAPS = [ + { + n: '01', title: 'Merchant Campaign Platform', color: '#f4be28', + desc: 'Register your store, upload products and inventory, then launch interactive promotional campaigns in minutes. Define maximum discounts per product and track performance in real time.', + metrics: [{ val: '5+', lbl: 'Game formats' }, { val: '1-click', lbl: 'Campaign setup' }], + }, + { + n: '02', title: 'Game Based Discount Engine', color: '#a78bfa', + desc: 'Select a product, choose a game (Maze, Spin Wheel, Scratch Card, or Match Master) and set a maximum discount. Customers play once and discover their reward only after completing the game.', + metrics: [{ val: '4×', lbl: 'Engagement lift' }, { val: '100%', lbl: 'Margin controlled' }], + }, + { + n: '03', title: 'Smart Coupon System', color: '#34d399', + desc: 'Generate daily surprise coupons through the Battery Challenge and other activities. Offer flat discounts, BOGO, percentage-off deals, festival specials, and brand promotions, fresh every day.', + metrics: [{ val: '6', lbl: 'Coupon types' }, { val: 'Daily', lbl: 'Fresh surprises' }], + }, + { + n: '04', title: 'Footfall & Campaign Analytics', color: '#f97316', + desc: 'Track which campaigns drove store visits, measure conversion rates, monitor repeat footfall, and optimize your promotional budget with a real-time analytics dashboard.', + metrics: [{ val: '98%', lbl: 'Count accuracy' }, { val: '<9ms', lbl: 'Real-time latency' }], + }, +]; + +const STEPS = [ + { + n: '01', title: 'Sign Up', desc: 'Create your Loyaly merchant account in minutes.', color: '#f4be28', + icon: , + }, + { + n: '02', title: 'Upload Your Products', desc: 'Add your catalogue, deals, and offers to the platform.', color: '#a78bfa', + icon: , + }, + { + n: '03', title: 'Publish Your Offers', desc: 'Go live with targeted deals your nearby customers will see instantly.', color: '#34d399', + icon: , + }, + { + n: '04', title: 'Connect to Customers', desc: 'Loyaly matches you with shoppers in your area who are ready to buy.', color: '#f97316', + icon: , + }, + { + n: '05', title: 'Close the Deal', desc: 'Customers walk in. They purchase. You grow.', color: '#f4be28', + icon: , + }, +]; + +const PILLARS = [ + { + title: 'Get Online', color: '#f4be28', + desc: 'Your store, visible to thousands of local shoppers, without building a website.', + icon: , + }, + { + title: 'Get Noticed', color: '#a78bfa', + desc: "Push real-time offers and proximity alerts that reach customers the moment they're nearby.", + icon: , + }, + { + title: 'Get Simplified', color: '#34d399', + desc: 'One dashboard. All your deals, customers, and performance, managed in one place.', + icon: , + }, +]; + const WHO = [ { label: 'Retail Stores', @@ -48,6 +112,7 @@ function RevealBlock({ children, delay = 0, className = '' }: { children: React. export default function ForBusinessPage() { const [countVisible, setCountVisible] = useState(false); + const [hovered, setHovered] = useState(null); const statsRef = useRef(null); useEffect(() => { @@ -162,6 +227,186 @@ export default function ForBusinessPage() { {/* ── PRODUCTS ── */} + {/* ── CAPABILITIES ── */} +
+ +
+
+
Capabilities
+

+ Four tools.
One merchant platform. +

+
+

+ Every tool works independently and amplifies the others, giving merchants a complete system to attract, engage, and retain customers. +

+
+
+ +
+ {CAPS.map((cap, i) => ( + +
setHovered(i)} + onMouseLeave={() => setHovered(null)} + className="uc-cap-row" + style={{ + display: 'grid', gridTemplateColumns: '80px 1fr 1fr auto', + alignItems: 'center', gap: '4vw', + padding: '40px 0', + borderBottom: '1px solid rgba(0,0,0,0.07)', + cursor: 'default', + transition: 'all 0.3s ease', + }} + > + {cap.n} +

{cap.title}

+

{cap.desc}

+
+ {cap.metrics.map((m, j) => ( +
+
{m.val}
+
{m.lbl}
+
+ ))} +
+
+
+ ))} +
+
+ + {/* ── HOW IT WORKS ── */} +
+
+ +
How It Works
+

+ Live in five steps. +

+
+
+
+ {STEPS.map((step, i) => ( + +
+
+ {step.icon} +
+
+
+ {step.n} +

{step.title}

+
+

{step.desc}

+
+
+
+ ))} +
+
+ + {/* ── MERCHANT BENEFITS ── */} +
+ +
Why Merchants Choose Us
+

+ Three ways we grow your store. +

+
+
+ {PILLARS.map((p, i) => ( + +
+ 0{i + 1} +
{p.icon}
+

{p.title}

+

{p.desc}

+
+
+ + ))} +
+
+ + {/* ── PROXIMITY MARKETING ── */} +
+
+ +
+ + {/* Radar visual */} +
+ {[0, 1, 2].map((r) => ( +
+ ))} +
+ + + +
+
+ + {/* Content */} +
+
Capability Spotlight
+

+ Reach customers the moment they're nearby. +

+

+ 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. +

+
+ {[{ v: 'Instant', l: 'Notification speed' }, { v: '0', l: 'Ad spend required' }, { v: 'Real-time', l: 'Radius targeting' }].map((s) => ( +
+
{s.v}
+
{s.l}
+
+ ))} +
+
+
+ +
+ {/* ── OUTCOMES ── */}
@@ -235,16 +480,31 @@ export default function ForBusinessPage() { ); diff --git a/src/components/About.tsx b/src/components/About.tsx deleted file mode 100644 index 78e5de0..0000000 --- a/src/components/About.tsx +++ /dev/null @@ -1,154 +0,0 @@ -import Image from 'next/image'; -import Link from 'next/link'; - -const FEATURES = [ - { - icon: '👁', - title: 'Turn Footfall into Insight', - description: - 'Real-time visitor tracking and movement analytics reveal exactly how customers move through your store, enabling smarter layout, staffing, and marketing decisions.', - }, - { - icon: '🎯', - title: 'Personalisation, Perfected', - description: - 'AI-driven profiles let you deliver the right offer to the right customer at precisely the right moment — online, in-store, or both.', - }, - { - icon: '⚙️', - title: 'One Engine. Total Intelligence.', - description: - 'A single unified platform connects footfall, loyalty, promotions, and revenue data so every team works from the same source of truth.', - }, -]; - -export default function About() { - return ( -
- {/* Two-column intro */} -
- {/* Image */} -
- Loyaly.AI platform dashboard showing customer intelligence data -
- - {/* Text */} -
-

- About Us -

-

- AI Powered Customer Intelligence for Retail -

-

- Loyaly.ai is an AI powered customer intelligence platform built for modern retail. We help - businesses understand who their customers are, what drives their behaviour, and how to - build lasting loyalty at every touchpoint. -

-

- From footfall tracking and personalised engagement to smart loyalty programmes and revenue - optimisation, Loyaly.AI gives retailers one unified platform to know their customers deeply - and act on that knowledge instantly. -

- - Explore Our Solutions - -
-
- - {/* Three-feature grid */} -
-
- {FEATURES.map(({ icon, title, description }) => ( -
- -

- {title} -

-

- {description} -

-
- ))} -
-
-
- ); -} diff --git a/src/components/BlogSection.tsx b/src/components/BlogSection.tsx deleted file mode 100644 index 67ad10b..0000000 --- a/src/components/BlogSection.tsx +++ /dev/null @@ -1,193 +0,0 @@ -import Image from 'next/image'; -import Link from 'next/link'; - -const CASE_STUDIES = [ - { - slug: 'ai-maximises-discount-strategy', - title: 'Stop Wasting Discounts: How AI Maximises Every Offer You Give', - excerpt: - 'Most retail discounts go to customers who would have bought anyway. Discover how Loyaly.AI\'s promotion intelligence engine targets the right buyers at the right margin.', - tags: ['AI Solutions', 'Retail Intelligence'], - image: '/loyaly_php/assets/images/case-study-2-img-960x718.jpeg', - imageAlt: 'Data visualisation showing AI-optimised discount targeting across customer segments', - readTime: '5 min read', - }, - { - slug: 'ai-redefining-retail-loyalty-2026', - title: 'Beyond Points: How AI is Redefining Retail Loyalty in 2026', - excerpt: - 'Traditional points schemes are losing ground. Learn how AI-driven loyalty programmes build genuine relationships through personalisation, timing, and context-aware rewards.', - tags: ['AI Retail', 'Loyalty Intelligence'], - image: '/loyaly_php/assets/images/case-study-1-img-960x718.jpeg', - imageAlt: 'Retail customer using a loyalty app powered by Loyaly.AI', - readTime: '7 min read', - }, -]; - -export default function BlogSection() { - return ( -
-
- {/* Header */} -
-
-

- Case Studies -

-

- Insights from the Loyaly.AI field -

-
- - All Articles - -
- - {/* Card grid */} -
- {CASE_STUDIES.map(({ slug, title, excerpt, tags, image, imageAlt, readTime }) => ( -
{ - const el = e.currentTarget as HTMLElement; - el.style.transform = 'translateY(-4px)'; - el.style.boxShadow = '0 8px 32px rgba(23,21,18,0.12)'; - }} - onMouseLeave={e => { - const el = e.currentTarget as HTMLElement; - el.style.transform = 'translateY(0)'; - el.style.boxShadow = '0 2px 16px rgba(23,21,18,0.07)'; - }} - > - {/* Image */} - -
- {imageAlt} -
- - - {/* Content */} -
- {/* Tags */} -
- {tags.map(tag => ( - - {tag} - - ))} -
- -

- - {title} - -

- -

- {excerpt} -

- -
- {readTime} - - Read more - -
-
-
- ))} -
-
-
- ); -} diff --git a/src/components/Footer.tsx b/src/components/Footer.tsx index f22618b..f757efe 100644 --- a/src/components/Footer.tsx +++ b/src/components/Footer.tsx @@ -16,9 +16,9 @@ const NAV = [ { title: 'Platform', links: [ - { label: 'Behavision AI', href: '/solutions_page' }, - { label: 'SpendSense AI', href: '/solutions_page' }, - { label: 'Dyscount AI', href: '/solutions_page' }, + { label: 'Behavision AI', href: '/use_cases' }, + { label: 'SpendSense AI', href: '/use_cases' }, + { label: 'Dyscount AI', href: '/use_cases' }, ], }, { diff --git a/src/components/GSAPReveal.tsx b/src/components/GSAPReveal.tsx deleted file mode 100644 index 9340161..0000000 --- a/src/components/GSAPReveal.tsx +++ /dev/null @@ -1,28 +0,0 @@ -'use client'; - -import React from 'react'; -import { useGSAPReveal, RevealAnimation } from '@/hooks/useGSAPReveal'; - -interface Props { - children: React.ReactNode; - delay?: number; - animation?: RevealAnimation; - duration?: number; - ease?: string; - start?: string; - className?: string; - style?: React.CSSProperties; - as?: keyof React.JSX.IntrinsicElements; -} - -export default function GSAPReveal({ - children, delay = 0, animation = 'fade-up', - duration = 1.0, ease, start, className, style, -}: Props) { - const ref = useGSAPReveal({ delay, animation, duration, ease, start }); - return ( -
- {children} -
- ); -} diff --git a/src/components/Partners.tsx b/src/components/Partners.tsx deleted file mode 100644 index ed98373..0000000 --- a/src/components/Partners.tsx +++ /dev/null @@ -1,153 +0,0 @@ -import Image from 'next/image'; - -const PARTNERS = [ - { name: 'Partner 1', src: '/loyaly_php/assets/images/partners-1.png' }, - { name: 'Partner 2', src: '/loyaly_php/assets/images/partners-2.png' }, - { name: 'Partner 3', src: '/loyaly_php/assets/images/partners-3.png' }, - { name: 'Partner 4', src: '/loyaly_php/assets/images/partners-4.png' }, - { name: 'Partner 5', src: '/loyaly_php/assets/images/partners-5.png' }, - { name: 'Partner 6', src: '/loyaly_php/assets/images/partners-6.png' }, -]; - -// Duplicate list so the CSS marquee loops seamlessly -const TRACK = [...PARTNERS, ...PARTNERS]; - -export default function Partners() { - return ( -
-
-

- Our Partners -

-

- Our trusted collaborators in progress and success -

-
- - {/* Marquee track */} -
- ); -} diff --git a/src/components/PhoneWidget.tsx b/src/components/PhoneWidget.tsx deleted file mode 100644 index b3c8461..0000000 --- a/src/components/PhoneWidget.tsx +++ /dev/null @@ -1,175 +0,0 @@ -'use client'; - -import React, { useRef, useEffect, useCallback } from 'react'; - -export default function PhoneWidget() { - const stageRef = useRef(null); - - const onMove = useCallback((e: MouseEvent) => { - const el = stageRef.current; - if (!el) return; - const r = el.getBoundingClientRect(); - const px = (e.clientX - r.left) / r.width - 0.5; - const py = (e.clientY - r.top) / r.height - 0.5; - el.style.setProperty('--rx', `${(-py * 8).toFixed(2)}deg`); - el.style.setProperty('--ry', `${(px * 10).toFixed(2)}deg`); - el.style.setProperty('--tx', `${(px * 18).toFixed(1)}px`); - el.style.setProperty('--ty', `${(py * 18).toFixed(1)}px`); - }, []); - - const onLeave = useCallback(() => { - const el = stageRef.current; - if (!el) return; - el.style.setProperty('--rx', '0deg'); - el.style.setProperty('--ry', '0deg'); - el.style.setProperty('--tx', '0px'); - el.style.setProperty('--ty', '0px'); - }, []); - - useEffect(() => { - const el = stageRef.current; - if (!el) return; - el.addEventListener('mousemove', onMove); - el.addEventListener('mouseleave', onLeave); - return () => { - el.removeEventListener('mousemove', onMove); - el.removeEventListener('mouseleave', onLeave); - }; - }, [onMove, onLeave]); - - return ( - <> - - -
-
- {/* Glow ring */} -
- - {/* Phone shell */} -
- {/* Shimmer sweep */} -
-
-
- - {/* Dynamic island */} -
-
-
-
-
-
- - {/* Header */} -
-
Good Morning
-
Loyaly ✦
-
- - {/* LYTs balance card */} -
-
-
Total LYTs
-
284
-
≈ ₹284 redeemable
-
- - {/* Activity feed */} -
- {[ - { label: 'Daily Login', pts: '+50', color: '#4ade80' }, - { label: 'Walking 5k Steps', pts: '+80', color: '#4ade80' }, - { label: 'Spin Wheel', pts: '-50', color: '#f87171' }, - ].map((item, i) => ( -
- {item.label} - {item.pts} -
- ))} -
- - {/* Nav dots */} -
- {[1, 0, 0, 0].map((a, i) => ( -
- ))} -
-
- - {/* Floating chip — top left */} -
-
-
-
+120 LYTs
-
just now
-
-
- - {/* Floating chip — bottom right */} -
-
Redeemable
-
₹284.00
-
-
-
- - ); -} diff --git a/src/components/ProblemParticles.tsx b/src/components/ProblemParticles.tsx deleted file mode 100644 index 6352e9b..0000000 --- a/src/components/ProblemParticles.tsx +++ /dev/null @@ -1,196 +0,0 @@ -'use client'; - -import { useEffect, useRef } from 'react'; - -interface Particle { - x: number; - y: number; - vx: number; - vy: number; - radius: number; - alpha: number; - type: 'lost' | 'converted' | 'regular'; - pulseSpeed: number; - pulseTime: number; -} - -export default function ProblemParticles() { - const canvasRef = useRef(null); - - useEffect(() => { - const canvas = canvasRef.current; - if (!canvas) return; - - const ctx = canvas.getContext('2d'); - if (!ctx) return; - - let animationFrameId = 0; - let cssWidth = canvas.offsetWidth; - let cssHeight = canvas.offsetHeight; - - const particles: Particle[] = []; - const storeNode = { x: cssWidth / 2, y: cssHeight / 2, radius: 18 }; - - const setCanvasSize = () => { - const dpr = Math.max(1, window.devicePixelRatio || 1); - cssWidth = canvas.offsetWidth; - cssHeight = canvas.offsetHeight; - canvas.width = Math.round(cssWidth * dpr); - canvas.height = Math.round(cssHeight * dpr); - // Map drawing coordinates to CSS pixels - ctx.setTransform(dpr, 0, 0, dpr, 0, 0); - storeNode.x = cssWidth / 2; - storeNode.y = cssHeight / 2; - }; - - const createParticle = (isInitial = false): Particle => { - const typeRand = Math.random(); - const type = typeRand < 0.2 ? 'lost' : typeRand < 0.45 ? 'converted' : 'regular'; - - let x: number, y: number; - if (isInitial) { - x = Math.random() * cssWidth; - y = Math.random() * cssHeight; - } else { - // Spawn from edges - if (Math.random() < 0.5) { - x = Math.random() < 0.5 ? 0 : cssWidth; - y = Math.random() * cssHeight; - } else { - x = Math.random() * cssWidth; - y = Math.random() < 0.5 ? 0 : cssHeight; - } - } - - // Vector pointing towards the store node (center) - const angle = Math.atan2(storeNode.y - y, storeNode.x - x); - const speed = 0.4 + Math.random() * 0.8; - - return { - x, - y, - vx: Math.cos(angle) * speed + (Math.random() - 0.5) * 0.2, - vy: Math.sin(angle) * speed + (Math.random() - 0.5) * 0.2, - radius: 2 + Math.random() * 4, - alpha: 0.1 + Math.random() * 0.7, - type, - pulseSpeed: 0.05 + Math.random() * 0.05, - pulseTime: Math.random() * Math.PI, - }; - }; - - // Initialize - setCanvasSize(); - for (let i = 0; i < 45; i++) particles.push(createParticle(true)); - - const handleResize = () => { - if (!canvas) return; - setCanvasSize(); - }; - - window.addEventListener('resize', handleResize); - - const draw = () => { - ctx.clearRect(0, 0, cssWidth, cssHeight); - - // Background glow - const bgGlow = ctx.createRadialGradient( - storeNode.x, - storeNode.y, - 10, - storeNode.x, - storeNode.y, - cssWidth * 0.4 - ); - bgGlow.addColorStop(0, 'rgba(0, 102, 255, 0.08)'); - bgGlow.addColorStop(1, 'rgba(0, 0, 0, 0)'); - ctx.fillStyle = bgGlow; - ctx.fillRect(0, 0, cssWidth, cssHeight); - - // Store hub - ctx.shadowBlur = 30; - ctx.shadowColor = '#0066ff'; - ctx.fillStyle = 'rgba(0, 102, 255, 0.9)'; - ctx.beginPath(); - ctx.arc(storeNode.x, storeNode.y, storeNode.radius, 0, Math.PI * 2); - ctx.fill(); - - ctx.strokeStyle = 'rgba(255, 255, 255, 0.6)'; - ctx.lineWidth = 2; - ctx.beginPath(); - ctx.arc(storeNode.x, storeNode.y, storeNode.radius - 6, 0, Math.PI * 2); - ctx.stroke(); - ctx.shadowBlur = 0; - - // Particles - particles.forEach((p, idx) => { - p.x += p.vx; - p.y += p.vy; - p.pulseTime += p.pulseSpeed; - - let alpha = p.alpha; - let radius = p.radius; - - if (p.type === 'converted') { - alpha = Math.max(0.4, p.alpha + Math.sin(p.pulseTime) * 0.3); - radius = p.radius + Math.sin(p.pulseTime) * 1.5; - } else if (p.type === 'lost') { - const dist = Math.hypot(storeNode.x - p.x, storeNode.y - p.y); - if (dist < 150) p.alpha -= 0.008; - } - - // Connections between particles - for (let j = idx + 1; j < particles.length; j++) { - const p2 = particles[j]; - const dist = Math.hypot(p2.x - p.x, p2.y - p.y); - if (dist < 80 && p.alpha > 0 && p2.alpha > 0) { - const lineAlpha = (1 - dist / 80) * 0.18 * Math.min(alpha, p2.alpha); - ctx.strokeStyle = `rgba(0, 102, 255, ${lineAlpha})`; - ctx.lineWidth = 1; - ctx.beginPath(); - ctx.moveTo(p.x, p.y); - ctx.lineTo(p2.x, p2.y); - ctx.stroke(); - } - } - - // Connection to store hub - const distToStore = Math.hypot(storeNode.x - p.x, storeNode.y - p.y); - if (distToStore < 120 && p.alpha > 0) { - const lineAlpha = (1 - distToStore / 120) * 0.25 * p.alpha; - ctx.strokeStyle = p.type === 'converted' ? `rgba(0, 220, 255, ${lineAlpha})` : `rgba(0, 102, 255, ${lineAlpha})`; - ctx.beginPath(); - ctx.moveTo(p.x, p.y); - ctx.lineTo(storeNode.x, storeNode.y); - ctx.stroke(); - } - - // Respawn check - if (distToStore < storeNode.radius || p.x < 0 || p.x > cssWidth || p.y < 0 || p.y > cssHeight || p.alpha <= 0) { - particles[idx] = createParticle(); - } else { - ctx.fillStyle = p.type === 'converted' ? `rgba(0, 220, 255, ${alpha})` : p.type === 'lost' ? `rgba(255, 68, 68, ${alpha})` : `rgba(255, 255, 255, ${alpha})`; - if (p.type === 'converted') { - ctx.shadowBlur = 10; - ctx.shadowColor = '#00dcff'; - } - ctx.beginPath(); - ctx.arc(p.x, p.y, radius, 0, Math.PI * 2); - ctx.fill(); - ctx.shadowBlur = 0; - } - }); - - animationFrameId = requestAnimationFrame(draw); - }; - - draw(); - - return () => { - window.removeEventListener('resize', handleResize); - cancelAnimationFrame(animationFrameId); - }; - }, []); - - return ; -} diff --git a/src/components/Solutions.tsx b/src/components/Solutions.tsx deleted file mode 100644 index 4df4236..0000000 --- a/src/components/Solutions.tsx +++ /dev/null @@ -1,237 +0,0 @@ -'use client'; - -import { useState } from 'react'; -import Image from 'next/image'; -import Link from 'next/link'; - -const SOLUTIONS = [ - { - id: 'footfall', - category: 'AI Solution', - title: 'Footfall Intelligence', - subtitle: 'Understand Customer Movement in Real Time', - excerpt: - 'Track visitor count, movement patterns, and peak hours across your retail spaces. Turn anonymous foot traffic into actionable intelligence that drives layout, staffing, and promotions.', - image: '/loyaly_php/assets/images/deepvision-fi-640x640.jpg', - imageAlt: 'Footfall Intelligence dashboard showing real-time customer movement heatmaps', - href: '/solutions/footfall-intelligence', - }, - { - id: 'journey', - category: 'AI Solution', - title: 'Customer Journey', - subtitle: 'Map Every Interaction Seamlessly', - excerpt: - 'Track and understand each step of your customer\'s journey — online and in-store — to identify friction points, improve conversion, and deliver experiences that build loyalty.', - image: '/loyaly_php/assets/images/nlpgenius-natural-language-processing-fi-640x640.jpg', - imageAlt: 'Customer journey map visualisation inside Loyaly.AI platform', - href: '/solutions/customer-journey', - }, - { - id: 'engagement', - category: 'AI Solution', - title: 'Customer Engagement', - subtitle: 'Drive Meaningful Interactions', - excerpt: - 'Analyse behaviour and preferences to deliver personalised experiences, timely offers, and targeted messaging that keep customers coming back.', - image: '/loyaly_php/assets/images/smarttrader-predictive-stock-market-analysis-fi-640x640.jpg', - imageAlt: 'Customer engagement analytics showing personalisation performance metrics', - href: '/solutions/customer-engagement', - }, - { - id: 'loyalty', - category: 'AI Solution', - title: 'Loyalty Management', - subtitle: 'Build Lasting Relationships', - excerpt: - 'Reward customer loyalty with smart programmes that adapt in real time — from LYTs and tiers to personalised perks that feel genuinely earned.', - image: '/loyaly_php/assets/images/cognivision-transformative-ai-for-intelligent-fi-640x640.jpg', - imageAlt: 'Loyalty management module showing customer tier performance', - href: '/solutions/loyalty-management', - }, - { - id: 'revenue', - category: 'AI Solution', - title: 'Revenue Optimisation', - subtitle: 'Maximise Business Performance', - excerpt: - 'Leverage data insights to optimise pricing, promotions, and strategies for higher revenue growth — without sacrificing margin.', - image: '/loyaly_php/assets/images/neuraforge-crafting-future-ready-ai-solutions-fi-640x640.jpg', - imageAlt: 'Revenue optimisation charts showing margin improvements', - href: '/solutions/revenue-optimisation', - }, -]; - -export default function Solutions() { - const [hoveredId, setHoveredId] = useState(null); - - return ( -
-
- {/* Header */} -
-

- Our Solutions -

-

- Exploring groundbreaking AI solutions transforming retail -

-

- From understanding footfall to optimising revenue, our five AI modules work independently - or together as one unified intelligence engine. -

-
- - {/* Grid */} -
- {SOLUTIONS.map(({ id, category, title, subtitle, excerpt, image, imageAlt, href }) => { - const isHovered = hoveredId === id; - return ( -
setHoveredId(id)} - onMouseLeave={() => setHoveredId(null)} - style={{ - background: '#fff8e8', - borderRadius: '16px', - overflow: 'hidden', - boxShadow: isHovered - ? '0 12px 40px rgba(23,21,18,0.14)' - : '0 2px 12px rgba(23,21,18,0.06)', - transform: isHovered ? 'translateY(-6px)' : 'translateY(0)', - transition: 'transform 0.3s ease, box-shadow 0.3s ease', - display: 'flex', - flexDirection: 'column', - }} - > - {/* Card image */} - -
- {imageAlt} -
- - - {/* Card content */} -
- {/* Category badge */} - - {category} - - -

- - {title} - -

- -

- {subtitle} -

- -

- {excerpt} -

- - - Explore more - -
-
- ); - })} -
- - {/* CTA */} -
- - View all solutions - -
-
-
- ); -} diff --git a/src/components/Testimonial.tsx b/src/components/Testimonial.tsx deleted file mode 100644 index 9cc5bc5..0000000 --- a/src/components/Testimonial.tsx +++ /dev/null @@ -1,211 +0,0 @@ -'use client'; - -import { useState, useEffect, useRef, useCallback } from 'react'; - -const TESTIMONIALS = [ - { - quote: - 'Loyaly.AI transformed how we understand our customers. Foot traffic insights alone helped us rearrange our store layout and boost average basket size by 18% in the first quarter.', - author: 'Priya Nair', - role: 'Head of Retail Operations', - company: 'Trendsetter Fashion Stores', - avatar: '/loyaly_php/assets/images/partners-1.png', - }, - { - quote: - 'The AI powered loyalty engine learns fast. Within weeks we were delivering personalised offers that felt genuinely relevant — our repeat visit rate climbed 23%.', - author: 'Arjun Mehta', - role: 'VP of Customer Experience', - company: 'FreshMart Supermarkets', - avatar: '/loyaly_php/assets/images/partners-2.png', - }, - { - quote: - "We tried three loyalty platforms before Loyaly.AI. This is the first one that actually connects footfall data, promotions, and CRM in a single dashboard. It's changed how we run campaigns.", - author: 'Sarah Connelly', - role: 'Chief Marketing Officer', - company: 'Urban Living Group', - avatar: '/loyaly_php/assets/images/partners-3.png', - }, -]; - -export default function Testimonial() { - const [active, setActive] = useState(0); - const [paused, setPaused] = useState(false); - const timerRef = useRef | null>(null); - const total = TESTIMONIALS.length; - - const go = useCallback( - (index: number) => { - setActive((index + total) % total); - }, - [total] - ); - - // Auto-advance every 6 s - useEffect(() => { - if (paused) return; - timerRef.current = setTimeout(() => go(active + 1), 6000); - return () => { - if (timerRef.current) clearTimeout(timerRef.current); - }; - }, [active, paused, go]); - - const { quote, author, role, company } = TESTIMONIALS[active]; - - return ( -
setPaused(true)} - onMouseLeave={() => setPaused(false)} - > -
- {/* Section label */} -

- Customer Stories -

-

- See how retailers are transforming customer loyalty with Loyaly.AI -

- - {/* Quote card */} -
- {/* Decorative quote mark */} - - -
- {quote} -
- -
- - {author} - - - {role}, {company} - -
-
- - {/* Navigation dots */} -
- {TESTIMONIALS.map((_, i) => ( -
- - {/* Prev / Next */} -
- - -
-
- - -
- ); -} - -const arrowBtnStyle: React.CSSProperties = { - width: '40px', - height: '40px', - borderRadius: '50%', - background: 'rgba(255,255,255,0.08)', - color: '#fff', - border: '1px solid rgba(255,255,255,0.15)', - cursor: 'pointer', - fontSize: '16px', - display: 'flex', - alignItems: 'center', - justifyContent: 'center', - transition: 'background 0.2s', -}; diff --git a/src/components/for-people/DiscoverDealsSection.tsx b/src/components/for-people/DiscoverDealsSection.tsx index 5c1c4c7..144c506 100644 --- a/src/components/for-people/DiscoverDealsSection.tsx +++ b/src/components/for-people/DiscoverDealsSection.tsx @@ -1,8 +1,14 @@ 'use client'; -import React, { useState } from 'react'; +import React, { useState, useLayoutEffect, useEffect, useRef } from 'react'; import Image from 'next/image'; import { PhoneFrame, PhoneBottomNav, BellIcon, PinIcon, ChevronIcon, SearchIcon, MicIcon, CameraIcon, MapIcon, HeartLogoIcon } from './PhoneMockup'; +import { gsap } from 'gsap'; +import { ScrollTrigger } from 'gsap/ScrollTrigger'; + +if (typeof window !== 'undefined') gsap.registerPlugin(ScrollTrigger); + +const useIsomorphicLayoutEffect = typeof window !== 'undefined' ? useLayoutEffect : useEffect; const deals = [ { store: 'Starbucks', category: 'Coffee & Drinks', offer: '2× LYTs', savings: '₹120 saved', color: '#00704A', dot: '#22c55e', distance: '0.3 km', rating: 4.8 }, @@ -14,9 +20,37 @@ const deals = [ export default function DiscoverDealsSection() { const [hovered, setHovered] = useState(null); + const panelRef = useRef(null); + const phoneRef = useRef(null); + + useIsomorphicLayoutEffect(() => { + if (typeof window === 'undefined') return; + const section = panelRef.current; + const phone = phoneRef.current; + if (!section || !phone) return; + + const ctx = gsap.context(() => { + gsap.fromTo(phone, + { y: 160, opacity: 0 }, + { + y: 0, + opacity: 1, + ease: 'power2.out', + scrollTrigger: { + trigger: section, + start: 'top 92%', + end: 'top 25%', + scrub: 1.2, + } + } + ); + }, section); + + return () => ctx.revert(); + }, []); return ( -
+
{/* Background photo */} @@ -63,7 +97,7 @@ export default function DiscoverDealsSection() {
{/* Phone mockup — white app screen, matches the in-app Discover experience */} -
+
{/* Amber header */} @@ -151,7 +185,7 @@ export default function DiscoverDealsSection() {
- +
diff --git a/src/components/for-people/EarnRewardsSection.tsx b/src/components/for-people/EarnRewardsSection.tsx index 27bf72b..8fe7dab 100644 --- a/src/components/for-people/EarnRewardsSection.tsx +++ b/src/components/for-people/EarnRewardsSection.tsx @@ -1,6 +1,6 @@ 'use client'; -import React, { useEffect, useRef, useState } from 'react'; +import React, { useEffect, useLayoutEffect, useRef, useState } from 'react'; import Image from 'next/image'; import { gsap } from 'gsap'; import { ScrollTrigger } from 'gsap/ScrollTrigger'; @@ -8,6 +8,8 @@ import { PhoneFrame, PhoneBottomNav, BellIcon, FlameIcon } from './PhoneMockup'; if (typeof window !== 'undefined') gsap.registerPlugin(ScrollTrigger); +const useIsomorphicLayoutEffect = typeof window !== 'undefined' ? useLayoutEffect : useEffect; + const feed = [ { store: 'Daily Login', pts: +50, time: '2m ago', type: 'earn' }, { store: 'Walking 5,000 steps', pts: +80, time: '1h ago', type: 'earn' }, @@ -18,10 +20,38 @@ const feed = [ export default function EarnRewardsSection() { const [pts, setPts] = useState(0); const panelRef = useRef(null); + const phoneRef = useRef(null); const rafRef = useRef(0); const rowRefs = useRef<(HTMLDivElement | null)[]>([]); const activeRowRef = useRef(0); + // Phone mockup rises in from the bottom as the section scrolls into view + useIsomorphicLayoutEffect(() => { + if (typeof window === 'undefined') return; + const section = panelRef.current; + const phone = phoneRef.current; + if (!section || !phone) return; + + const ctx = gsap.context(() => { + gsap.fromTo(phone, + { y: 160, opacity: 0 }, + { + y: 0, + opacity: 1, + ease: 'power2.out', + scrollTrigger: { + trigger: section, + start: 'top 92%', + end: 'top 25%', + scrub: 1.2, + } + } + ); + }, section); + + return () => ctx.revert(); + }, []); + // Move the highlighted feed card as the section scrolls through the viewport useEffect(() => { if (typeof window === 'undefined') return; @@ -136,7 +166,7 @@ export default function EarnRewardsSection() {
{/* Right — phone mockup, matches the in-app Earn / Home experience */} -
+
{/* Amber header */} @@ -230,7 +260,7 @@ export default function EarnRewardsSection() { ))}
- +
diff --git a/src/components/for-people/ExperienceSection.tsx b/src/components/for-people/ExperienceSection.tsx index 15152fe..21fd38a 100644 --- a/src/components/for-people/ExperienceSection.tsx +++ b/src/components/for-people/ExperienceSection.tsx @@ -1,6 +1,12 @@ 'use client'; -import React from 'react'; +import React, { useLayoutEffect, useEffect, useRef } from 'react'; +import { gsap } from 'gsap'; +import { ScrollTrigger } from 'gsap/ScrollTrigger'; + +if (typeof window !== 'undefined') gsap.registerPlugin(ScrollTrigger); + +const useIsomorphicLayoutEffect = typeof window !== 'undefined' ? useLayoutEffect : useEffect; const words = [ { text: 'Effortless.', size: 'clamp(58px, 9vw, 134px)', color: '#ffffff' }, @@ -14,8 +20,37 @@ const steps = [ ]; export default function ExperienceSection() { + const panelRef = useRef(null); + const cardRef = useRef(null); + + useIsomorphicLayoutEffect(() => { + if (typeof window === 'undefined') return; + const section = panelRef.current; + const card = cardRef.current; + if (!section || !card) return; + + const ctx = gsap.context(() => { + gsap.fromTo(card, + { x: 200, opacity: 0 }, + { + x: 0, + opacity: 1, + ease: 'power2.out', + scrollTrigger: { + trigger: section, + start: 'top 92%', + end: 'top 25%', + scrub: 1.2, + } + } + ); + }, section); + + return () => ctx.revert(); + }, []); + return ( -
+
@@ -36,35 +71,41 @@ export default function ExperienceSection() { ))}
- {/* Steps */} -
-

+

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.

{steps.map((s, i) => ( -
- {s.n} - {s.label} + {s.n} + {s.label}
))}
-
+
- {['#f4be28', '#4ade80', '#a855f7', '#3b82f6'].map((c, i) => ( -
0 ? -9 : 0 }} /> + {['#ff7b39', '#4ade80', '#a855f7', '#3b82f6'].map((c, i) => ( +
0 ? -9 : 0 }} /> ))}
- - Joined by 50,000+ shoppers + + Joined by 50,000+ shoppers
diff --git a/src/components/for-people/FinalCTASection.tsx b/src/components/for-people/FinalCTASection.tsx index 79e867c..2389f1e 100644 --- a/src/components/for-people/FinalCTASection.tsx +++ b/src/components/for-people/FinalCTASection.tsx @@ -44,13 +44,9 @@ export default function FinalCTASection() { const tl = gsap.timeline({ scrollTrigger: { trigger: sectionRef.current, start: 'top 80%', toggleActions: 'play none none reset' }, }); - tl.fromTo('.fcta-badge', - { opacity: 0, y: 20, scale: 0.9 }, - { opacity: 1, y: 0, scale: 1, duration: 0.6, ease: 'back.out(2)' } - ) - .fromTo('.fcta-line-1', + tl.fromTo('.fcta-line-1', { opacity: 0, y: 50, filter: 'blur(8px)' }, - { opacity: 1, y: 0, filter: 'blur(0px)', duration: 0.8, ease: 'expo.out' }, '-=0.2' + { opacity: 1, y: 0, filter: 'blur(0px)', duration: 0.8, ease: 'expo.out' } ) .fromTo('.fcta-line-2', { opacity: 0, y: 50, filter: 'blur(8px)' }, @@ -60,9 +56,32 @@ export default function FinalCTASection() { { opacity: 0, y: 24 }, { opacity: 1, y: 0, duration: 0.65, ease: 'power3.out' }, '-=0.4' ) + .fromTo('.fcta-hanging-logo', + { opacity: 0, y: -60, rotation: -16 }, + { opacity: 1, y: 0, rotation: 0, duration: 1.1, stagger: 0.16, ease: 'back.out(1.5)' }, + '-=0.45' + ) + .fromTo('.fcta-logo-link', + { rotation: 10 }, + { rotation: 0, duration: 1.2, stagger: 0.16, ease: 'back.out(1.6)' }, + '<' + ) + .call(() => { + if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) return; + gsap.utils.toArray('.fcta-hanging-logo').forEach((el, i) => { + gsap.to(el, { + rotation: i % 2 === 0 ? 3.5 : -3.5, + duration: 2.4 + i * 0.3, + ease: 'sine.inOut', + yoyo: true, + repeat: -1, + transformOrigin: 'top center', + }); + }); + }) .fromTo('.fcta-btns', { opacity: 0, y: 20 }, - { opacity: 1, y: 0, duration: 0.55, ease: 'power3.out' }, '-=0.3' + { opacity: 1, y: 0, duration: 0.55, ease: 'power3.out' }, '-=0.45' ) .fromTo('.fcta-stat', { opacity: 0, y: 28, scale: 0.88 }, @@ -94,30 +113,10 @@ export default function FinalCTASection() { {/* Amber glow orb top-center */}
- {/* Ghost wordmark */} -
- LOYALY -
{/* Content */}
- {/* Live badge */} -
- - - Now live in Coimbatore - -
{/* Headline */}

@@ -144,13 +143,130 @@ export default function FinalCTASection() { {/* Subtitle */}

Download Loyaly and start earning on your very next purchase. Free. Instant. Yours.

+ {/* Hanging Logos */} +
+ {/* Play Store Logo (hanging) */} +
+ {/* Keyring loop */} +
+ {/* String */} +
+ {/* Logo Circle */} + + Google Play + + {/* Tooltip */} +
+ Download In Playstore +
+
+ + {/* Apple Logo (hanging) */} +
+ {/* Keyring loop */} +
+ {/* String */} +
+ {/* Logo Circle */} + + App Store + + {/* Tooltip */} +
+ Download in App store +
+
+
+ {/* CTAs */}
{` @keyframes fctaPulse { 0%,100%{box-shadow:0 0 0 0 rgba(34,197,94,0.5)} 50%{box-shadow:0 0 0 6px rgba(34,197,94,0)} } @keyframes fctaShimmer { 0%{background-position:200% center} 100%{background-position:-200% center} } + .fcta-hanging-logo a { + transition: transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1); + } + .fcta-hanging-logo a:hover { + transform: scale(1.08); + } + .fcta-tooltip { + position: absolute; + top: calc(100% + 4px); + left: 50%; + transform: translateX(-50%) translateY(8px); + background: #171512; + color: #ffffff; + padding: 6px 14px; + border-radius: 6px; + font-size: 11px; + font-weight: 700; + font-family: 'Sora', sans-serif; + white-space: nowrap; + opacity: 0; + pointer-events: none; + transition: opacity 0.25s ease, transform 0.25s cubic-bezier(0.25, 1, 0.22, 1); + box-shadow: 0 4px 12px rgba(0,0,0,0.15); + z-index: 10; + } + .fcta-hanging-logo:hover .fcta-tooltip { + opacity: 1; + transform: translateX(-50%) translateY(0); + } + .fcta-tooltip::before { + content: ''; + position: absolute; + top: -4px; + left: 50%; + transform: translateX(-50%) rotate(45deg); + width: 8px; + height: 8px; + background: #171512; + } + @media (max-width: 1023px) { + .fcta-hanging-logos-wrapper { + display: none !important; + } + .fcta-sub { + margin-bottom: 40px !important; + } + } + @media (min-width: 1024px) { + .fcta-btns { + display: none !important; + } + } `}

); diff --git a/src/components/for-people/HeroSection.tsx b/src/components/for-people/HeroSection.tsx index 3746afa..417cdbf 100644 --- a/src/components/for-people/HeroSection.tsx +++ b/src/components/for-people/HeroSection.tsx @@ -61,7 +61,7 @@ export default function HeroSection() {

Shop Smart. Live Rewarded. @@ -71,7 +71,7 @@ export default function HeroSection() { 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', }}> - Meet LYT (Loyaly Token): the single currency behind every reward in the app. Earn them through daily tasks, walking challenges, and games, then spend them instantly at partner stores near you with zero expiry. + Meet LYTs (Loyaly Tokens): the single currency behind every reward. Earn them through daily challenges and games, then spend instantly at partner stores near you with zero expiry.

diff --git a/src/components/for-people/PhoneMockup.tsx b/src/components/for-people/PhoneMockup.tsx index 2bd7ba2..f801e9f 100644 --- a/src/components/for-people/PhoneMockup.tsx +++ b/src/components/for-people/PhoneMockup.tsx @@ -56,9 +56,20 @@ export function MapIcon() { ); } -export function HeartLogoIcon({ size = 16 }: { size?: number }) { +export function HeartLogoIcon({ size = 16, active = false }: { size?: number; active?: boolean }) { return ( - + ); } export function UpArrowIcon({ color = '#16a34a' }: { color?: string }) { @@ -85,12 +96,12 @@ export function FlameIcon({ color = '#f4be28' }: { color?: string }) { /* ── Bottom nav — pass the active tab key to highlight it ── */ export function PhoneBottomNav({ active = 'home' }: { active?: string }) { - const items: { key: string; icon: React.ReactNode }[] = [ - { key: 'home', icon: }, - { key: 'tag', icon: }, - { key: 'heart', icon: }, - { key: 'shop', icon: }, - { key: 'user', icon: }, + const items: { key: string; icon: (isActive: boolean) => React.ReactNode }[] = [ + { key: 'home', icon: () => }, + { key: 'tag', icon: () => }, + { key: 'heart', icon: (isActive) => }, + { key: 'shop', icon: () => }, + { key: 'user', icon: () => }, ]; return (
@@ -99,11 +110,11 @@ export function PhoneBottomNav({ active = 'home' }: { active?: string }) { return (
- {n.icon} + {n.icon(isActive)}
); })} diff --git a/src/components/for-people/PillarsSection.tsx b/src/components/for-people/PillarsSection.tsx new file mode 100644 index 0000000..740ea15 --- /dev/null +++ b/src/components/for-people/PillarsSection.tsx @@ -0,0 +1,68 @@ +'use client'; + +import React from 'react'; + +const PILLARS = [ + { + n: '01', + title: 'Shop Smarter', + desc: 'Unlock top deals, discounts, and exclusive offers at stores near you, just by walking in.', + color: '#f4be28', + }, + { + n: '02', + title: 'Earn Rewards', + desc: 'Every rupee spent earns LYT points. Zero expiry. Redeem anytime, at any partner store.', + color: '#16a34a', + }, + { + n: '03', + title: 'Make It a Pleasure', + desc: 'Shopping should feel good. Loyaly makes every trip more rewarding, more fun, and more personal.', + color: '#a78bfa', + }, +]; + +export default function PillarsSection() { + return ( +
+
+
+ Save More02 +
+ +

+ Save more on every in-store visit. +

+

+ Earn Loyaly rewards on everyday shopping, from groceries to fashion to home essentials. Every purchase brings you closer to your next reward. +

+ +
+ {PILLARS.map((p, i) => ( +
+
+

{p.title}

+

{p.desc}

+
+ ))} +
+
+ + +
+ ); +} diff --git a/src/components/home/ProblemSection.tsx b/src/components/home/ProblemSection.tsx index 703749e..903cffb 100644 --- a/src/components/home/ProblemSection.tsx +++ b/src/components/home/ProblemSection.tsx @@ -153,6 +153,31 @@ export default function ProblemSection({ isLoaded = true }: ProblemSectionProps)
+ {/* India retail market stats strip */} +
+ {[ + { val: '$2 Tn', label: 'India retail market by 2032, 25% CAGR' }, + { val: '5th', label: 'Largest retail destination globally' }, + { val: '10%', label: "Of India's GDP from retail" }, + { val: '12%', label: 'Of retail is organised, the rest is offline' }, + { val: '500M', label: 'Indians shopping online by 2030, up from 220M' }, + ].map((s, i) => ( +
+
{s.val}
+
{s.label}
+
+ ))} +
+ {/* Grid wrapper */}
{/* Row 1: Red Stat Cards */} @@ -429,6 +454,7 @@ export default function ProblemSection({ isLoaded = true }: ProblemSectionProps) #problem .problem-stats-row { grid-template-columns: 1fr !important; } #problem .dark-bento-grid { grid-template-columns: 1fr !important; } #problem .dark-bento-card-4 { grid-column: span 1; } + #problem .problem-india-stats { grid-template-columns: repeat(2, 1fr) !important; } } `}