feat: add global responsive guards and enhance layout for mobile and touch interactions
Some checks are pending
CI/CD / test-and-build (push) Waiting to run
CI/CD / deploy (push) Blocked by required conditions

This commit is contained in:
Najjar\NajjarV02 2026-05-21 13:46:17 +04:00
parent de9f358582
commit fa5f4f7a3e
4 changed files with 164 additions and 76 deletions

View File

@ -696,3 +696,46 @@ html {
}
html, body { overflow-x: hidden; max-width: 100vw; }
/* === GLOBAL RESPONSIVE GUARDS === */
/* Anchor scroll never lands behind fixed navbar */
[id] { scroll-margin-top: clamp(80px, 12vh, 120px); }
/* No element overflows viewport horizontally */
img, video, svg, canvas { max-width: 100%; height: auto; }
/* Grid/flex children should be allowed to shrink below content width to prevent overflow */
.container-wide > * { min-width: 0; }
/* Tap targets: minimum 44x44 for interactive elements on touch screens */
@media (hover: none) and (pointer: coarse) {
a, button, [role='button'] { min-height: 44px; }
.cta-link { min-height: 32px; }
}
/* Mobile section padding tighter */
@media (max-width: 600px) {
.container-wide {
padding-left: 1rem;
padding-right: 1rem;
}
.eyebrow {
font-size: 0.68rem;
letter-spacing: 0.28em;
}
.cta-lg { padding: 0.85rem 1.25rem; font-size: 0.72rem; letter-spacing: 0.2em; }
.cta-md { padding: 0.8rem 1.15rem; font-size: 0.68rem; }
}
/* WhatsApp floating button: lift above safe-area on iOS, keep clear of footer content */
.wa-fab {
bottom: calc(1.25rem + env(safe-area-inset-bottom, 0px)) !important;
}
@media (max-width: 600px) {
.wa-fab {
width: 52px !important;
height: 52px !important;
bottom: calc(1rem + env(safe-area-inset-bottom, 0px)) !important;
}
}

View File

