updated mobile view

This commit is contained in:
R-Bharathraj
2026-07-15 13:16:11 +05:30
parent 89b0089457
commit 85e0f6eb63
25 changed files with 572 additions and 219 deletions

View File

@@ -9,16 +9,16 @@ const NAV = [
title: 'Product',
links: [
{ label: 'For People', href: '/for_people' },
{ label: 'For Business', href: '/use_cases' },
{ label: 'Meet the Agents', href: '/solutions_page' },
{ label: 'For Business', href: '/for_business' },
{ label: 'Meet the Agents', href: '/meet_the_agents' },
],
},
{
title: 'Platform',
links: [
{ label: 'Behavision AI', href: '/use_cases' },
{ label: 'SpendSense AI', href: '/use_cases' },
{ label: 'Dyscount AI', href: '/use_cases' },
{ label: 'Behavision AI', href: '/for_business' },
{ label: 'SpendSense AI', href: '/for_business' },
{ label: 'Dyscount AI', href: '/for_business' },
],
},
{
@@ -66,7 +66,7 @@ export default function Footer() {
color: '#ffffff',
position: 'relative',
overflow: 'hidden',
margin: '0 20px 20px',
margin: '0 var(--sec-gutter) var(--sec-gap)',
borderRadius: '0 0 24px 24px',
}}>

View File

