refactor: replace RobotCategoryGrid with CategoryShowcaseScroll and update styles across components
Some checks are pending
CI/CD / test-and-build (push) Waiting to run
CI/CD / deploy (push) Blocked by required conditions

- Updated HomePage to use CategoryShowcaseScroll instead of RobotCategoryGrid for better category display.
- Modified BrandShowcase component to adjust background gradients and text colors for improved aesthetics.
- Changed CompanyStory component to enhance visual consistency with updated accent colors.
- Refined ExclusiveAccessSection to align with new design standards, including gradient adjustments.
- Enhanced Hero3DRobotics with new gradient backgrounds and updated text colors for better readability.
- Updated RoboticsScrollShowcase to reflect new color scheme and improved text visibility.
- Adjusted RoboticsSplineShowcase to maintain design consistency with updated colors and gradients.
- Improved MotionSection to enhance scroll behavior and visibility transitions.
- Updated container-scroll-animation styles for better visual effects.
- Introduced new CategoryShowcaseScroll component for a more dynamic category display experience.
This commit is contained in:
Najjar\NajjarV02 2026-05-20 18:15:43 +04:00
parent 729ab71c2c
commit 8457493f49
11 changed files with 711 additions and 39 deletions

View File

@ -15,7 +15,7 @@
--color-blue-deep: #1a2e6e;
--color-blue-bright: #3a55c4;
--color-silver: #DEE0F0;
--color-silver-soft: #BFC3E2;
--color-silver-soft: #D7DBEA;
--color-steel: #8891C7;
--color-graphite: #221F20;
--color-white: #FBFBFD;
@ -23,7 +23,7 @@
/* Accent aliases (kept for legacy class names) */
--color-gold: #DEE0F0;
--color-accent: #273F94;
--color-accent-2: #BFC3E2;
--color-accent-2: #D7DBEA;
--color-accent-3: #8891C7;
--color-accent-hover: #3a55c4;
@ -34,14 +34,14 @@
--color-text-dim: #6a73a5;
/* Borders */
--color-border: rgba(191, 195, 226, 0.18);
--color-border-strong: rgba(191, 195, 226, 0.36);
--color-border-light: rgba(191, 195, 226, 0.08);
--color-border: rgba(199, 207, 230, 0.18);
--color-border-strong: rgba(199, 207, 230, 0.36);
--color-border-light: rgba(199, 207, 230, 0.08);
--color-border-neutral: rgba(255, 255, 255, 0.08);
/* Glass */
--color-glass-bg: rgba(28, 27, 33, 0.6);
--color-glass-border: rgba(191, 195, 226, 0.22);
--color-glass-border: rgba(199, 207, 230, 0.22);
--color-glass-highlight: rgba(222, 224, 240, 0.06);
/* Spacing */
@ -129,7 +129,7 @@ html {
/* === Typography gradients (metallic silver-blue) === */
.text-gradient {
background: linear-gradient(135deg, #FBFBFD 0%, #DEE0F0 45%, #8891C7 100%);
background: linear-gradient(135deg, #FFFFFF 0%, #DEE0F0 50%, #8891C7 100%);
-webkit-background-clip: text;
background-clip: text;
-webkit-text-fill-color: transparent;
@ -137,7 +137,7 @@ html {
}
.text-gradient-accent {
background: linear-gradient(135deg, #FBFBFD 0%, #DEE0F0 35%, #BFC3E2 65%, #273F94 100%);
background: linear-gradient(135deg, #FFFFFF 0%, #DEE0F0 50%, #8891C7 100%);
-webkit-background-clip: text;
background-clip: text;
-webkit-text-fill-color: transparent;
@ -186,8 +186,8 @@ html {
position: absolute;
inset: 0;
background-image:
linear-gradient(rgba(191, 195, 226, 0.05) 1px, transparent 1px),
linear-gradient(90deg, rgba(191, 195, 226, 0.05) 1px, transparent 1px);
linear-gradient(rgba(199, 207, 230, 0.05) 1px, transparent 1px),
linear-gradient(90deg, rgba(199, 207, 230, 0.05) 1px, transparent 1px);
background-size: 48px 48px;
mask-image: radial-gradient(ellipse 60% 50% at 50% 40%, #000 30%, transparent 80%);
-webkit-mask-image: radial-gradient(ellipse 60% 50% at 50% 40%, #000 30%, transparent 80%);
@ -213,7 +213,7 @@ html {
position: absolute;
inset: 0;
pointer-events: none;
background: linear-gradient(110deg, transparent 30%, rgba(191, 195, 226, 0.07) 50%, transparent 70%);
background: linear-gradient(110deg, transparent 30%, rgba(199, 207, 230, 0.07) 50%, transparent 70%);
background-size: 250% 100%;
animation: lightSweep 9s ease-in-out infinite;
mix-blend-mode: screen;
@ -297,7 +297,7 @@ html {
.btn-ghost {
background: rgba(222, 224, 240, 0.04);
color: #FBFBFD;
border-color: rgba(191, 195, 226, 0.28);
border-color: rgba(199, 207, 230, 0.28);
backdrop-filter: blur(12px);
}
.btn-ghost:hover {

View File

@ -3,7 +3,7 @@ import { Navbar } from '@/components/Navbar';
import { FooterAndContact } from '@/components/FooterAndContact';
import { Hero3DRobotics } from '@/components/robotics/Hero3DRobotics';
import { BrandShowcase } from '@/components/robotics/BrandShowcase';
import { RobotCategoryGrid } from '@/components/robotics/RobotCategoryGrid';
import { CategoryShowcaseScroll } from '@/components/robotics/CategoryShowcaseScroll';
import { RobotProductCard } from '@/components/robotics/RobotProductCard';
import { IndustryUseCases } from '@/components/robotics/IndustryUseCases';
import { DemoCTA } from '@/components/robotics/DemoCTA';
@ -88,9 +88,9 @@ export default function HomePage() {
<SectionHeading
eyebrow="Robot categories"
title="From quadruped patrol to humanoid concierge."
description="Find the right robot for your business humanoid for events and education, quadruped for inspection and security, service and delivery for hospitality."
description="Find the right robot for your business — humanoid platforms for events and education, quadrupeds for inspection and security, and service robots for hospitality, delivery, and cleaning."
/>
<RobotCategoryGrid />
<CategoryShowcaseScroll />
</div>
</MotionSection>

View File

@ -107,7 +107,7 @@ function BrandCard({
position: 'absolute',
inset: 0,
backgroundImage:
'linear-gradient(rgba(191,195,226,0.04) 1px, transparent 1px), linear-gradient(90deg, rgba(191,195,226,0.04) 1px, transparent 1px)',
'linear-gradient(rgba(199, 207, 230,0.04) 1px, transparent 1px), linear-gradient(90deg, rgba(199, 207, 230,0.04) 1px, transparent 1px)',
backgroundSize: '32px 32px',
maskImage: 'radial-gradient(ellipse 60% 80% at 50% 40%, #000 30%, transparent 80%)',
WebkitMaskImage: 'radial-gradient(ellipse 60% 80% at 50% 40%, #000 30%, transparent 80%)',
@ -198,7 +198,7 @@ function BrandCard({
<p
style={{
margin: 0,
color: '#BFC3E2',
color: '#D7DBEA',
fontSize: '0.92rem',
lineHeight: 1.55,
}}
@ -274,7 +274,7 @@ function BrandCard({
position: 'absolute',
inset: 0,
backgroundImage:
'linear-gradient(rgba(191,195,226,0.06) 1px, transparent 1px), linear-gradient(90deg, rgba(191,195,226,0.06) 1px, transparent 1px)',
'linear-gradient(rgba(199, 207, 230,0.06) 1px, transparent 1px), linear-gradient(90deg, rgba(199, 207, 230,0.06) 1px, transparent 1px)',
backgroundSize: '24px 24px',
maskImage: 'radial-gradient(ellipse 60% 60% at 50% 50%, #000 30%, transparent 80%)',
WebkitMaskImage: 'radial-gradient(ellipse 60% 60% at 50% 50%, #000 30%, transparent 80%)',

View File

@ -0,0 +1,670 @@
'use client';
import { useRef, useEffect, useState } from 'react';
import Image from 'next/image';
import Link from 'next/link';
import { motion, useScroll, useTransform } from 'framer-motion';
import { ArrowRight, Bot, Footprints, Coffee, Truck, Sparkles, Hotel, Search, Factory } from 'lucide-react';
import type { LucideIcon } from 'lucide-react';
type Category = {
id: string;
name: string;
brand: 'Unitree' | 'Pudu Robotics' | 'Unitree + Pudu';
brandAccent: string;
models: string;
description: string;
useCases: string[];
image: string;
imageAlt: string;
href: string;
Icon: LucideIcon;
};
const CATEGORIES: Category[] = [
{
id: 'humanoid',
name: 'Humanoid Robots',
brand: 'Unitree',
brandAccent: '#DEE0F0',
models: 'G1 · H2 · R1',
description:
'Bipedal humanoid platforms for events, education, research, and customer-facing experiences across the UAE.',
useCases: ['Events & activations', 'Education & STEM', 'Research labs', 'Concierge & reception'],
image: '/images/robots/unitree-g1.png',
imageAlt: 'Unitree G1 humanoid robot',
href: '/robots/?category=humanoid',
Icon: Bot,
},
{
id: 'quadruped',
name: 'Quadruped Robots',
brand: 'Unitree',
brandAccent: '#DEE0F0',
models: 'Go2 · B2 · A2',
description:
'Agile four-legged robots built for inspection, security patrol, and field mobility in any terrain.',
useCases: ['Facility inspection', 'Security patrol', 'Terrain mobility', 'Robotics research'],
image: '/images/robots/unitree-go2.png',
imageAlt: 'Unitree Go2 quadruped robot',
href: '/robots/?category=quadruped',
Icon: Footprints,
},
{
id: 'service',
name: 'Service Robots',
brand: 'Pudu Robotics',
brandAccent: '#8891C7',
models: 'KettyBot · BellaBot',
description:
'Greeting, guiding, and customer-interaction robots designed for restaurants, hotels, and retail venues.',
useCases: ['Restaurant greeting', 'Customer guidance', 'Retail activation', 'Hospitality service'],
image: '/images/robots/pudu-kettybot.svg',
imageAlt: 'Pudu KettyBot service robot',
href: '/robots/?category=service',
Icon: Coffee,
},
{
id: 'delivery',
name: 'Delivery Robots',
brand: 'Pudu Robotics',
brandAccent: '#8891C7',
models: 'BellaBot · D-Series',
description:
'Multi-tray autonomous delivery robots for hotels, restaurants, hospitals, and back-of-house operations.',
useCases: ['Hotel room service', 'Restaurant delivery', 'Hospital logistics', 'Back-of-house transport'],
image: '/images/robots/pudu-bellabot.svg',
imageAlt: 'Pudu BellaBot delivery robot',
href: '/robots/?category=delivery',
Icon: Truck,
},
{
id: 'cleaning',
name: 'Cleaning Robots',
brand: 'Pudu Robotics',
brandAccent: '#8891C7',
models: 'CC1 · Commercial Cleaning',
description:
'Autonomous commercial cleaning platforms that sweep, scrub, mop, and vacuum across large venues.',
useCases: ['Shopping malls', 'Airports & transit', 'Hotels & resorts', 'Corporate offices'],
image: '/images/robots/pudu-cc1.svg',
imageAlt: 'Pudu CC1 cleaning robot',
href: '/robots/?category=cleaning',
Icon: Sparkles,
},
{
id: 'hospitality',
name: 'Hospitality Robots',
brand: 'Pudu Robotics',
brandAccent: '#8891C7',
models: 'BellaBot · KettyBot',
description:
'Premium guest-facing robots for hotels, resorts, and events — designed to enhance every guest moment.',
useCases: ['Hotel concierge', 'Resort service', 'Event activations', 'Guest experience'],
image: '/images/robots/pudu-bellabot.svg',
imageAlt: 'Pudu BellaBot hospitality robot',
href: '/robots/?category=hospitality',
Icon: Hotel,
},
{
id: 'inspection',
name: 'Inspection Robots',
brand: 'Unitree',
brandAccent: '#DEE0F0',
models: 'Go2 · B2 · AS2',
description:
'Quadruped inspection platforms for energy, utilities, and industrial sites — equipped with rich sensor payloads.',
useCases: ['Energy & utilities', 'Industrial sites', 'Infrastructure', 'Security patrols'],
image: '/images/robots/unitree-b2.png',
imageAlt: 'Unitree B2 industrial quadruped robot',
href: '/robots/?category=inspection',
Icon: Search,
},
{
id: 'commercial',
name: 'Commercial Automation',
brand: 'Unitree + Pudu',
brandAccent: '#3a55c4',
models: 'Multi-brand portfolio',
description:
'Mixed robotics fleets for warehouses, smart buildings, and enterprise operations across the UAE.',
useCases: ['Warehouses', 'Smart buildings', 'Enterprise venues', 'Mixed-fleet deployments'],
image: '/images/robots/unitree-as2.png',
imageAlt: 'Unitree AS2 autonomous system for commercial automation',
href: '/robots/?category=commercial',
Icon: Factory,
},
];
export function CategoryShowcaseScroll() {
const [isMobile, setIsMobile] = useState(false);
useEffect(() => {
const check = () => setIsMobile(window.innerWidth < 900);
check();
window.addEventListener('resize', check);
return () => window.removeEventListener('resize', check);
}, []);
if (isMobile) return <CategoryStack />;
return <CategorySticky />;
}
function CategorySticky() {
const containerRef = useRef<HTMLDivElement>(null);
const { scrollYProgress } = useScroll({
target: containerRef,
offset: ['start start', 'end end'],
});
const [activeIdx, setActiveIdx] = useState(0);
useEffect(() => {
return scrollYProgress.on('change', (v) => {
const idx = Math.min(
CATEGORIES.length - 1,
Math.max(0, Math.floor(v * CATEGORIES.length))
);
setActiveIdx(idx);
});
}, [scrollYProgress]);
/* progress bar height */
const progressHeight = useTransform(scrollYProgress, [0, 1], ['0%', '100%']);
return (
<div
ref={containerRef}
style={{
position: 'relative',
/* 65vh per category — total ~520vh feels responsive, not endless */
height: `${CATEGORIES.length * 65}vh`,
}}
>
<div
style={{
position: 'sticky',
top: '5.5rem',
/* fill the viewport — no empty area below the panel during sticky */
height: 'calc(100svh - 6.5rem)',
maxHeight: '780px',
display: 'grid',
gridTemplateColumns: 'minmax(0, 0.95fr) minmax(0, 1.05fr)',
gap: 'clamp(1.5rem, 3vw, 2.5rem)',
alignItems: 'stretch',
}}
>
{/* LEFT — sticky text column with progress + active category */}
<div style={{ position: 'relative', display: 'flex', flexDirection: 'column', justifyContent: 'space-between', padding: '0.25rem 0', minWidth: 0 }}>
{/* progress rail */}
<div
style={{
position: 'absolute',
left: 0,
top: 0,
bottom: 0,
width: 2,
background: 'rgba(136,145,199,0.15)',
borderRadius: 1,
overflow: 'hidden',
}}
aria-hidden
>
<motion.div
style={{
width: '100%',
height: progressHeight,
background: 'linear-gradient(180deg, #DEE0F0, #3a55c4)',
boxShadow: '0 0 12px rgba(58,85,196,0.6)',
}}
/>
</div>
{/* category list */}
<div style={{ paddingLeft: '1.25rem', display: 'flex', flexDirection: 'column', gap: '0.4rem', maxHeight: '32vh', overflow: 'hidden' }}>
<span className="eyebrow" style={{ marginBottom: '0.5rem' }}>Robot categories · 8</span>
{CATEGORIES.map((c, i) => (
<button
key={c.id}
type="button"
onClick={() => {
const el = containerRef.current;
if (!el) return;
const rect = el.getBoundingClientRect();
const targetY = window.scrollY + rect.top + (rect.height * (i + 0.5)) / CATEGORIES.length;
window.scrollTo({ top: targetY - window.innerHeight / 2, behavior: 'smooth' });
}}
style={{
display: 'flex',
alignItems: 'center',
gap: '0.55rem',
padding: '0.4rem 0',
background: 'transparent',
border: 'none',
cursor: 'pointer',
textAlign: 'left',
color: i === activeIdx ? '#FBFBFD' : '#6a73a5',
fontSize: i === activeIdx ? '1rem' : '0.85rem',
fontWeight: i === activeIdx ? 600 : 500,
letterSpacing: '-0.005em',
transition: 'color 0.3s, font-size 0.3s',
}}
>
<span
aria-hidden
style={{
width: i === activeIdx ? 18 : 8,
height: 1,
background: i === activeIdx ? '#DEE0F0' : '#3a3d52',
transition: 'width 0.3s, background 0.3s',
}}
/>
<span style={{ fontSize: '0.65rem', letterSpacing: '0.18em', color: '#6a73a5' }}>
{String(i + 1).padStart(2, '0')}
</span>
{c.name}
</button>
))}
</div>
{/* active category copy */}
<div style={{ paddingLeft: '1.25rem', marginTop: '1rem', display: 'flex', flexDirection: 'column', gap: '1rem' }}>
<motion.h2
key={`title-${activeIdx}`}
initial={{ opacity: 0, y: 14 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.45, ease: [0.16, 1, 0.3, 1] }}
style={{
margin: 0,
fontSize: 'clamp(1.6rem, 3.4vw, 2.4rem)',
fontWeight: 300,
lineHeight: 1.1,
letterSpacing: '-0.03em',
}}
>
<span className="text-gradient" style={{ fontWeight: 500 }}>
{CATEGORIES[activeIdx].name}
</span>
</motion.h2>
<motion.p
key={`desc-${activeIdx}`}
initial={{ opacity: 0, y: 14 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.45, delay: 0.05, ease: [0.16, 1, 0.3, 1] }}
style={{
margin: 0,
color: '#DEE0F0',
fontSize: 'clamp(0.92rem, 1.7vw, 1rem)',
lineHeight: 1.65,
maxWidth: 500,
}}
>
{CATEGORIES[activeIdx].description}
</motion.p>
<motion.div
key={`cta-${activeIdx}`}
initial={{ opacity: 0, y: 14 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.45, delay: 0.12, ease: [0.16, 1, 0.3, 1] }}
style={{ display: 'flex', flexWrap: 'wrap', gap: '0.5rem' }}
>
<Link
href={CATEGORIES[activeIdx].href}
style={{
display: 'inline-flex',
alignItems: 'center',
gap: '0.4rem',
padding: '0.7rem 1.2rem',
borderRadius: 999,
background: 'linear-gradient(135deg, #3a55c4 0%, #273F94 55%, #1a2e6e 100%)',
color: '#FBFBFD',
fontSize: '0.72rem',
fontWeight: 700,
letterSpacing: '0.16em',
textTransform: 'uppercase',
textDecoration: 'none',
boxShadow: '0 12px 32px rgba(39,63,148,0.45)',
}}
>
Explore robots
<ArrowRight size={13} />
</Link>
<Link
href="/book-demo/"
style={{
display: 'inline-flex',
alignItems: 'center',
gap: '0.4rem',
padding: '0.7rem 1.2rem',
borderRadius: 999,
border: '1px solid rgba(222,224,240,0.28)',
background: 'rgba(255,255,255,0.04)',
color: '#DEE0F0',
fontSize: '0.72rem',
fontWeight: 700,
letterSpacing: '0.16em',
textTransform: 'uppercase',
textDecoration: 'none',
}}
>
Book demo
<ArrowRight size={13} />
</Link>
</motion.div>
</div>
</div>
{/* RIGHT — visual stage */}
<div
style={{
position: 'relative',
borderRadius: 24,
overflow: 'hidden',
background:
`radial-gradient(ellipse 70% 50% at 50% 60%, rgba(58,85,196,0.28) 0%, transparent 65%), linear-gradient(180deg, rgba(28,27,33,0.85), rgba(8,8,10,0.97))`,
border: '1px solid rgba(222,224,240,0.14)',
boxShadow: '0 30px 90px rgba(0,0,0,0.7), inset 0 1px 0 rgba(222,224,240,0.06)',
}}
>
{/* metallic edge */}
<div
aria-hidden
style={{
position: 'absolute',
inset: 0,
borderRadius: 24,
padding: 1,
background:
'linear-gradient(135deg, rgba(222,224,240,0.32), transparent 45%, rgba(58,85,196,0.22))',
WebkitMask: 'linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0)',
WebkitMaskComposite: 'xor',
maskComposite: 'exclude',
pointerEvents: 'none',
}}
/>
{/* grid */}
<div
aria-hidden
style={{
position: 'absolute',
inset: 0,
backgroundImage:
'linear-gradient(rgba(199, 207, 230,0.06) 1px, transparent 1px), linear-gradient(90deg, rgba(199, 207, 230,0.06) 1px, transparent 1px)',
backgroundSize: '36px 36px',
maskImage: 'radial-gradient(ellipse 70% 70% at 50% 50%, #000 30%, transparent 80%)',
WebkitMaskImage: 'radial-gradient(ellipse 70% 70% at 50% 50%, #000 30%, transparent 80%)',
pointerEvents: 'none',
}}
/>
{/* spotlight */}
<div
aria-hidden
style={{
position: 'absolute',
top: '5%',
left: '50%',
transform: 'translateX(-50%)',
width: '70%',
height: '70%',
background:
'radial-gradient(ellipse 60% 70% at 50% 35%, rgba(58,85,196,0.45) 0%, transparent 65%)',
filter: 'blur(14px)',
pointerEvents: 'none',
}}
/>
{/* top floating brand chip */}
<div
style={{
position: 'absolute',
top: '1.25rem',
left: '1.25rem',
zIndex: 5,
display: 'flex',
alignItems: 'center',
gap: '0.5rem',
padding: '0.4rem 0.85rem',
borderRadius: 999,
background: 'rgba(14,13,18,0.7)',
border: `1px solid ${CATEGORIES[activeIdx].brandAccent}55`,
color: CATEGORIES[activeIdx].brandAccent,
fontSize: '0.65rem',
fontWeight: 800,
letterSpacing: '0.24em',
textTransform: 'uppercase',
backdropFilter: 'blur(8px)',
transition: 'border-color 0.4s, color 0.4s',
}}
>
<span style={{ width: 6, height: 6, borderRadius: 999, background: CATEGORIES[activeIdx].brandAccent }} />
{CATEGORIES[activeIdx].brand}
</div>
{/* top-right index */}
<div
style={{
position: 'absolute',
top: '1.25rem',
right: '1.25rem',
zIndex: 5,
fontSize: 'clamp(2rem, 4vw, 3rem)',
fontWeight: 800,
color: 'transparent',
WebkitTextStroke: '1px rgba(222,224,240,0.32)',
letterSpacing: '-0.04em',
lineHeight: 1,
}}
>
{String(activeIdx + 1).padStart(2, '0')}
<span style={{ color: '#6a73a5', WebkitTextStroke: 0, fontSize: '0.7rem', letterSpacing: '0.2em', marginLeft: 4 }}>
/ {String(CATEGORIES.length).padStart(2, '0')}
</span>
</div>
{/* product stage — cross-fade per category */}
<div style={{ position: 'absolute', inset: 0 }}>
{CATEGORIES.map((c, i) => (
<motion.div
key={c.id}
aria-hidden={i !== activeIdx}
initial={false}
animate={{
opacity: i === activeIdx ? 1 : 0,
scale: i === activeIdx ? 1 : 0.94,
filter: i === activeIdx ? 'blur(0px)' : 'blur(6px)',
}}
transition={{ duration: 0.7, ease: [0.16, 1, 0.3, 1] }}
style={{
position: 'absolute',
inset: 0,
display: 'flex',
alignItems: 'flex-end',
justifyContent: 'center',
padding: 'clamp(1.5rem, 4vw, 3rem)',
paddingBottom: '32%',
}}
>
<div
style={{
position: 'relative',
width: '100%',
height: '100%',
filter:
'drop-shadow(0 32px 50px rgba(0,0,0,0.78)) drop-shadow(0 0 32px rgba(58,85,196,0.45))',
}}
>
<Image
src={c.image}
alt={c.imageAlt}
fill
sizes="(max-width: 768px) 90vw, 620px"
style={{ objectFit: 'contain', objectPosition: 'center bottom' }}
priority={i === 0}
/>
</div>
</motion.div>
))}
</div>
{/* floor line */}
<div
aria-hidden
style={{
position: 'absolute',
left: '6%',
right: '6%',
bottom: '32%',
height: 1,
background: 'linear-gradient(90deg, transparent, rgba(222,224,240,0.55), transparent)',
pointerEvents: 'none',
}}
/>
{/* floor reflection */}
{CATEGORIES.map((c, i) => (
<motion.div
key={`r-${c.id}`}
aria-hidden
initial={false}
animate={{ opacity: i === activeIdx ? 0.3 : 0 }}
transition={{ duration: 0.7 }}
style={{
position: 'absolute',
left: 'clamp(1.5rem, 4vw, 3rem)',
right: 'clamp(1.5rem, 4vw, 3rem)',
bottom: '6%',
height: '22%',
transform: 'scaleY(-1)',
transformOrigin: 'center top',
maskImage: 'linear-gradient(to bottom, rgba(0,0,0,0.8), transparent 78%)',
WebkitMaskImage: 'linear-gradient(to bottom, rgba(0,0,0,0.8), transparent 78%)',
pointerEvents: 'none',
filter: 'blur(1.4px)',
}}
>
<Image
src={c.image}
alt=""
fill
sizes="(max-width: 768px) 90vw, 620px"
style={{ objectFit: 'contain', objectPosition: 'center top' }}
/>
</motion.div>
))}
{/* bottom info bar: models + use cases */}
<motion.div
key={`info-${activeIdx}`}
initial={{ opacity: 0, y: 16 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.5, delay: 0.08, ease: [0.16, 1, 0.3, 1] }}
style={{
position: 'absolute',
bottom: '1rem',
left: '1rem',
right: '1rem',
zIndex: 5,
padding: '0.875rem 1.1rem',
borderRadius: 16,
background: 'rgba(14,13,18,0.78)',
border: '1px solid rgba(222,224,240,0.16)',
backdropFilter: 'blur(14px)',
display: 'flex',
flexDirection: 'column',
gap: '0.55rem',
}}
>
<div style={{ display: 'flex', flexWrap: 'wrap', alignItems: 'center', justifyContent: 'space-between', gap: '0.5rem' }}>
<span style={{ fontSize: '0.62rem', color: '#8891C7', letterSpacing: '0.24em', textTransform: 'uppercase', fontWeight: 700 }}>
Featured models
</span>
<span style={{ fontSize: '0.85rem', color: '#FBFBFD', fontWeight: 600 }}>
{CATEGORIES[activeIdx].models}
</span>
</div>
<div style={{ display: 'flex', flexWrap: 'wrap', gap: '0.35rem' }}>
{CATEGORIES[activeIdx].useCases.map((u) => (
<span
key={u}
style={{
fontSize: '0.66rem',
padding: '0.22rem 0.55rem',
borderRadius: 999,
background: 'rgba(255,255,255,0.04)',
border: '1px solid rgba(222,224,240,0.18)',
color: '#D7DBEA',
letterSpacing: '0.04em',
}}
>
{u}
</span>
))}
</div>
</motion.div>
</div>
</div>
</div>
);
}
function CategoryStack() {
return (
<div style={{ display: 'flex', flexDirection: 'column', gap: '1rem' }}>
{CATEGORIES.map((c, i) => (
<Link
key={c.id}
href={c.href}
style={{
position: 'relative',
display: 'grid',
gridTemplateColumns: 'minmax(0, 1fr) 130px',
gap: '0.75rem',
padding: '1rem',
borderRadius: 18,
background:
`radial-gradient(ellipse 70% 80% at 100% 0%, ${c.brandAccent}1F, transparent 60%), linear-gradient(135deg, rgba(28,27,33,0.85), rgba(8,8,10,0.96))`,
border: `1px solid ${c.brandAccent}33`,
color: '#FBFBFD',
textDecoration: 'none',
overflow: 'hidden',
minHeight: 150,
}}
>
<div style={{ display: 'flex', flexDirection: 'column', gap: '0.5rem', minWidth: 0 }}>
<span style={{ fontSize: '0.6rem', letterSpacing: '0.22em', textTransform: 'uppercase', color: '#8891C7', fontWeight: 700 }}>
{String(i + 1).padStart(2, '0')} · {c.brand}
</span>
<h3 style={{ margin: 0, fontSize: '1.05rem', fontWeight: 700, letterSpacing: '-0.01em' }}>
{c.name}
</h3>
<p style={{ margin: 0, color: '#D7DBEA', fontSize: '0.82rem', lineHeight: 1.5 }}>
{c.description}
</p>
<span style={{ marginTop: 'auto', display: 'inline-flex', alignItems: 'center', gap: '0.35rem', color: c.brandAccent, fontSize: '0.68rem', letterSpacing: '0.18em', textTransform: 'uppercase', fontWeight: 700 }}>
Explore
<ArrowRight size={12} />
</span>
</div>
<div
style={{
position: 'relative',
borderRadius: 12,
overflow: 'hidden',
background:
`radial-gradient(ellipse 70% 50% at 50% 60%, ${c.brandAccent}22 0%, transparent 65%), linear-gradient(180deg, rgba(28,27,33,0.7), rgba(10,10,12,0.95))`,
border: '1px solid rgba(222,224,240,0.08)',
}}
>
<Image
src={c.image}
alt={c.imageAlt}
fill
sizes="130px"
style={{ objectFit: 'contain', padding: '0.5rem' }}
/>
</div>
</Link>
))}
</div>
);
}

View File

@ -31,7 +31,7 @@ const PILLARS: Pillar[] = [
title: 'Digital Transformation',
body: 'Automation systems and smart projects that modernize operations.',
Icon: Workflow,
accent: '#BFC3E2',
accent: '#D7DBEA',
},
{
num: '04',
@ -63,7 +63,7 @@ export function CompanyStory() {
position: 'absolute',
inset: 0,
backgroundImage:
'linear-gradient(rgba(191,195,226,0.06) 1px, transparent 1px), linear-gradient(90deg, rgba(191,195,226,0.06) 1px, transparent 1px)',
'linear-gradient(rgba(199, 207, 230,0.06) 1px, transparent 1px), linear-gradient(90deg, rgba(199, 207, 230,0.06) 1px, transparent 1px)',
backgroundSize: '36px 36px',
maskImage: 'radial-gradient(ellipse 70% 80% at 50% 40%, #000 25%, transparent 80%)',
WebkitMaskImage: 'radial-gradient(ellipse 70% 80% at 50% 40%, #000 25%, transparent 80%)',
@ -348,7 +348,7 @@ function CapabilityTile({ pillar, offset }: { pillar: Pillar; offset: 'up' | 'do
margin: 0,
fontSize: '0.88rem',
lineHeight: 1.55,
color: '#BFC3E2',
color: '#D7DBEA',
position: 'relative',
}}
>

View File

@ -189,7 +189,7 @@ function BrandShowcaseTile({
position: 'absolute',
inset: 0,
backgroundImage:
'linear-gradient(rgba(191,195,226,0.06) 1px, transparent 1px), linear-gradient(90deg, rgba(191,195,226,0.06) 1px, transparent 1px)',
'linear-gradient(rgba(199, 207, 230,0.06) 1px, transparent 1px), linear-gradient(90deg, rgba(199, 207, 230,0.06) 1px, transparent 1px)',
backgroundSize: '24px 24px',
maskImage: 'radial-gradient(ellipse 60% 60% at 50% 50%, #000 30%, transparent 80%)',
WebkitMaskImage: 'radial-gradient(ellipse 60% 60% at 50% 50%, #000 30%, transparent 80%)',
@ -334,7 +334,7 @@ function TerritoryTile() {
<circle cx="155" cy="55" r="32" fill="none" stroke="#DEE0F0" strokeOpacity="0.45" strokeDasharray="2 4" />
<circle cx="155" cy="55" r="22" fill="none" stroke="#DEE0F0" strokeOpacity="0.65" />
<circle cx="155" cy="55" r="3.5" fill="#DEE0F0" />
<text x="160" y="44" fontFamily="Inter, sans-serif" fontSize="8" letterSpacing="3" fill="#BFC3E2" textAnchor="start">DXB</text>
<text x="160" y="44" fontFamily="Inter, sans-serif" fontSize="8" letterSpacing="3" fill="#D7DBEA" textAnchor="start">DXB</text>
</svg>
<div style={{ position: 'relative', display: 'flex', flexDirection: 'column', gap: 4 }}>
<span style={{ fontSize: '0.62rem', color: '#8891C7', letterSpacing: '0.22em', textTransform: 'uppercase', fontWeight: 700 }}>

View File

@ -141,7 +141,7 @@ export function Hero3DRobotics() {
display: 'block',
fontWeight: 600,
background:
'linear-gradient(110deg, #FBFBFD 0%, #DEE0F0 28%, #BFC3E2 55%, #3a55c4 100%)',
'linear-gradient(110deg, #FFFFFF 0%, #DEE0F0 50%, #8891C7 100%)',
WebkitBackgroundClip: 'text',
backgroundClip: 'text',
WebkitTextFillColor: 'transparent',
@ -157,7 +157,7 @@ export function Hero3DRobotics() {
<p style={{ margin: 0, color: '#DEE0F0', fontSize: 'clamp(1rem, 2vw, 1.18rem)', lineHeight: 1.7, maxWidth: 600, fontWeight: 300 }}>
YS Lootah Robotics is the exclusive UAE sales destination for selected Unitree and Pudu Robotics solutions helping businesses explore, configure, book demos, and deploy advanced robots across Dubai and the UAE.
</p>
<p style={{ margin: 0, color: '#BFC3E2', fontSize: '0.78rem', letterSpacing: '0.32em', textTransform: 'uppercase', fontWeight: 600 }}>
<p style={{ margin: 0, color: '#D7DBEA', fontSize: '0.78rem', letterSpacing: '0.32em', textTransform: 'uppercase', fontWeight: 600 }}>
In Tech We Innovate · In Trust We Lead
</p>

View File

@ -18,7 +18,7 @@ const SHOWROOM_ROBOTS = [
slug: 'unitree-go2',
image: '/images/robots/unitree-go2.png',
category: 'Quadruped',
accent: '#BFC3E2',
accent: '#D7DBEA',
},
{
name: 'Pudu BellaBot',
@ -58,10 +58,10 @@ export function RoboticsScrollShowcase() {
</span>
<h2 className="text-4xl font-light leading-[1.05] tracking-[-0.035em] text-white sm:text-5xl md:text-6xl lg:text-7xl">
Advanced robotics.
<span className="block bg-gradient-to-r from-white via-[#DEE0F0] to-[#3a55c4] bg-clip-text font-semibold text-transparent">
<span className="block bg-gradient-to-r from-white via-[#DEE0F0] to-[#8891C7] bg-clip-text font-semibold text-transparent">
Exclusive UAE access.
</span>
<span className="mt-3 block text-base font-normal text-[#BFC3E2] sm:text-lg md:text-xl">
<span className="mt-3 block text-base font-normal text-[#D7DBEA] sm:text-lg md:text-xl">
Built for Dubai&apos;s next generation of automation.
</span>
</h2>
@ -92,14 +92,14 @@ function ConsoleInterior() {
className={`flex items-center gap-2.5 rounded-lg border px-3 py-2 text-left text-xs font-semibold uppercase tracking-[0.12em] transition ${
t.active
? 'border-[#DEE0F0]/40 bg-[#273F94]/30 text-[#DEE0F0]'
: 'border-transparent text-[#BFC3E2]/80 hover:bg-white/[0.04]'
: 'border-transparent text-[#D7DBEA]/80 hover:bg-white/[0.04]'
}`}
>
<t.icon className="h-3.5 w-3.5" />
{t.label}
</button>
))}
<div className="mt-auto rounded-xl border border-[#DEE0F0]/10 bg-[#221F20]/60 p-3 text-[10px] uppercase tracking-[0.18em] text-[#BFC3E2]/70">
<div className="mt-auto rounded-xl border border-[#DEE0F0]/10 bg-[#221F20]/60 p-3 text-[10px] uppercase tracking-[0.18em] text-[#D7DBEA]/70">
<span className="block text-[#DEE0F0]">YS Lootah Robotics</span>
In Tech We Innovate
</div>
@ -169,7 +169,7 @@ function ConsoleInterior() {
</Link>
<Link
href="/contact/"
className="inline-flex items-center gap-1.5 rounded-full border border-[#DEE0F0]/30 px-3.5 py-2 text-[10px] font-bold uppercase tracking-[0.16em] text-[#BFC3E2] md:text-[11px]"
className="inline-flex items-center gap-1.5 rounded-full border border-[#DEE0F0]/30 px-3.5 py-2 text-[10px] font-bold uppercase tracking-[0.16em] text-[#D7DBEA] md:text-[11px]"
>
Request UAE quotation
</Link>

View File

@ -99,7 +99,7 @@ export function RoboticsSplineShowcase() {
style={{
display: 'inline-block',
background:
'linear-gradient(110deg, #FBFBFD 0%, #DEE0F0 35%, #BFC3E2 60%, #3a55c4 100%)',
'linear-gradient(110deg, #FFFFFF 0%, #DEE0F0 50%, #8891C7 100%)',
WebkitBackgroundClip: 'text',
backgroundClip: 'text',
WebkitTextFillColor: 'transparent',
@ -190,7 +190,7 @@ export function RoboticsSplineShowcase() {
borderRadius: 999,
border: '1px solid rgba(136,145,199,0.5)',
background: 'transparent',
color: '#BFC3E2',
color: '#D7DBEA',
fontSize: '0.78rem',
fontWeight: 700,
letterSpacing: '0.14em',
@ -231,7 +231,7 @@ export function RoboticsSplineShowcase() {
>
<item.Icon size={18} style={{ color: '#DEE0F0', marginBottom: '0.5rem' }} />
<div style={{ fontSize: '0.85rem', fontWeight: 600, color: '#FBFBFD' }}>{item.label}</div>
<div style={{ marginTop: 4, fontSize: '0.66rem', letterSpacing: '0.2em', textTransform: 'uppercase', color: 'rgba(191,195,226,0.72)' }}>
<div style={{ marginTop: 4, fontSize: '0.66rem', letterSpacing: '0.2em', textTransform: 'uppercase', color: 'rgba(199, 207, 230,0.72)' }}>
{item.value}
</div>
</div>
@ -246,7 +246,7 @@ export function RoboticsSplineShowcase() {
fontWeight: 600,
letterSpacing: '0.32em',
textTransform: 'uppercase',
color: '#BFC3E2',
color: '#D7DBEA',
}}
>
In Tech We Innovate · In Trust We Lead
@ -308,7 +308,7 @@ export function RoboticsSplineShowcase() {
backdropFilter: 'blur(12px)',
}}
>
<div style={{ fontSize: '0.62rem', letterSpacing: '0.22em', textTransform: 'uppercase', color: 'rgba(191,195,226,0.7)' }}>
<div style={{ fontSize: '0.62rem', letterSpacing: '0.22em', textTransform: 'uppercase', color: 'rgba(199, 207, 230,0.7)' }}>
YS Lootah Robotics
</div>
<div style={{ marginTop: 4, fontSize: '0.88rem', fontWeight: 600, color: '#FBFBFD' }}>

View File

@ -32,7 +32,7 @@ export function MotionSection({ children, className = '', id, delay = 0, style }
}
}
},
{ threshold: 0.12 }
{ threshold: 0, rootMargin: '0px 0px -10% 0px' }
);
obs.observe(el);
return () => obs.disconnect();
@ -45,7 +45,9 @@ export function MotionSection({ children, className = '', id, delay = 0, style }
className={className}
style={{
opacity: visible ? 1 : 0,
transform: visible ? 'translateY(0)' : 'translateY(28px)',
// when hidden, lift via translate. When visible, drop transform entirely so
// child position:sticky behaves correctly (transformed ancestor would break sticky).
...(visible ? {} : { transform: 'translateY(28px)' }),
transition: `opacity 0.9s cubic-bezier(0.16,1,0.3,1) ${delay}s, transform 0.9s cubic-bezier(0.16,1,0.3,1) ${delay}s`,
scrollMarginTop: '6rem',
...style,

View File

@ -113,7 +113,7 @@ function DisplayFrame({
/>
<div
aria-hidden
className="pointer-events-none absolute inset-0 bg-[linear-gradient(rgba(191,195,226,0.06)_1px,transparent_1px),linear-gradient(90deg,rgba(191,195,226,0.06)_1px,transparent_1px)] bg-[size:42px_42px] [mask-image:radial-gradient(ellipse_70%_70%_at_50%_50%,#000_30%,transparent_82%)]"
className="pointer-events-none absolute inset-0 bg-[linear-gradient(rgba(199, 207, 230,0.06)_1px,transparent_1px),linear-gradient(90deg,rgba(199, 207, 230,0.06)_1px,transparent_1px)] bg-[size:42px_42px] [mask-image:radial-gradient(ellipse_70%_70%_at_50%_50%,#000_30%,transparent_82%)]"
/>
{/* status bar */}
<div className="absolute left-0 right-0 top-0 z-20 flex items-center justify-between border-b border-[#DEE0F0]/10 bg-[#0a0a0c]/80 px-4 py-2.5 backdrop-blur-xl">