@ -67,7 +67,7 @@ export default function RootLayout({
<I18nProvider>
{children}
{/* WhatsApp Floating Button */}
<a href="https://wa.me/971559482728" target="_blank" rel="noopener noreferrer" aria-label="Contact us on WhatsApp" className="fixed bottom-6 z-50 flex items-center justify-center h-14 w-14 rounded-full bg-gradient-to-r from-[#25D366] to-[#128C7E] text-white shadow-lg shadow-[#25D366]/30 transition-all duration-300 ease-out hover:scale-110 hover:shadow-[#25D366]/50 hover:shadow-xl active:scale-95 group" style={{ insetInlineEnd: '1.5rem' }}>
<a href="https://wa.me/971559482728" target="_blank" rel="noopener noreferrer" aria-label="Contact us on WhatsApp" className="wa-fab fixed z-50 flex items-center justify-center h-14 w-14 rounded-full bg-gradient-to-r from-[#25D366] to-[#128C7E] text-white shadow-lg shadow-[#25D366]/30 transition-all duration-300 ease-out hover:scale-110 hover:shadow-[#25D366]/50 hover:shadow-xl active:scale-95 group" style={{ insetInlineEnd: 'max(1rem, env(safe-area-inset-right, 0px))' }}>
<span className="absolute inset-0 -z-10 rounded-full bg-gradient-to-r from-[#25D366] to-[#128C7E] opacity-0 blur-xl transition-opacity duration-300 group-hover:opacity-100"></span>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className="tabler-icon tabler-icon-brand-whatsapp relative z-10 h-8 w-8">
<path d="M3 21l1.65 -3.8a9 9 0 1 1 3.4 2.9l-5.05 .9"></path>

View File

@ -34,6 +34,15 @@ export function Navbar() {
};
}, [mobileOpen]);
useEffect(() => {
if (!mobileOpen) return;
const onKey = (e: KeyboardEvent) => {
if (e.key === 'Escape') setMobileOpen(false);
};
window.addEventListener('keydown', onKey);
return () => window.removeEventListener('keydown', onKey);
}, [mobileOpen]);
const isActive = (href: string) => {
if (href === '/') return pathname === '/' || pathname === '';
return pathname.startsWith(href.replace(/\/$/, ''));

View File

@ -34,7 +34,7 @@ const ICON_MAP: Record<Industry['icon'], LucideIcon> = {
};
const SHORT_COPY: Record<string, string> = {
hospitality: 'Service and delivery robots that help hotels, lounges, and guest venues operate smoothly.',
hospitality: 'Service and delivery robots for hotels, lounges, and guest venues.',
restaurants: 'Delivery robots that support faster table service and reduce staff walking time.',
hotels: 'Autonomous delivery and concierge-style robotics for premium guest experiences.',
malls: 'Cleaning, service, and activation robots for high-traffic retail environments.',
@ -58,7 +58,7 @@ export function IndustryUseCases({ limit }: { limit?: number }) {
return (
<section className="iu" aria-label="Industries served">
{/* STATS ROW */}
{/* STATS — compact dark chips */}
<motion.ul
className="iu-stats"
role="list"
@ -87,43 +87,77 @@ export function IndustryUseCases({ limit }: { limit?: number }) {
position: relative;
display: flex;
flex-direction: column;
gap: clamp(1.75rem, 3.5vw, 2.75rem);
padding: clamp(1.5rem, 3vw, 2.5rem) clamp(1.25rem, 2.5vw, 2rem);
border-radius: 24px;
background: #F6F7F9;
color: #0F1116;
gap: clamp(1.5rem, 3vw, 2.25rem);
}
/* STATS */
/* STATS — compact premium chips */
.iu-stats {
list-style: none;
margin: 0;
padding: 0.4rem 0;
padding: 0;
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 1rem 1.5rem;
border-top: 1px solid rgba(16, 22, 46, 0.08);
border-bottom: 1px solid rgba(16, 22, 46, 0.08);
gap: 0.55rem;
}
.iu-stat {
position: relative;
display: flex;
flex-direction: column;
gap: 0.2rem;
padding: 0.85rem 0.25rem;
justify-content: center;
gap: 0.35rem;
padding: clamp(0.7rem, 1.4vw, 0.95rem) clamp(0.85rem, 1.6vw, 1.1rem);
min-height: 84px;
border-radius: 18px;
border: 1px solid rgba(120, 140, 255, 0.22);
background:
linear-gradient(135deg, rgba(80, 110, 255, 0.12), rgba(255, 255, 255, 0.03));
overflow: hidden;
transition: border-color 0.3s, transform 0.3s, box-shadow 0.3s, background 0.3s;
}
.iu-stat::before {
content: '';
position: absolute;
top: 0;
right: 14px;
width: 28px;
height: 1px;
background: linear-gradient(90deg, transparent, rgba(180, 195, 255, 0.55));
}
.iu-stat::after {
content: '';
position: absolute;
inset: 0;
background: radial-gradient(ellipse 60% 80% at 100% 100%, rgba(74, 102, 216, 0.10), transparent 60%);
pointer-events: none;
opacity: 0;
transition: opacity 0.35s;
}
.iu-stat:hover {
border-color: rgba(120, 140, 255, 0.45);
transform: translateY(-1px);
box-shadow: 0 10px 24px rgba(0, 0, 0, 0.38), 0 0 18px rgba(74, 102, 216, 0.18);
}
.iu-stat:hover::after { opacity: 1; }
.iu-stat-value {
font-size: clamp(1.65rem, 3vw, 2.2rem);
font-weight: 600;
font-size: clamp(1.4rem, 2.4vw, 1.85rem);
font-weight: 500;
letter-spacing: -0.025em;
line-height: 1;
color: #0F1116;
background: linear-gradient(180deg, #FFFFFF, #B5BDDB);
-webkit-background-clip: text;
background-clip: text;
color: transparent;
position: relative;
z-index: 1;
}
.iu-stat-label {
font-size: 0.7rem;
letter-spacing: 0.18em;
font-size: 0.66rem;
letter-spacing: 0.22em;
text-transform: uppercase;
font-weight: 600;
color: #5b6076;
font-weight: 700;
color: #A6B2D8;
position: relative;
z-index: 1;
}
/* GRID */
@ -133,14 +167,14 @@ export function IndustryUseCases({ limit }: { limit?: number }) {
gap: 1rem;
}
@media (min-width: 600px) {
.iu-stats { grid-template-columns: repeat(4, minmax(0, 1fr)); }
@media (min-width: 760px) {
.iu-stats { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 0.7rem; }
.iu-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1.1rem; }
}
@media (min-width: 980px) {
.iu-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 1.25rem; }
@media (min-width: 1000px) {
.iu-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 1.2rem; }
}
@media (min-width: 1400px) {
@media (min-width: 1300px) {
.iu-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}
`}</style>
@ -169,9 +203,8 @@ function IndustryCard({ industry, delay }: { industry: Industry; delay: number }
<span className="ic-media-glow" />
<span className="ic-media-grid" />
<span className="ic-media-icon">
<Icon size={42} strokeWidth={1.4} />
<Icon size={36} strokeWidth={1.4} />
</span>
<span className="ic-media-tag">{industry.name}</span>
</div>
<div className="ic-body">
@ -192,38 +225,47 @@ function IndustryCard({ industry, delay }: { industry: Industry; delay: number }
display: flex;
flex-direction: column;
height: 100%;
background: #FFFFFF;
border: 1px solid rgba(16, 22, 46, 0.06);
border-radius: 18px;
overflow: hidden;
text-decoration: none;
color: inherit;
box-shadow: 0 4px 14px rgba(8, 12, 28, 0.04);
color: #FFFFFF;
border: 1px solid rgba(222, 224, 240, 0.10);
background:
radial-gradient(ellipse 80% 60% at 100% 0%, color-mix(in srgb, var(--accent) 12%, transparent), transparent 60%),
linear-gradient(180deg, rgba(22, 21, 30, 0.92), rgba(10, 10, 14, 0.96));
box-shadow:
0 1px 0 rgba(222, 224, 240, 0.04) inset,
0 14px 28px rgba(0, 0, 0, 0.36);
transition: transform 0.4s cubic-bezier(0.16, 1, 0.3, 1),
box-shadow 0.4s, border-color 0.4s;
}
.ic:hover,
.ic:focus-visible {
transform: translateY(-3px);
border-color: rgba(74, 102, 216, 0.28);
box-shadow: 0 18px 36px rgba(8, 12, 28, 0.10), 0 2px 6px rgba(8, 12, 28, 0.04);
border-color: rgba(74, 102, 216, 0.42);
box-shadow:
0 1px 0 rgba(222, 224, 240, 0.08) inset,
0 24px 52px rgba(0, 0, 0, 0.55),
0 0 0 1px rgba(74, 102, 216, 0.22),
0 0 28px rgba(58, 85, 196, 0.22);
}
.ic:focus-visible {
outline: 2px solid #4a66d8;
outline: 2px solid rgba(74, 102, 216, 0.75);
outline-offset: 3px;
}
/* MEDIA AREA */
/* MEDIA */
.ic-media {
position: relative;
aspect-ratio: 16 / 10;
background:
radial-gradient(ellipse 70% 80% at 30% 20%, color-mix(in srgb, var(--accent) 35%, white) 0%, transparent 60%),
linear-gradient(135deg, #EEF1F6 0%, #DDE3EE 100%);
radial-gradient(ellipse 70% 80% at 30% 30%, color-mix(in srgb, var(--accent) 14%, transparent) 0%, transparent 60%),
linear-gradient(135deg, rgba(20, 22, 36, 0.95) 0%, rgba(10, 11, 18, 0.98) 100%);
overflow: hidden;
display: flex;
align-items: center;
justify-content: center;
border-bottom: 1px solid rgba(222, 224, 240, 0.06);
}
.ic-media-glow {
position: absolute;
@ -232,16 +274,16 @@ function IndustryCard({ industry, delay }: { industry: Industry; delay: number }
left: 20%;
top: 10%;
border-radius: 999px;
background: radial-gradient(circle at 50% 50%, rgba(74, 102, 216, 0.16), transparent 65%);
filter: blur(20px);
background: radial-gradient(circle at 50% 50%, rgba(74, 102, 216, 0.22), transparent 65%);
filter: blur(22px);
pointer-events: none;
}
.ic-media-grid {
position: absolute;
inset: 0;
background-image:
linear-gradient(rgba(16, 22, 46, 0.05) 1px, transparent 1px),
linear-gradient(90deg, rgba(16, 22, 46, 0.05) 1px, transparent 1px);
linear-gradient(rgba(222, 224, 240, 0.05) 1px, transparent 1px),
linear-gradient(90deg, rgba(222, 224, 240, 0.05) 1px, transparent 1px);
background-size: 32px 32px;
mask-image: radial-gradient(ellipse 70% 80% at 50% 50%, #000 30%, transparent 80%);
-webkit-mask-image: radial-gradient(ellipse 70% 80% at 50% 50%, #000 30%, transparent 80%);
@ -253,54 +295,44 @@ function IndustryCard({ industry, delay }: { industry: Industry; delay: number }
display: inline-flex;
align-items: center;
justify-content: center;
width: 88px;
height: 88px;
border-radius: 22px;
color: #273F94;
background: rgba(255, 255, 255, 0.85);
border: 1px solid rgba(16, 22, 46, 0.06);
box-shadow: 0 8px 22px rgba(8, 12, 28, 0.08);
transition: transform 0.45s cubic-bezier(0.16, 1, 0.3, 1);
width: 72px;
height: 72px;
border-radius: 18px;
color: color-mix(in srgb, var(--accent) 80%, white);
background:
radial-gradient(ellipse 60% 60% at 50% 30%, color-mix(in srgb, var(--accent) 22%, transparent), transparent 70%),
rgba(14, 13, 18, 0.65);
border: 1px solid color-mix(in srgb, var(--accent) 32%, transparent);
box-shadow: 0 8px 22px rgba(0, 0, 0, 0.4);
transition: transform 0.45s cubic-bezier(0.16, 1, 0.3, 1),
box-shadow 0.4s, border-color 0.4s;
}
.ic:hover .ic-media-icon,
.ic:focus-visible .ic-media-icon {
transform: scale(1.06);
}
.ic-media-tag {
position: absolute;
left: 14px;
bottom: 12px;
z-index: 2;
padding: 0.32rem 0.65rem;
border-radius: 999px;
font-size: 0.62rem;
letter-spacing: 0.2em;
text-transform: uppercase;
font-weight: 700;
color: #273F94;
background: rgba(255, 255, 255, 0.85);
border: 1px solid rgba(39, 63, 148, 0.18);
transform: scale(1.08);
border-color: color-mix(in srgb, var(--accent) 60%, transparent);
box-shadow: 0 0 24px color-mix(in srgb, var(--accent) 40%, transparent);
}
/* BODY */
.ic-body {
display: flex;
flex-direction: column;
gap: 0.55rem;
padding: 1.1rem 1.15rem 1.15rem;
gap: 0.5rem;
padding: 1.05rem 1.15rem 1.1rem;
flex: 1;
}
.ic-title {
margin: 0;
font-size: 1.1rem;
font-size: 1.05rem;
font-weight: 600;
letter-spacing: -0.01em;
color: #0F1116;
color: #FFFFFF;
}
.ic-desc {
margin: 0;
color: #4a4f63;
font-size: 0.9rem;
color: #C9CCDE;
font-size: 0.88rem;
line-height: 1.55;
flex: 1;
display: -webkit-box;
@ -312,11 +344,15 @@ function IndustryCard({ industry, delay }: { industry: Industry; delay: number }
display: inline-flex;
align-items: center;
gap: 0.45rem;
margin-top: 0.4rem;
font-size: 0.82rem;
margin-top: 0.35rem;
font-size: 0.78rem;
font-weight: 600;
color: #273F94;
letter-spacing: 0.02em;
color: #DEE0F0;
transition: color 0.3s;
}
.ic:hover .ic-cta,
.ic:focus-visible .ic-cta { color: #FFFFFF; }
.ic-cta-arrow {
display: inline-flex;
align-items: center;