@@ -16,7 +16,7 @@ const DETAILS = [
},
{
label: 'Email us',
value: <a href="mailto:loyalydigital@gmail.com" style={{ color: '#fff', textDecoration: 'none', fontWeight: 600 }}>loyalydigital@gmail.com</a>,
value: <a href="mailto:loyalydigital@gmail.com" className="git-email-link">loyalydigital@gmail.com</a>,
icon: (
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round">
<rect x="2" y="4" width="20" height="16" rx="2" /><path d="m22 7-10 5L2 7" />
@@ -72,7 +72,7 @@ export default function GetInTouch() {
aria-label="Contact us"
style={{
position: 'relative',
margin: '0 20px 0',
margin: '0 var(--sec-gutter) 0',
borderRadius: '24px 24px 0 0',
overflow: 'hidden',
background: '#07070d',
@@ -84,7 +84,7 @@ export default function GetInTouch() {
maxWidth: 1200, margin: '0 auto',
padding: 'clamp(56px, 8vh, 100px) clamp(28px, 5vw, 72px)',
display: 'grid',
gridTemplateColumns: 'repeat(auto-fit, minmax(320px, 1fr))',
gridTemplateColumns: 'repeat(auto-fit, minmax(min(100%, 320px), 1fr))',
gap: 'clamp(40px, 5vw, 80px)',
alignItems: 'start',
}}>
@@ -117,20 +117,13 @@ export default function GetInTouch() {
{/* Detail cards */}
<div style={{ display: 'flex', flexDirection: 'column', gap: 14, marginBottom: 36 }}>
{DETAILS.map((d) => (
<div key={d.label} style={{
display: 'flex', gap: 16, alignItems: 'flex-start',
padding: '18px 20px', borderRadius: 16,
background: 'rgba(255,255,255,0.03)', border: '1px solid rgba(255,255,255,0.07)',
}}>
<div style={{
width: 40, height: 40, borderRadius: 11, flexShrink: 0,
display: 'flex', alignItems: 'center', justifyContent: 'center',
background: 'rgba(244,190,40,0.1)', border: '1px solid rgba(244,190,40,0.22)',
color: '#f4be28',
}}>{d.icon}</div>
<div key={d.label} className="git-detail">
<div className="git-detail-icon">
{d.icon}
</div>
<div>
<div style={{ fontSize: 11, fontWeight: 700, letterSpacing: '0.12em', textTransform: 'uppercase', color: 'rgba(255,255,255,0.4)', fontFamily: 'Sora, sans-serif', marginBottom: 6 }}>{d.label}</div>
<div style={{ fontSize: 15, lineHeight: 1.6, color: 'rgba(255,255,255,0.7)', fontFamily: 'Sora, sans-serif' }}>{d.value}</div>
<div className="git-detail-label">{d.label}</div>
<div className="git-detail-value">{d.value}</div>
</div>
</div>
))}
@@ -147,16 +140,7 @@ export default function GetInTouch() {
</div>
</div>
{/* ── Right — form ── */}
<div style={{
background: 'rgba(255,255,255,0.03)',
border: '1px solid rgba(255,255,255,0.08)',
borderRadius: 24,
padding: 'clamp(28px, 3vw, 44px)',
backdropFilter: 'blur(20px)',
WebkitBackdropFilter: 'blur(20px)',
boxShadow: 'inset 0 1px 0 rgba(255,255,255,0.05)',
}}>
<div className="git-form-card">
{formState === 'success' ? (
<div role="status" aria-live="polite" style={{ textAlign: 'center', padding: '40px 0' }}>
<div style={{
@@ -235,6 +219,95 @@ export default function GetInTouch() {
@keyframes gitspin { to { transform: rotate(360deg); } }
.git-input::placeholder { color: rgba(255,255,255,0.3); }
.git-input:focus { border-color: rgba(244,190,40,0.6) !important; box-shadow: 0 0 0 3px rgba(244,190,40,0.12) !important; }
.git-detail {
display: flex;
gap: 20px;
align-items: flex-start;
padding: 10px 0;
transition: transform 0.2s ease;
}
.git-detail-icon {
width: 42px;
height: 42px;
border-radius: 50%;
flex-shrink: 0;
display: flex;
align-items: center;
justify-content: center;
background: rgba(255,255,255,0.02);
border: 1px solid rgba(255,255,255,0.06);
color: rgba(255,255,255,0.5);
transition: all 0.3s cubic-bezier(0.16, 1, 0.3, 1);
}
.git-detail:hover .git-detail-icon {
background: rgba(244,190,40,0.1);
border-color: rgba(244,190,40,0.3);
color: #f4be28;
transform: scale(1.05);
box-shadow: 0 0 15px rgba(244,190,40,0.1);
}
.git-detail-label {
font-size: 11px;
font-weight: 700;
letter-spacing: 0.12em;
text-transform: uppercase;
color: rgba(255,255,255,0.4);
font-family: 'Sora', sans-serif;
margin-bottom: 6px;
transition: color 0.3s ease;
}
.git-detail:hover .git-detail-label {
color: #f4be28;
}
.git-detail-value {
font-size: 15px;
line-height: 1.6;
color: rgba(255,255,255,0.75);
font-family: 'Sora', sans-serif;
transition: color 0.3s ease;
}
.git-detail:hover .git-detail-value {
color: rgba(255,255,255,0.95);
}
.git-email-link {
color: #fff;
text-decoration: none;
font-weight: 600;
position: relative;
transition: color 0.3s ease;
}
.git-email-link::after {
content: '';
position: absolute;
width: 100%;
transform: scaleX(0);
height: 1px;
bottom: -2px;
left: 0;
background-color: #f4be28;
transform-origin: bottom right;
transition: transform 0.25s ease-out;
}
.git-email-link:hover {
color: #f4be28;
}
.git-email-link:hover::after {
transform: scaleX(1);
transform-origin: bottom left;
}
.git-form-card {
background: rgba(255,255,255,0.03);
border: 1px solid rgba(255,255,255,0.08);
border-radius: 24px;
padding: clamp(28px, 3vw, 44px);
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
box-shadow: inset 0 1px 0 rgba(255,255,255,0.05);
}
.git-social {
width: 38px; height: 38px; border-radius: 10px;
display: flex; align-items: center; justify-content: center;
@@ -242,6 +315,17 @@ export default function GetInTouch() {
color: rgba(255,255,255,0.5); transition: all 0.2s ease;
}
.git-social:hover { background: rgba(244,190,40,0.12); border-color: rgba(244,190,40,0.3); color: #f4be28; }
@media (max-width: 768px) {
.git-form-card {
border: none;
background: transparent;
padding: 20px 0;
box-shadow: none;
backdrop-filter: none;
-webkit-backdrop-filter: none;
}
}
@media (max-width: 420px) {
.git-grid { grid-template-columns: 1fr !important; }
}

View File

@@ -8,8 +8,8 @@ import Image from 'next/image';
const NAV_LINKS = [
{ label: 'Home', href: '/' },
{ label: 'For People', href: '/for_people' },
{ label: 'For Business', href: '/use_cases' },
{ label: 'Meet the Agents', href: '/solutions_page' },
{ label: 'For Business', href: '/for_business' },
{ label: 'Meet the Agents', href: '/meet_the_agents' },
{ label: 'About us', href: '/about_us' },
{ label: 'Blogs', href: '/blog_main' },
];
@@ -232,7 +232,7 @@ export default function Header() {
className={transparentHeader ? 'header-transparent' : ''}
style={{
position: 'fixed',
top: isMobileViewport ? '14px' : 0,
top: isMobileViewport ? '20px' : 0,
left: '20px',
right: '20px',
width: 'auto',
@@ -247,18 +247,18 @@ export default function Header() {
transition: 'transform 0.35s cubic-bezier(0.4,0,0.2,1), background 0.3s ease, box-shadow 0.3s ease',
}}
>
<div style={{
<div className="header-inner" style={{
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
padding: '0 48px',
padding: '0 var(--hdr-gutter)',
height: transparentHeader ? '150px' : '92px',
width: '100%',
boxSizing: 'border-box',
transition: 'height 0.3s ease',
}}>
{/* Logo */}
<div style={{ flexShrink: 0, flex: 1, minWidth: 120 }}>
<div style={{ flexShrink: 0, flex: 1, minWidth: 120, display: 'flex', alignItems: 'center' }}>
<Link href="/" aria-label="Loyaly.AI home" style={{ display: 'inline-flex', alignItems: 'center', textDecoration: 'none' }}>
<Image
src={transparentHeader ? '/assets/images/logo-dark.png' : '/assets/images/loyalyai.png'}
@@ -360,6 +360,8 @@ export default function Header() {
@media (max-width: 1023px) {
.desktop-nav { display: none !important; }
.menu-trigger { display: flex !important; }
.header-inner { height: 68px !important; }
.header-logo-img { height: 32px !important; }
}
@media (min-width: 1024px) and (max-width: 1280px) {
.header-nav-pill { padding: 5px 6px !important; }

View File

@@ -9,7 +9,7 @@ export default function MapSection() {
return (
<section style={{
margin: '0 20px 20px',
margin: '0 var(--sec-gutter) var(--sec-gap)',
borderRadius: 24,
overflow: 'hidden',
background: '#fff',

View File

@@ -100,11 +100,14 @@ export default function EarnRewardsSection() {
}} />
{/* Safe area — reserves the notch strip above the app's top bar */}
<div style={{ height: 32, flexShrink: 0, background: '#ffffff' }} />
{/* The embed is a Flutter web app built for a real phone's logical
width (390px). Rendering it at 390 and scaling to fit keeps the
UI proportioned as designed instead of cramped at ~280px. The
iframe is overscanned ~16px past the right clip so Flutter's
desktop-style list scrollbar falls outside the visible screen. */}
{/* The embed is a responsive Flutter web app. We render it at a
comfortable logical width (390px) and scale it down to fill the
screen exactly, so the UI stays proportioned as designed instead
of cramped at ~260px. The iframe width is exactly the design
width (no horizontal overscan) so the app lays out edge-to-edge
and stays centered — nothing on the right (e.g. the Profile tab)
gets clipped. Flutter's thin right-edge list scrollbar is hidden
by a slim mask strip rather than by cutting into the layout. */}
<div className="erm-phone-viewport" style={{ position: 'relative', flex: 1, minHeight: 0, overflow: 'hidden' }}>
<iframe
src="https://anbarasu22004.github.io/lytsup_view/"
@@ -118,6 +121,8 @@ export default function EarnRewardsSection() {
transformOrigin: 'top left',
}}
/>
{/* Masks Flutter's canvas-painted scrollbar at the far right edge */}
<div className="erm-scrollbar-mask" aria-hidden />
</div>
</div>
<style>{`
@@ -126,10 +131,15 @@ export default function EarnRewardsSection() {
/* --pm-scale = screen width (frame - 2*10px padding) ÷ 390px design width */
.erm-phone-shell { --pm-scale: calc(280 / 390); }
.erm-phone-iframe {
width: calc(100% / var(--pm-scale) + 16px);
width: calc(100% / var(--pm-scale));
height: calc(100% / var(--pm-scale));
transform: scale(var(--pm-scale));
}
.erm-scrollbar-mask {
position: absolute; top: 0; right: 0; z-index: 2;
width: 7px; height: 100%; pointer-events: none;
background: linear-gradient(to right, rgba(255,255,255,0), #ffffff 75%);
}
@media (prefers-reduced-motion: reduce) { .erm-phone-shell { animation: none !important; } }
@media (max-width: 900px) {
.erm-phone-shell { width: 280px !important; --pm-scale: calc(260 / 390); }

View File

@@ -10,22 +10,7 @@ if (typeof window !== 'undefined') gsap.registerPlugin(ScrollTrigger);
const useIsomorphicLayoutEffect = typeof window !== 'undefined' ? useLayoutEffect : useEffect;
function useMagnetic() {
const ref = useRef<HTMLAnchorElement | null>(null);
useEffect(() => {
const el = ref.current;
if (!el) return;
const onMove = (e: MouseEvent) => {
const r = el.getBoundingClientRect();
el.style.transform = `translate(${((e.clientX - r.left) / r.width - 0.5) * 16}px,${((e.clientY - r.top) / r.height - 0.5) * 16}px) scale(1.04)`;
};
const onLeave = () => { el.style.transform = ''; };
el.addEventListener('mousemove', onMove);
el.addEventListener('mouseleave', onLeave);
return () => { el.removeEventListener('mousemove', onMove); el.removeEventListener('mouseleave', onLeave); };
}, []);
return ref;
}
const PROOF = [
{ val: '50K+', label: 'Active users', color: '#f4be28', icon: '👥', iconBg: '#fffbeb' },
@@ -36,8 +21,6 @@ const PROOF = [
export default function FinalCTASection() {
const sectionRef = useRef<HTMLDivElement>(null);
const mag1 = useMagnetic();
const mag2 = useMagnetic();
const coinLayerRef = useRef<HTMLDivElement>(null);
const badgeMag1 = useMagneticShared<HTMLDivElement>(10);
const badgeMag2 = useMagneticShared<HTMLDivElement>(10);
@@ -106,10 +89,6 @@ export default function FinalCTASection() {
'-=0.35'
)
.call(burstCoins)
.fromTo('.fcta-btns',
{ opacity: 0, y: 20 },
{ opacity: 1, y: 0, duration: 0.55, ease: 'power3.out' }, '-=0.45'
)
.fromTo('.fcta-stat',
{ opacity: 0, y: 28, scale: 0.88 },
{ opacity: 1, y: 0, scale: 1, duration: 0.55, stagger: 0.1, ease: 'back.out(1.8)' }, '-=0.25'
@@ -147,8 +126,8 @@ export default function FinalCTASection() {
ref={sectionRef}
style={{
position: 'relative',
width: 'calc(100% - 40px)',
margin: '0 20px 20px',
width: 'calc(100% - (var(--sec-gutter) * 2))',
margin: '0 var(--sec-gutter) var(--sec-gap)',
borderRadius: 32,
overflow: 'hidden',
background: '#ffffff',
@@ -176,7 +155,7 @@ export default function FinalCTASection() {
fontSize: 'clamp(52px,8vw,116px)',
fontWeight: 900, color: '#171512',
}}>
Your lyts
Your Lyts
</span>
<span className="fcta-line-2" style={{
display: 'block',
@@ -263,41 +242,7 @@ export default function FinalCTASection() {
</div>
</div>
{/* CTAs */}
<div className="fcta-btns" style={{ display: 'flex', gap: 14, justifyContent: 'center', flexWrap: 'wrap', marginBottom: 64 }}>
<Link
href="/contacts"
ref={mag1}
style={{
display: 'inline-flex', alignItems: 'center', gap: 9,
padding: '16px 34px', borderRadius: 100,
background: 'linear-gradient(135deg,#f4be28,#ff9500)',
color: '#1a1200', fontWeight: 800, fontSize: '0.97rem',
fontFamily: 'Sora, sans-serif', textDecoration: 'none',
boxShadow: '0 8px 32px rgba(244,190,40,0.35)',
transition: 'box-shadow 0.3s ease, transform 0.3s ease',
}}
>
<svg width="17" height="17" viewBox="0 0 24 24" fill="currentColor"><path d="M18.71 19.5c-.83 1.24-1.71 2.45-3.05 2.47-1.34.03-1.77-.79-3.29-.79-1.53 0-2 .77-3.27.82-1.31.05-2.3-1.32-3.14-2.53C4.25 17 2.94 12.45 4.7 9.39c.87-1.52 2.43-2.48 4.12-2.51 1.28-.02 2.5.87 3.29.87.78 0 2.26-1.07 3.8-.91.65.03 2.47.26 3.64 1.98-.09.06-2.17 1.28-2.15 3.81.03 3.02 2.65 4.03 2.68 4.04-.03.07-.42 1.44-1.38 2.83M13 3.5c.73-.83 1.94-1.46 2.94-1.5.13 1.17-.34 2.35-1.04 3.19-.69.85-1.83 1.51-2.95 1.42-.15-1.15.41-2.35 1.05-3.11z"/></svg>
Download for iOS
</Link>
<Link
href="/contacts"
ref={mag2}
style={{
display: 'inline-flex', alignItems: 'center', gap: 9,
padding: '16px 34px', borderRadius: 100,
background: 'transparent',
color: '#171512', fontWeight: 700, fontSize: '0.97rem',
fontFamily: 'Sora, sans-serif', textDecoration: 'none',
border: '1.5px solid rgba(23,21,18,0.2)',
transition: 'border-color 0.3s ease, background 0.3s ease',
}}
>
<svg width="17" height="17" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7"><rect x="2" y="8" width="20" height="10" rx="2"/><path d="M7.83 3l1.3 2.35M16.17 3l-1.3 2.35"/></svg>
Get on Android
</Link>
</div>
{/* Proof stats — individual sticker cards, matching the dark-border card system used across the page */}
<div className="fcta-proof-row" style={{ display: 'flex', justifyContent: 'center', gap: 18, flexWrap: 'wrap', width: '80%', maxWidth: 720, margin: '0 auto' }}>
@@ -389,18 +334,10 @@ export default function FinalCTASection() {
.fcta-sweep { display: none; }
}
@media (max-width: 1023px) {
.fcta-store-badges {
display: none !important;
}
.fcta-sub {
margin-bottom: 40px !important;
}
}
@media (min-width: 1024px) {
.fcta-btns {
display: none !important;
}
}
@media (max-width: 560px) {
.fcta-proof-row {
width: 100% !important;

View File

@@ -357,6 +357,10 @@ export default function VerticalScrollWrapper({ children, sections = [] }: Props
}
@media (max-width: 600px) {
.fp-shell { padding: 0 22px; }
/* Full-bleed panels on phones (no left/right margin), keep bottom gap */
.fp-panel { width: 100%; margin: 0 0 12px; }
/* Hero flush to the top on phones */
.fp-root { padding-top: 0; }
}
@media (prefers-reduced-motion: reduce) {

View File

@@ -178,6 +178,16 @@ export default function HeroCarousel({ onReady }: HeroCarouselProps) {
}
}
/* Phones — full-bleed hero, flush to top (top margin 0), keep bottom gap */
@media (max-width: 600px) {
.hero-carousel {
width: 100%;
height: calc(100vh - 12px);
height: calc(100svh - 12px);
margin: 0 0 12px;
}
}
.hero-carousel-slides {
position: absolute;
inset: 0;

View File

@@ -156,8 +156,8 @@ export default function LytsUpSection({ isLoaded = true }: LytsUpSectionProps) {
id="lytsup"
className="relative overflow-hidden"
style={{
width: 'calc(100% - 40px)',
margin: '0 20px 20px',
width: 'calc(100% - (var(--sec-gutter) * 2))',
margin: '0 var(--sec-gutter) var(--sec-gap)',
borderRadius: 32,
padding: 'clamp(64px, 8vw, 110px) clamp(20px, 4vw, 64px) clamp(64px, 8vw, 96px)',
zIndex: 2,

View File

@@ -110,8 +110,8 @@ export default function ProblemSection({ isLoaded = true }: ProblemSectionProps)
className="relative overflow-hidden problem-section"
style={{
background: '#ffffff',
width: 'calc(100% - 40px)',
margin: '0 20px 20px',
width: 'calc(100% - (var(--sec-gutter) * 2))',
margin: '0 var(--sec-gutter) var(--sec-gap)',
borderRadius: '32px',
padding: 'clamp(72px, 9vw, 130px) clamp(20px, 4vw, 64px) clamp(64px, 7vw, 96px)',
zIndex: 1,
@@ -526,8 +526,14 @@ export default function ProblemSection({ isLoaded = true }: ProblemSectionProps)
}
@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; }
#problem .problem-header-grid { grid-template-columns: 1fr !important; }
#problem .problem-header-right {
border-left: none !important;
padding-left: 0 !important;
border-top: 2px solid rgba(23,21,18,0.1) !important;
padding-top: 20px !important;
margin-top: 20px !important;
}
#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; }

View File

@@ -389,7 +389,7 @@ function ProductCard({ product, index }: { product: Product; index: number }) {
</div>
<Link
href="/solutions_page"
href="/meet_the_agents"
style={{
display: 'inline-flex', alignItems: 'center', gap: '8px', width: 'max-content',
padding: '11px 22px', borderRadius: '99px', fontSize: '0.85rem', fontWeight: 800,
@@ -694,7 +694,15 @@ export default function ProductsSection({ isLoaded = false }: ProductsSectionPro
flex-direction: column; align-items: flex-start; gap: 16px;
padding: clamp(40px, 8vw, 64px) 24px 24px;
}
.products-heading-hint { text-align: left !important; }
.products-heading-hint {
text-align: left !important;
border-right: none !important;
padding-right: 0 !important;
border-top: 2px solid rgba(244,190,40,0.3) !important;
padding-top: 16px !important;
margin-top: 8px !important;
max-width: 100% !important;
}
.products-track {
position: relative; height: auto;
padding-top: 8px; padding-bottom: 8px;

View File

@@ -135,8 +135,8 @@ export default function ShiftSection({ isLoaded = true }: ShiftSectionProps) {
className="relative overflow-hidden shift-section"
style={{
background: 'linear-gradient(155deg, #fffdf6 0%, #fbf5e4 48%, #f6ecd2 100%)',
width: 'calc(100% - 40px)',
margin: '0 20px 20px',
width: 'calc(100% - (var(--sec-gutter) * 2))',
margin: '0 var(--sec-gutter) var(--sec-gap)',
borderRadius: '32px',
padding: 'clamp(72px, 9vw, 130px) clamp(20px, 4vw, 64px) clamp(56px, 7vw, 90px)',
zIndex: 1,
@@ -490,8 +490,14 @@ export default function ShiftSection({ isLoaded = true }: ShiftSectionProps) {
}
@media (max-width: 900px) {
#shift .shift-header-grid { grid-template-columns: 1fr; }
#shift .shift-header-right { border-left: none; padding-left: 0; border-top: 2px solid rgba(244,190,40,0.3); padding-top: 20px; margin-top: 20px; }
#shift .shift-header-grid { grid-template-columns: 1fr !important; }
#shift .shift-header-right {
border-left: none !important;
padding-left: 0 !important;
border-top: 2px solid rgba(244,190,40,0.3) !important;
padding-top: 20px !important;
margin-top: 20px !important;
}
}
`}</style>
</section>

View File

@@ -32,7 +32,7 @@ interface Step {
const STEPS: Step[] = [
{ step: '01', id: 'earn', title: 'Earn Online', desc: 'Daily login, 5,000-step walking challenges, and interactive games like Maze and Spin Wheel earn LYTs and unlock surprise coupons.' },
{ step: '02', id: 'engage', title: 'Unlock Deals', desc: 'Merchants create game based discount campaigns: customers play once to reveal their exclusive reward on a specific product.' },
{ step: '02', id: 'engage', title: 'Unlock Deals', desc: 'Merchants create LYTs-earning campaigns: customers play once to reveal their exclusive reward on a specific product.' },
{ step: '03', id: 'spend', title: 'Discover & Visit', desc: 'Browse participating stores nearby, view active game campaigns and LYTs-earning offers, then walk in and shop in person.' },
{ step: '04', id: 'repeat', title: 'Redeem & Repeat', desc: 'Use LYTs and coupons at checkout to save money, then come back tomorrow to earn more and keep the loop going.' },
];
@@ -270,8 +270,8 @@ export default function TheLoop() {
id="the-loop"
style={{
position: 'relative',
width: 'calc(100% - 40px)',
margin: '0 20px 0',
width: 'calc(100% - (var(--sec-gutter) * 2))',
margin: '0 var(--sec-gutter) 0',
borderRadius: '32px 32px 0 0',
overflow: 'hidden',
zIndex: 2,
@@ -316,7 +316,7 @@ export default function TheLoop() {
color: 'rgba(255,255,255,0.38)', lineHeight: 1.75,
fontFamily: 'Sora, sans-serif',
}}>
Earn LYTs online, unlock game based deals, discover nearby stores, and redeem offline.
Earn LYTs online, unlock LYTs-based deals, discover nearby stores, and redeem offline.
</p>
</div>
@@ -536,8 +536,8 @@ export default function TheLoop() {
id="the-loop-mobile"
style={{
position: 'relative',
width: 'calc(100% - 40px)',
margin: '0 20px 0',
width: 'calc(100% - (var(--sec-gutter) * 2))',
margin: '0 var(--sec-gutter) 0',
borderRadius: '32px 32px 0 0',
overflow: 'hidden',
zIndex: 2,
@@ -581,7 +581,7 @@ export default function TheLoop() {
color: 'rgba(255,255,255,0.4)', lineHeight: 1.5,
fontFamily: 'Sora, sans-serif',
}}>
Earn LYTs online, unlock game based deals, discover nearby stores, and redeem offline.
Earn LYTs online, unlock LYTs-based deals, discover nearby stores, and redeem offline.
</p>
</div>
@@ -729,8 +729,8 @@ export default function TheLoop() {
{/* Impact metrics — outside section to avoid overflow:hidden clipping */}
<div style={{
position: 'relative', zIndex: 2,
width: 'calc(100% - 40px)',
margin: '0 20px 20px',
width: 'calc(100% - (var(--sec-gutter) * 2))',
margin: '0 var(--sec-gutter) var(--sec-gap)',
borderRadius: '0 0 32px 32px',
background: '#0c0a07',
padding: 'clamp(32px,4vh,52px) clamp(28px,5vw,80px) clamp(28px,4vh,48px)',

View File

@@ -221,8 +221,8 @@ export default function WhatWeDo({ isLoaded = false }: WhatWeDoProps) {
id="what-we-do"
className="relative bg-[#0D0D0D] !pt-32 sm:!pt-40 md:!pt-44 pb-24 md:pb-32 px-6 md:px-12 xl:px-16 overflow-hidden select-none"
style={{
width: 'calc(100% - 40px)',
margin: '0 20px 20px',
width: 'calc(100% - (var(--sec-gutter) * 2))',
margin: '0 var(--sec-gutter) var(--sec-gap)',
borderRadius: 32,
zIndex: 2,
}}

View File

@@ -24,7 +24,7 @@ export const HERO_SLIDES: HeroSlideData[] = [
ctaLabel: 'Book a Demo',
ctaHref: '/contacts',
secondaryLabel: 'See How It Works',
secondaryHref: '/solutions_page',
secondaryHref: '/meet_the_agents',
image: '/assets/home_hero/home_hero_01.png',
imageAlt: 'Shoppers walking through a modern premium shopping mall',
},
@@ -50,9 +50,9 @@ export const HERO_SLIDES: HeroSlideData[] = [
description:
'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',
ctaHref: '/meet_the_agents',
secondaryLabel: 'Meet the Tools',
secondaryHref: '/solutions_page',
secondaryHref: '/meet_the_agents',
image: '/assets/home_hero/home_hero_03.png',
imageAlt: 'Aerial view of a large, crowded luxury shopping mall atrium',
},

View File

@@ -115,17 +115,17 @@ export default function ProductsScrollSection() {
return (
<section
ref={sectionRef}
className="products-scroll-section"
style={{
position: 'relative',
height: `${(TOTAL - 1) * STEP_VH + 100}vh`,
background: '#07070d',
margin: '0 20px 20px',
borderRadius: 24,
overflow: 'hidden',
}}
>
<div
ref={pinRef}
className="uc-pp-pin"
style={{
height: '100vh',
display: 'flex',
@@ -144,7 +144,7 @@ export default function ProductsScrollSection() {
}} />
{/* Header */}
<div style={{ position: 'relative', zIndex: 2, marginBottom: 'clamp(56px,8vh,96px)' }}>
<div className="uc-pp-header" style={{ position: 'relative', zIndex: 2, marginBottom: 'clamp(56px,8vh,96px)' }}>
<SectionEyebrow variant="pill" style={{ marginBottom: 16 }}>Our Products</SectionEyebrow>
<h2 style={{ fontSize: 'clamp(32px, 4.5vw, 64px)', fontWeight: 800, letterSpacing: '-0.05em', lineHeight: 0.92, color: '#fff', margin: 0, fontFamily: 'Sora, sans-serif', maxWidth: 640 }}>
Offline Shopping. Online Intelligence.
@@ -152,7 +152,7 @@ export default function ProductsScrollSection() {
</div>
{/* Horizontal progress track with 3 points */}
<div style={{ position: 'relative', zIndex: 2, margin: '0 0 clamp(72px,10vh,120px)', padding: '0 16px' }}>
<div className="uc-pp-track" style={{ position: 'relative', zIndex: 2, margin: '0 0 clamp(72px,10vh,120px)', padding: '0 16px' }}>
<div style={{ position: 'relative', height: 2, background: 'rgba(255,255,255,0.08)', borderRadius: 2 }}>
{/* Growing fill line */}
<div
@@ -215,6 +215,7 @@ export default function ProductsScrollSection() {
<div
key={p.name}
ref={el => { visualRefs.current[i] = el; }}
data-pp-panel
style={{
position: 'absolute', inset: 0,
opacity: i === 0 ? 1 : 0,
@@ -234,7 +235,7 @@ export default function ProductsScrollSection() {
<div style={{ position: 'absolute', bottom: '-25%', left: '-15%', width: '55%', aspectRatio: '1', borderRadius: '50%', background: 'rgba(0,0,0,0.08)', pointerEvents: 'none' }} />
{/* Ghost number */}
<span style={{
<span data-pp-ghost style={{
position: 'absolute', bottom: -30, right: 14, lineHeight: 1,
fontSize: 'clamp(130px,13vw,200px)', fontWeight: 900,
fontFamily: 'Sora, sans-serif', letterSpacing: '-0.06em',
@@ -257,7 +258,7 @@ export default function ProductsScrollSection() {
{/* Hero metric */}
<div style={{ position: 'relative' }}>
<div style={{
<div data-pp-metric style={{
fontSize: 'clamp(72px,8.5vw,130px)', fontWeight: 900, lineHeight: 0.9,
color: '#111', fontFamily: 'Sora, sans-serif', letterSpacing: '-0.05em',
}}>{p.metric}</div>
@@ -273,7 +274,7 @@ export default function ProductsScrollSection() {
</div>
{/* Right — editorial text (stacked, cross-fading) */}
<div style={{ position: 'relative', minHeight: 'clamp(300px, 38vh, 420px)' }}>
<div className="uc-pp-text" style={{ position: 'relative', minHeight: 'clamp(300px, 38vh, 420px)' }}>
{PRODUCTS.map((p, i) => (
<div
key={p.name}
@@ -287,22 +288,22 @@ export default function ProductsScrollSection() {
display: 'flex', flexDirection: 'column', justifyContent: 'center',
}}
>
<div style={{
<div data-pp-tag style={{
display: 'inline-block', width: 'fit-content', fontSize: 11, fontWeight: 700, letterSpacing: '0.14em',
textTransform: 'uppercase', color: p.color, fontFamily: 'Sora, sans-serif',
marginBottom: 20, background: `${p.color}15`, padding: '6px 14px', borderRadius: 100,
border: `1px solid ${p.color}30`,
}}>{p.tag}</div>
<h3 style={{ fontSize: 'clamp(34px, 4vw, 60px)', fontWeight: 800, letterSpacing: '-0.04em', lineHeight: 0.95, color: '#fff', margin: '0 0 22px', fontFamily: 'Sora, sans-serif' }}>{p.name}</h3>
<h3 data-pp-title style={{ fontSize: 'clamp(34px, 4vw, 60px)', fontWeight: 800, letterSpacing: '-0.04em', lineHeight: 0.95, color: '#fff', margin: '0 0 22px', fontFamily: 'Sora, sans-serif' }}>{p.name}</h3>
<p style={{
<p data-pp-desc style={{
fontSize: 'clamp(15px,1.25vw,19px)', lineHeight: 1.7, color: 'rgba(255,255,255,0.45)',
fontFamily: 'Sora, sans-serif', margin: '0 0 36px', maxWidth: 460,
paddingLeft: 20, borderLeft: `2px solid ${p.color}55`,
}}>{p.desc}</p>
<Link href="/contacts" style={{
<Link href="/contacts" data-pp-cta style={{
display: 'inline-flex', alignItems: 'center', gap: 8, width: 'fit-content',
padding: '15px 32px', background: p.color, color: '#111',
fontSize: 14, fontWeight: 800, borderRadius: 100, textDecoration: 'none',
@@ -315,12 +316,75 @@ export default function ProductsScrollSection() {
</div>
<style>{`
.products-scroll-section {
margin: 0 20px 20px;
width: calc(100% - 40px);
border-radius: 24px;
}
@media (max-width: 768px) {
.products-scroll-section {
margin: 0 var(--sec-gutter) 20px !important;
width: calc(100% - (var(--sec-gutter) * 2)) !important;
}
}
/* ── Tablet / large phone: stack the two columns. The section is a fixed
100vh pin, so the stacked blocks are kept compact enough to fit the
viewport height across this whole range (incl. shorter tablets). ── */
@media (max-width: 860px) {
.uc-pp-grid { grid-template-columns: 1fr !important; gap: 24px !important; }
.uc-pp-visual { min-height: 260px !important; }
.uc-pp-pin { padding: 0 4% !important; }
.uc-pp-grid { grid-template-columns: 1fr !important; gap: 20px !important; }
.uc-pp-visual { min-height: 200px !important; }
/* Text panels are absolutely-positioned crossfaders, so the column
needs an explicit height to reserve space for them. */
.uc-pp-text { min-height: 260px !important; }
.uc-pp-label { display: none; }
.uc-pp-header { margin-bottom: 30px !important; }
.uc-pp-track { margin-bottom: 40px !important; }
}
/* ── Phone: compress further so the pinned frame never clips the header
or CTA, even on short viewports. ── */
@media (max-width: 600px) {
.uc-pp-pin { padding: 0 24px !important; }
.uc-pp-header { margin-bottom: 26px !important; }
.uc-pp-header h2 { font-size: clamp(26px, 7.5vw, 34px) !important; }
.uc-pp-track { margin-bottom: 34px !important; padding: 0 14px !important; }
.uc-pp-grid { gap: 18px !important; }
.uc-pp-visual { min-height: 190px !important; }
.uc-pp-text { min-height: 270px !important; }
/* Shrink the oversized hero metric + ghost number to fit the panel */
.uc-pp-visual [data-pp-metric] { font-size: clamp(52px, 15vw, 72px) !important; }
.uc-pp-visual [data-pp-ghost] { font-size: clamp(96px, 30vw, 130px) !important; bottom: -20px !important; }
.uc-pp-visual [data-pp-panel] { padding: 20px 22px !important; }
/* Tighten the editorial text stack */
.uc-pp-text [data-pp-title] { font-size: clamp(28px, 8vw, 38px) !important; margin-bottom: 14px !important; }
.uc-pp-text [data-pp-desc] { font-size: 14px !important; margin-bottom: 22px !important; line-height: 1.6 !important; }
.uc-pp-text [data-pp-tag] { margin-bottom: 14px !important; }
.uc-pp-text [data-pp-cta] { padding: 13px 26px !important; }
}
/* ── Short viewports (small phones like iPhone SE ~568px, landscape,
short windows). The pinned frame equals the viewport height, so on
these we compress aggressively so nothing spills out of view.
Scoped to the stacked range so desktop short windows are untouched. ── */
@media (max-width: 860px) and (max-height: 700px) {
.uc-pp-header { margin-bottom: 16px !important; }
.uc-pp-header h2 { font-size: clamp(20px, 6vw, 27px) !important; line-height: 1 !important; }
.uc-pp-track { margin-bottom: 22px !important; }
.uc-pp-grid { gap: 14px !important; }
.uc-pp-visual { min-height: 156px !important; }
.uc-pp-text { min-height: 230px !important; }
.uc-pp-visual [data-pp-metric] { font-size: 46px !important; }
.uc-pp-visual [data-pp-ghost] { font-size: 92px !important; bottom: -16px !important; }
.uc-pp-visual [data-pp-panel] { padding: 16px 18px !important; }
.uc-pp-text [data-pp-tag] { margin-bottom: 10px !important; }
.uc-pp-text [data-pp-title] { font-size: 25px !important; margin-bottom: 8px !important; }
.uc-pp-text [data-pp-desc] { font-size: 12.5px !important; margin-bottom: 14px !important; line-height: 1.5 !important; }
.uc-pp-text [data-pp-cta] { padding: 10px 20px !important; font-size: 12.5px !important; }
}
`}</style>
</section>
);
}
}