update home,about,solutions

This commit is contained in:
2026-06-01 20:20:14 +05:30
parent 8d74f7063e
commit a59a5e79dc
19 changed files with 3543 additions and 1381 deletions

View File

@@ -1932,10 +1932,10 @@ h1:where(.wp-block-heading).has-background,
--container-widget-flex-grow: 0;
--container-widget-align-self: initial;
--flex-wrap-mobile: wrap;
--padding-top: 20px;
--padding-bottom: 20px;
--padding-left: 20px;
--padding-right: 20px;
--padding-top: 32px;
--padding-bottom: 32px;
--padding-left: 32px;
--padding-right: 32px;
}
.elementor .elementor-element.elementor-element-6c7cbcb .elementor-repeater-item-3264830 {
@@ -2095,7 +2095,7 @@ h1:where(.wp-block-heading).has-background,
}
.elementor .elementor-element.elementor-element-6c7cbcb .owl-carousel .owl-stage-outer {
border-radius: 25px 25px 25px 25px;
border-radius: 32px 32px 32px 32px;
}
.elementor .elementor-element.elementor-element-6c7cbcb .content-slider.nav-view-compact .owl-nav,
@@ -13053,20 +13053,20 @@ h1:where(.wp-block-heading).has-background,
}
.elementor-61 .elementor-element.elementor-element-6c7cbcb .elementor-repeater-item-6867061 .slide-content-inner {
max-width: 64%;
margin: 110px 0px 0px 75px;
max-width: 88%;
margin: 0 auto;
}
.elementor-61 .elementor-element.elementor-element-6c7cbcb .elementor-repeater-item-6867061 .slide-content {
-webkit-align-items: flex-start;
-moz-align-items: flex-start;
-ms-align-items: flex-start;
align-items: flex-start;
-webkit-align-items: center;
-moz-align-items: center;
-ms-align-items: center;
align-items: center;
-webkit-justify-content: center;
-moz-justify-content: center;
-ms-justify-content: center;
justify-content: center;
text-align: left;
text-align: center;
}
.elementor-61 .elementor-element.elementor-element-6c7cbcb .elementor-repeater-item-6867061 .content-slider-item-heading {
@@ -19114,6 +19114,7 @@ img.wp-smiley,
--margin-bottom: 0px;
--margin-left: 0px;
--margin-right: 0px;
position: relative;
}
.elementor-element.elementor-element-f35119c {
@@ -28753,8 +28754,8 @@ img.wp-smiley,
--margin-right: 0px;
--padding-top: 0px;
--padding-bottom: 0px;
--padding-left: 20px;
--padding-right: 20px;
--padding-left: 0px;
--padding-right: 0px;
}
.elementor-element.elementor-element-13a7637 {
@@ -38655,11 +38656,13 @@ body.rtl .elementor-6473 .elementor-element.elementor-element-13a7637 {
--column-gap: 0px;
--background-transition: 0s;
--border-radius: 25px 25px 25px 25px;
border-radius: 25px;
overflow: hidden;
--z-index: 1;
}
.elementor-6473 .elementor-element.elementor-element-7da6646:not(.elementor-motion-effects-element-type-background), .elementor-6473 .elementor-element.elementor-element-7da6646 > .elementor-motion-effects-container > .elementor-motion-effects-layer {
background-image: url("/images/home4-banner-4.png");
background-image: url("/images/bg-header-5.png");
background-position: center center;
background-repeat: no-repeat;
background-size: cover;

View File

@@ -16806,7 +16806,7 @@ html.elementor-html {
}
}
/* .team-listing-wrapper.team-grid-listing {
.team-listing-wrapper.team-grid-listing {
display: block;
margin: 0 -10px -20px
}
@@ -17060,7 +17060,7 @@ html.elementor-html {
padding: 0 22px;
margin-bottom: 78px
}
} */
}
.body-container .single-team {
display: -webkit-box;

View File

@@ -19,6 +19,11 @@ export default function AnimationProvider({ children }: { children: React.ReactN
duration: 0.8,
});
// Mobile browsers fire `resize` when the address bar shows/hides while
// scrolling. Refreshing ScrollTrigger on every one of those caused jumpy /
// re-hidden animations on phones. Ignore those spurious resizes.
ScrollTrigger.config({ ignoreMobileResize: true });
const initDecorativeBlocks = () => {
// Clean up previous block triggers to avoid duplicates
ScrollTrigger.getAll().forEach((t) => {
@@ -27,6 +32,7 @@ export default function AnimationProvider({ children }: { children: React.ReactN
}
});
const vh = window.innerHeight || document.documentElement.clientHeight;
const decorativeBlocks = document.querySelectorAll(".block-decoration");
decorativeBlocks.forEach((block) => {
ScrollTrigger.create({
@@ -50,6 +56,14 @@ export default function AnimationProvider({ children }: { children: React.ReactN
block.classList.remove("animated");
},
});
// ScrollTrigger does not fire onEnter for blocks already in view at
// creation — on larger / taller screens those stayed un-animated.
// Reveal any block already intersecting the viewport.
const r = block.getBoundingClientRect();
if (r.top < vh && r.bottom > 0) {
block.classList.add("animated");
}
});
};
@@ -83,15 +97,22 @@ export default function AnimationProvider({ children }: { children: React.ReactN
};
window.addEventListener("load", handleLoad);
// Also refresh on window resize
// Refresh on window resize — debounced so dragging the window across
// breakpoints recomputes trigger positions once it settles, instead of
// thrashing on every intermediate pixel.
let resizeTimer: ReturnType<typeof setTimeout>;
const handleResize = () => {
initDecorativeBlocks();
ScrollTrigger.refresh(true);
clearTimeout(resizeTimer);
resizeTimer = setTimeout(() => {
initDecorativeBlocks();
ScrollTrigger.refresh(true);
}, 200);
};
window.addEventListener("resize", handleResize);
return () => {
timeouts.forEach(clearTimeout);
clearTimeout(resizeTimer);
window.removeEventListener("load", handleLoad);
window.removeEventListener("resize", handleResize);
ScrollTrigger.getAll().forEach((t) => t.kill());

View File

@@ -9,6 +9,71 @@ if (typeof window !== "undefined") {
gsap.registerPlugin(ScrollTrigger);
}
/* ============================================================
Shared scroll-reveal trigger factory.
ScrollTrigger does NOT fire `onEnter` for elements that are ALREADY inside
the viewport when the trigger is created. On taller / larger screens more
content sits above the fold on load, so those elements stayed stuck at
opacity:0 (invisible). This was the root cause of "animations work on my
laptop but break on bigger screens / other devices".
This factory fixes it by revealing any element already intersecting the
viewport right after creation, so behaviour is identical on every screen
size. It also honours prefers-reduced-motion by revealing instantly.
============================================================ */
function createRevealTrigger(opts: {
trigger: Element;
start?: string;
show: () => void;
hide: () => void;
triggerOnce?: boolean;
}): () => void {
const { trigger, start = "top 88%", show, hide, triggerOnce = false } = opts;
// Reduced motion: reveal immediately, no scroll dependency.
if (
typeof window !== "undefined" &&
window.matchMedia?.("(prefers-reduced-motion: reduce)").matches
) {
show();
return () => {};
}
const st = ScrollTrigger.create({
trigger,
start,
onEnter: (self) => {
show();
if (triggerOnce) self.kill();
},
onEnterBack: () => {
if (!triggerOnce) show();
},
onLeave: () => {
if (!triggerOnce) hide();
},
onLeaveBack: () => {
if (!triggerOnce) hide();
},
});
// Reveal-if-already-in-view (deferred one frame so layout is measured).
const raf = requestAnimationFrame(() => {
const r = trigger.getBoundingClientRect();
const vh = window.innerHeight || document.documentElement.clientHeight;
if (r.top < vh && r.bottom > 0) {
show();
if (triggerOnce) st.kill();
}
});
return () => {
cancelAnimationFrame(raf);
st.kill();
};
}
/* ============================================================
1. ScrollReveal
Fade-in + slide-up on scroll. The workhorse animation.
@@ -40,47 +105,19 @@ export function ScrollReveal({
gsap.set(el, { y: yOffset, x: xOffset, opacity: 0 });
const trigger = ScrollTrigger.create({
trigger: el,
start: "top 88%",
onEnter: (self) => {
gsap.to(el, {
y: 0,
x: 0,
opacity: 1,
duration,
ease: "power3.out",
delay,
overwrite: "auto",
});
if (triggerOnce) self.kill();
},
onEnterBack: () => {
if (!triggerOnce) {
gsap.to(el, {
y: 0,
x: 0,
opacity: 1,
duration,
ease: "power3.out",
delay,
overwrite: "auto",
});
}
},
onLeave: () => {
if (!triggerOnce) {
gsap.set(el, { y: yOffset, x: xOffset, opacity: 0 });
}
},
onLeaveBack: () => {
if (!triggerOnce) {
gsap.set(el, { y: yOffset, x: xOffset, opacity: 0 });
}
},
});
const show = () =>
gsap.to(el, {
y: 0,
x: 0,
opacity: 1,
duration,
ease: "power3.out",
delay,
overwrite: "auto",
});
const hide = () => gsap.set(el, { y: yOffset, x: xOffset, opacity: 0 });
return () => trigger?.kill();
return createRevealTrigger({ trigger: el, show, hide, triggerOnce });
}, [delay, duration, yOffset, xOffset, triggerOnce]);
return (
@@ -122,47 +159,19 @@ export function RevealText({
gsap.set(items, { y: "110%", opacity: 0 });
const trigger = ScrollTrigger.create({
trigger: el,
start: "top 88%",
onEnter: (self) => {
gsap.to(items, {
y: "0%",
opacity: 1,
duration,
ease: "power4.out",
stagger: type === "chars" ? 0.02 : 0.04,
delay,
overwrite: "auto",
});
if (triggerOnce) self.kill();
},
onEnterBack: () => {
if (!triggerOnce) {
gsap.to(items, {
y: "0%",
opacity: 1,
duration,
ease: "power4.out",
stagger: type === "chars" ? 0.02 : 0.04,
delay,
overwrite: "auto",
});
}
},
onLeave: () => {
if (!triggerOnce) {
gsap.set(items, { y: "110%", opacity: 0 });
}
},
onLeaveBack: () => {
if (!triggerOnce) {
gsap.set(items, { y: "110%", opacity: 0 });
}
},
});
const show = () =>
gsap.to(items, {
y: "0%",
opacity: 1,
duration,
ease: "power4.out",
stagger: type === "chars" ? 0.02 : 0.04,
delay,
overwrite: "auto",
});
const hide = () => gsap.set(items, { y: "110%", opacity: 0 });
return () => trigger?.kill();
return createRevealTrigger({ trigger: el, show, hide, triggerOnce });
}, [children, type, delay, duration, triggerOnce]);
const renderContent = () => {
@@ -290,45 +299,18 @@ export function StaggerChildren({
gsap.set(items, { y: yOffset, opacity: 0 });
const trigger = ScrollTrigger.create({
trigger: el,
start: "top 85%",
onEnter: (self) => {
gsap.to(items, {
y: 0,
opacity: 1,
duration,
ease: "power3.out",
stagger,
overwrite: "auto",
});
if (triggerOnce) self.kill();
},
onEnterBack: () => {
if (!triggerOnce) {
gsap.to(items, {
y: 0,
opacity: 1,
duration,
ease: "power3.out",
stagger,
overwrite: "auto",
});
}
},
onLeave: () => {
if (!triggerOnce) {
gsap.set(items, { y: yOffset, opacity: 0 });
}
},
onLeaveBack: () => {
if (!triggerOnce) {
gsap.set(items, { y: yOffset, opacity: 0 });
}
},
});
const show = () =>
gsap.to(items, {
y: 0,
opacity: 1,
duration,
ease: "power3.out",
stagger,
overwrite: "auto",
});
const hide = () => gsap.set(items, { y: yOffset, opacity: 0 });
return () => trigger?.kill();
return createRevealTrigger({ trigger: el, start: "top 85%", show, hide, triggerOnce });
}, [stagger, duration, yOffset, triggerOnce]);
return (
@@ -365,45 +347,18 @@ export function ScaleReveal({
gsap.set(el, { scale: 0.85, opacity: 0 });
const trigger = ScrollTrigger.create({
trigger: el,
start: "top 88%",
onEnter: (self) => {
gsap.to(el, {
scale: 1,
opacity: 1,
duration,
ease: "power3.out",
delay,
overwrite: "auto",
});
if (triggerOnce) self.kill();
},
onEnterBack: () => {
if (!triggerOnce) {
gsap.to(el, {
scale: 1,
opacity: 1,
duration,
ease: "power3.out",
delay,
overwrite: "auto",
});
}
},
onLeave: () => {
if (!triggerOnce) {
gsap.set(el, { scale: 0.85, opacity: 0 });
}
},
onLeaveBack: () => {
if (!triggerOnce) {
gsap.set(el, { scale: 0.85, opacity: 0 });
}
},
});
const show = () =>
gsap.to(el, {
scale: 1,
opacity: 1,
duration,
ease: "power3.out",
delay,
overwrite: "auto",
});
const hide = () => gsap.set(el, { scale: 0.85, opacity: 0 });
return () => trigger?.kill();
return createRevealTrigger({ trigger: el, show, hide, triggerOnce });
}, [delay, duration, triggerOnce]);
return (
@@ -443,45 +398,18 @@ export function SlideReveal({
const xStart = direction === "left" ? -60 : 60;
gsap.set(el, { x: xStart, opacity: 0 });
const trigger = ScrollTrigger.create({
trigger: el,
start: "top 88%",
onEnter: (self) => {
gsap.to(el, {
x: 0,
opacity: 1,
duration,
ease: "power3.out",
delay,
overwrite: "auto",
});
if (triggerOnce) self.kill();
},
onEnterBack: () => {
if (!triggerOnce) {
gsap.to(el, {
x: 0,
opacity: 1,
duration,
ease: "power3.out",
delay,
overwrite: "auto",
});
}
},
onLeave: () => {
if (!triggerOnce) {
gsap.set(el, { x: xStart, opacity: 0 });
}
},
onLeaveBack: () => {
if (!triggerOnce) {
gsap.set(el, { x: xStart, opacity: 0 });
}
},
});
const show = () =>
gsap.to(el, {
x: 0,
opacity: 1,
duration,
ease: "power3.out",
delay,
overwrite: "auto",
});
const hide = () => gsap.set(el, { x: xStart, opacity: 0 });
return () => trigger?.kill();
return createRevealTrigger({ trigger: el, show, hide, triggerOnce });
}, [direction, delay, duration, triggerOnce]);
return (
@@ -573,43 +501,18 @@ export function CountUp({
const el = elementRef.current;
if (!el) return;
const trigger = ScrollTrigger.create({
trigger: el,
start: "top 90%",
onEnter: (self) => {
const obj = { val: start };
gsap.to(obj, {
val: end,
duration,
ease: "power2.out",
onUpdate: () => setValue(obj.val),
});
if (triggerOnce) self.kill();
},
onEnterBack: () => {
if (!triggerOnce) {
const obj = { val: start };
gsap.to(obj, {
val: end,
duration,
ease: "power2.out",
onUpdate: () => setValue(obj.val),
});
}
},
onLeave: () => {
if (!triggerOnce) {
setValue(start);
}
},
onLeaveBack: () => {
if (!triggerOnce) {
setValue(start);
}
},
});
const show = () => {
const obj = { val: start };
gsap.to(obj, {
val: end,
duration,
ease: "power2.out",
onUpdate: () => setValue(obj.val),
});
};
const hide = () => setValue(start);
return () => trigger?.kill();
return createRevealTrigger({ trigger: el, start: "top 90%", show, hide, triggerOnce });
}, [start, end, duration, triggerOnce]);
return (

View File

@@ -18,7 +18,7 @@ export default function AboutUsPage() {
<div className="content-wrapper content-wrapper-may-contain-elementor-code content-wrapper-sidebar-position-none">
<div className="content">
<div className="content-inner">
<div data-elementor-type="wp-page" data-elementor-id="86" className="elementor elementor-86">
<div data-elementor-type="wp-page" data-elementor-id="86" className="elementor elementor-86 elementor-59">
<AboutHero />
<TheDoormileWay />
<EVLogisticSection />

View File

@@ -767,7 +767,7 @@ body {
content: '' !important;
position: absolute !important;
inset: 0 !important;
background: linear-gradient(to bottom, rgba(0, 0, 0, 0.45) 0%, rgba(0, 0, 0, 0.78) 55%, rgba(0, 0, 0, 0.95) 100%) !important;
background: var(--hero-overlay, linear-gradient(to bottom, rgba(0, 0, 0, 0.45) 0%, rgba(0, 0, 0, 0.78) 55%, rgba(0, 0, 0, 0.95) 100%)) !important;
z-index: 1 !important;
}
@@ -777,6 +777,13 @@ body {
}
/* Responsive constraints to keep all heroes matching the home page carousel perfectly */
@media (max-width: 1536px) {
.custom-standard-hero-card {
height: 600px !important;
min-height: 600px !important;
}
}
@media (max-width: 1024px) {
.custom-standard-hero-container {
padding: 10px 10px 10px 10px !important;

View File

@@ -1,5 +1,5 @@
import type { Metadata } from "next";
import { Manrope, Space_Grotesk } from "next/font/google";
import { Manrope, Space_Grotesk, Syne, DM_Sans } from "next/font/google";
import "./globals.css";
import Header from "@/components/layout/Header";
import Footer from "@/components/layout/Footer";
@@ -21,6 +21,19 @@ const spaceGrotesk = Space_Grotesk({
weight: ["400", "500", "600", "700"],
});
// Fonts for the Solutions industry section (Syne headings, DM Sans body).
const syne = Syne({
subsets: ["latin"],
variable: "--font-syne",
weight: ["600", "700", "800"],
});
const dmSans = DM_Sans({
subsets: ["latin"],
variable: "--font-dm-sans",
weight: ["400", "500"],
});
export const metadata: Metadata = {
title: "Doormile — Last-Mile Logistics Intelligence",
description: "Doormile powers last-mile logistics with MileTruth™ AI, providing connected miles, SLA protection, and carrier management.",
@@ -36,7 +49,7 @@ export default function RootLayout({
children: React.ReactNode;
}>) {
return (
<html lang="en-US" className={`${manrope.variable} ${spaceGrotesk.variable}`}>
<html lang="en-US" className={`${manrope.variable} ${spaceGrotesk.variable} ${syne.variable} ${dmSans.variable}`}>
<head>
{/* FontAwesome icons */}
<link

View File

@@ -515,6 +515,19 @@ export default function Header() {
background-color: #ffffff !important;
opacity: 1 !important;
}
/* The theme reveals the mobile slide-in menu via Elementor's
body[data-elementor-device-mode="mobile"] rules, which are set by
Elementor's frontend JS — that JS isn't shipped in this Next port,
so the panel stayed display:none and the hamburger opened nothing.
Restore it with the same 1024px breakpoint the nav already switches
at. The panel sits off-screen (right:-320px) until .active slides
it in, matching production behaviour. */
@media (max-width: 1024px) {
#masthead .elementor-widget-logico_navigation_menu .mobile-header-menu-container {
display: block !important;
}
}
`,
}}
/>

View File

@@ -8,18 +8,18 @@ export default function AboutHero() {
width: 100% !important;
text-align: center !important;
color: #fff !important;
padding: 60px 40px !important;
padding: 60px 40px 100px 40px !important;
z-index: 2;
display: flex !important;
flex-direction: column !important;
justify-content: center !important;
justify-content: flex-end !important;
align-items: center !important;
height: 100% !important;
}
.about-us-hero-title {
margin: 0 !important;
font-family: var(--font-manrope), sans-serif !important;
font-family: "Manrope", Sans-serif !important;
font-size: clamp(34px, 5.5vw, 68px) !important;
font-weight: 850 !important;
line-height: 1.1 !important;
@@ -33,7 +33,8 @@ export default function AboutHero() {
<div className="custom-standard-hero-container">
<div
style={{
backgroundImage: "linear-gradient(to bottom, rgba(0, 0, 0, 0.45) 0%, rgba(0, 0, 0, 0.78) 55%, rgba(0, 0, 0, 0.95) 100%), url('/images/about-bg.png')"
backgroundImage: "url('/images/about-bg.png')",
["--hero-overlay" as any]: "linear-gradient(to bottom, rgba(0, 0, 0, 0.15) 0%, rgba(0, 0, 0, 0.15) 60%, rgba(0, 0, 0, 0.55) 100%)"
}}
className="custom-standard-hero-card"
>

View File

@@ -1,12 +1,81 @@
import React from "react";
"use client";
import React, { useEffect, useRef } from "react";
import gsap from "gsap";
import { ScrollTrigger } from "gsap/ScrollTrigger";
if (typeof window !== "undefined") {
gsap.registerPlugin(ScrollTrigger);
}
export default function CompetitiveEdge() {
const sectionRef = useRef<HTMLDivElement>(null);
const tableWrapperRef = useRef<HTMLDivElement>(null);
const moatRef = useRef<HTMLDivElement>(null);
useEffect(() => {
const section = sectionRef.current;
const tableWrapper = tableWrapperRef.current;
const moat = moatRef.current;
if (!section || !tableWrapper || !moat) return;
// GSAP Timeline ScrollTrigger for viewport entrances
const entryTl = gsap.timeline({
scrollTrigger: {
trigger: section,
start: "top 78%",
toggleActions: "play none none none",
}
});
entryTl
// 1. Reveal Table & Right panel
.fromTo([tableWrapper, moat], {
opacity: 0,
y: 45,
}, {
opacity: 1,
y: 0,
duration: 0.95,
stagger: 0.12,
ease: "power4.out",
})
// 2. Stagger slide up row items
.fromTo(section.querySelectorAll(".table-row-hover"), {
opacity: 0,
y: 20,
}, {
opacity: 1,
y: 0,
duration: 0.75,
stagger: 0.05,
ease: "power3.out",
}, "-=0.6")
// 3. Pop checkmarks and badges cleanly
.fromTo(section.querySelectorAll(".yes-badge, .advanced-badge"), {
opacity: 0,
scale: 0.8,
}, {
opacity: 1,
scale: 1,
duration: 0.55,
stagger: 0.03,
ease: "back.out(1.6)",
}, "-=0.45");
}, []);
return (
<section id="comparison" className="comparison-section">
<section id="comparison" className="comparison-section" ref={sectionRef}>
{/* Visual background layers */}
<div className="comparison-bg-glow" />
<div className="comparison-bg-dots" />
<div className="container">
<div className="comparison-layout">
{/* Comparison matrix Table */}
<div className="table-wrapper">
{/* Comparison Matrix Table (69% on Desktop) */}
<div className="table-wrapper" ref={tableWrapperRef}>
<table className="comparison-table">
<thead>
<tr>
@@ -20,7 +89,7 @@ export default function CompetitiveEdge() {
<tbody>
<tr className="table-row-hover">
<td className="capability-cell">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" style={{ marginRight: "8px", display: "inline-block", verticalAlign: "middle" }}>
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round">
<rect x="1" y="3" width="15" height="13"></rect>
<polygon points="16 8 20 8 23 11 23 16 16 16 16 8"></polygon>
<circle cx="5.5" cy="18.5" r="2.5"></circle>
@@ -35,7 +104,7 @@ export default function CompetitiveEdge() {
</tr>
<tr className="table-row-hover">
<td className="capability-cell">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" style={{ marginRight: "8px", display: "inline-block", verticalAlign: "middle" }}>
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round">
<path d="M12 22c5.523 0 10-4.477 10-10S17.523 2 12 2 2 6.477 2 12s4.477 10 10 10z"></path>
<path d="M12 6v6l4 2"></path>
</svg>
@@ -48,7 +117,7 @@ export default function CompetitiveEdge() {
</tr>
<tr className="table-row-hover">
<td className="capability-cell">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" style={{ marginRight: "8px", display: "inline-block", verticalAlign: "middle" }}>
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round">
<polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"></polygon>
</svg>
EV-aware planning
@@ -60,8 +129,8 @@ export default function CompetitiveEdge() {
</tr>
<tr className="table-row-hover">
<td className="capability-cell">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" style={{ marginRight: "8px", display: "inline-block", verticalAlign: "middle" }}>
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h32a2 2 0 0 0 2-2V8z"></path>
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round">
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path>
<polyline points="14 2 14 8 20 8"></polyline>
<line x1="16" y1="13" x2="8" y2="13"></line>
<line x1="16" y1="17" x2="8" y2="17"></line>
@@ -76,7 +145,7 @@ export default function CompetitiveEdge() {
</tr>
<tr className="table-row-hover">
<td className="capability-cell">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" style={{ marginRight: "8px", display: "inline-block", verticalAlign: "middle" }}>
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round">
<circle cx="12" cy="12" r="10"></circle>
<polyline points="12 6 12 12 16 14"></polyline>
</svg>
@@ -89,20 +158,20 @@ export default function CompetitiveEdge() {
</tr>
<tr className="table-row-hover">
<td className="capability-cell">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" style={{ marginRight: "8px", display: "inline-block", verticalAlign: "middle" }}>
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round">
<path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"></path>
</svg>
Verified handling
</td>
<td className="col-highlight"><span className="yes-badge"> Yes</span></td>
<td className="no-text">No</td>
<td className="partial-text">Partial</td>
<td className="no-text">No</td>
<td className="no-text">No</td>
</tr>
<tr className="table-row-hover">
<td className="capability-cell">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" style={{ marginRight: "8px", display: "inline-block", verticalAlign: "middle" }}>
<path d="M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h38s-3-2-3-9"></path>
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round">
<path d="M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9"></path>
<path d="M13.73 21a2 2 0 0 1-3.46 0"></path>
</svg>
Hyperlocal learning
@@ -114,7 +183,7 @@ export default function CompetitiveEdge() {
</tr>
<tr className="table-row-hover">
<td className="capability-cell">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" style={{ marginRight: "8px", display: "inline-block", verticalAlign: "middle" }}>
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round">
<circle cx="12" cy="12" r="10"></circle>
<line x1="22" y1="12" x2="18" y2="12"></line>
<line x1="6" y1="12" x2="2" y2="12"></line>
@@ -132,20 +201,379 @@ export default function CompetitiveEdge() {
</table>
</div>
{/* Strategic Moat Side cards */}
<div className="moat-panel">
<div className="elementor-element elementor-element-54d05ac elementor-widget elementor-widget-logico_heading" data-id="54d05ac" data-element_type="widget" data-widget_type="logico_heading.default">
<div className="elementor-widget-container">
<div className="section-header">
<span className="section-tag">Competitive Edge</span>
<h3 className="logico-title" style={{ marginTop: "10px", marginBottom: "15px" }}>Where Doormile Sits And Why It Wins</h3>
<p className="section-desc">A side-by-side technical capabilities comparison showing how operational fleet ownership and dynamic AI planning disrupt basic aggregators.</p>
</div>
</div>
</div>
{/* Moat Highlight Card (28% on Desktop) */}
<div className="moat-panel" ref={moatRef}>
<div className="moat-accent-line" />
<div className="advantage-badge">DoorMile Advantage</div>
<h3 className="moat-heading">WHERE DOORMILE SITS AND WHY IT WINS</h3>
<p className="moat-desc">
A side-by-side technical capabilities comparison showing how operational fleet ownership and dynamic AI planning disrupt basic aggregators.
</p>
</div>
</div>
</div>
<style dangerouslySetInnerHTML={{ __html: `
/* --- HIGH-IMPACT PREMIUM CAPABILITIES SECTION STYLE --- */
.comparison-section {
position: relative;
padding: 120px 0;
background-color: #fafafa;
overflow: hidden;
font-family: "Manrope", sans-serif;
}
/* Spotlight radial background glow */
.comparison-bg-glow {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 900px;
height: 900px;
background: radial-gradient(circle, rgba(200, 16, 46, 0.03) 0%, transparent 70%);
z-index: 0;
pointer-events: none;
}
/* Subtle logistics dot grid overlay */
.comparison-bg-dots {
position: absolute;
inset: 0;
background-image: radial-gradient(#e2e4e8 1.5px, transparent 1.5px);
background-size: 32px 32px;
opacity: 0.45;
z-index: 0;
pointer-events: none;
}
.comparison-section .container {
position: relative;
z-index: 2;
max-width: 1400px;
margin: 0 auto;
padding: 0 40px;
}
/* Proportional flex layout scaling */
.comparison-layout {
display: flex;
align-items: stretch;
justify-content: space-between;
gap: 32px;
}
/* Spacious table styling wrapper (69% width) */
.table-wrapper {
flex: 0 0 69%;
max-width: 69%;
background: #ffffff;
border-radius: 24px;
border: 1px solid rgba(0, 0, 0, 0.05);
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.015), 0 1px 3px rgba(0, 0, 0, 0.01);
overflow: hidden;
transition: box-shadow 0.4s cubic-bezier(0.16, 1, 0.3, 1);
}
.table-wrapper:hover {
box-shadow: 0 35px 70px rgba(0, 0, 0, 0.035), 0 1px 3px rgba(0, 0, 0, 0.01);
}
.comparison-table {
width: 100%;
border-collapse: collapse;
text-align: left;
}
/* Enlarge row paddings and metrics size */
.comparison-table th,
.comparison-table td {
padding: 22px 24px;
border-bottom: 1px solid #f0f0f4;
font-size: 0.96rem;
color: #2b2b2b;
transition: all 0.3s cubic-bezier(0.16, 1, 0.3, 1);
}
.comparison-table tr:last-child td {
border-bottom: none;
}
.comparison-table th {
font-family: 'Manrope', sans-serif;
font-weight: 700;
text-transform: uppercase;
font-size: 0.8rem;
letter-spacing: 0.1em;
color: #8a8f9d;
background: rgba(15, 23, 42, 0.02);
}
/* High weight column header highlights */
th.col-highlight {
background: #c8102e !important;
color: #ffffff !important;
text-align: center;
font-weight: 800;
font-size: 0.85rem;
letter-spacing: 0.1em;
border-left: 2.5px solid #c8102e;
border-right: 2.5px solid #c8102e;
box-shadow: 0 4px 20px rgba(200, 16, 46, 0.1);
}
/* High weight cells gradient & highlights */
td.col-highlight {
text-align: center;
color: #c8102e !important;
font-weight: 700;
background: linear-gradient(180deg, rgba(200, 16, 46, 0.02) 0%, rgba(200, 16, 46, 0.005) 100%) !important;
border-left: 2.5px solid rgba(200, 16, 46, 0.12);
border-right: 2.5px solid rgba(200, 16, 46, 0.12);
position: relative;
will-change: transform, box-shadow, background;
animation: doormile-glow-pulse 4s infinite ease-in-out;
}
/* Row Hover Enhancements: brighten row & trigger DoorMile glow expand */
.table-row-hover {
transition: background-color 0.3s ease;
}
.table-row-hover:hover {
background-color: #fafbfd;
}
.table-row-hover:hover td.col-highlight {
background: linear-gradient(180deg, rgba(200, 16, 46, 0.045) 0%, rgba(200, 16, 46, 0.015) 100%) !important;
border-left-color: rgba(200, 16, 46, 0.35);
border-right-color: rgba(200, 16, 46, 0.35);
box-shadow: inset 0 0 16px rgba(200, 16, 46, 0.04);
transform: scale(1.015);
z-index: 10;
}
/* Soft Breathing Box Shadow Red Glow Pulse Loop */
@keyframes doormile-glow-pulse {
0% {
box-shadow: inset 0 0 0 0px rgba(200, 16, 46, 0);
}
50% {
box-shadow: inset 0 0 15px 1.5px rgba(200, 16, 46, 0.045);
}
100% {
box-shadow: inset 0 0 0 0px rgba(200, 16, 46, 0);
}
}
.capability-cell {
display: flex;
align-items: center;
gap: 12px;
font-weight: 700;
color: #111111;
font-size: 1.05rem;
}
.capability-cell svg {
color: #c8102e;
transition: transform 0.35s cubic-bezier(0.16, 1, 0.3, 1);
flex-shrink: 0;
}
.table-row-hover:hover .capability-cell svg {
transform: scale(1.18) rotate(4deg);
}
/* Premium Badge styles */
.yes-badge {
display: inline-flex;
align-items: center;
gap: 6px;
color: #c8102e;
font-weight: 700;
font-size: 0.95rem;
background: rgba(200, 16, 46, 0.05);
padding: 4px 12px;
border-radius: 6px;
border: 1px solid rgba(200, 16, 46, 0.1);
will-change: transform, opacity;
}
.advanced-badge {
display: inline-flex;
align-items: center;
gap: 6px;
background: rgba(200, 16, 46, 0.075);
border: 1.5px solid #c8102e;
padding: 4px 12px;
border-radius: 8px;
font-size: 0.78rem;
text-transform: uppercase;
letter-spacing: 0.06em;
font-weight: 800;
color: #c8102e;
will-change: transform, opacity;
box-shadow: 0 4px 12px rgba(200, 16, 46, 0.06);
}
.no-text {
color: #8e94a5;
font-weight: 500;
}
.partial-text {
color: #4b5262;
font-weight: 500;
}
/* --- RIGHT SIDE ADVANTAGE CARD PANEL (Centered content alignment) --- */
.moat-panel {
flex: 0 0 28%;
max-width: 28%;
background: linear-gradient(135deg, #ffffff 0%, #fbfbfc 100%);
border: 1px solid rgba(0, 0, 0, 0.05);
border-radius: 24px;
padding: 40px 24px;
box-shadow: 0 20px 45px rgba(0, 0, 0, 0.025), inset 0 1px 0 #ffffff;
display: flex;
flex-direction: column;
align-items: center; /* Centers items horizontally */
justify-content: center;
text-align: center; /* Centers all text */
position: relative;
overflow: hidden;
transition: transform 0.4s cubic-bezier(0.16, 1, 0.3, 1), box-shadow 0.4s ease;
will-change: transform;
}
.moat-panel:hover {
transform: translateY(-5px);
box-shadow: 0 35px 70px rgba(0, 0, 0, 0.045);
}
.moat-accent-line {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 5px;
background: #c8102e;
}
/* DoorMile Advantage Badge */
.advantage-badge {
font-family: 'Manrope', sans-serif;
font-weight: 800;
font-size: 0.72rem;
letter-spacing: 0.12em;
text-transform: uppercase;
color: #c8102e;
background: rgba(200, 16, 46, 0.06);
padding: 6px 14px;
border-radius: 30px;
margin: 0 auto 24px auto;
border: 1.5px solid rgba(200, 16, 46, 0.15);
display: inline-block;
white-space: nowrap;
}
/* Centered heading with bottom accent underline instead of left bar */
.moat-heading {
font-family: 'Manrope', sans-serif;
font-size: clamp(1.4rem, 2.3vw, 2.1rem);
font-weight: 800;
line-height: 1.25;
color: #111111;
margin: 0 auto 20px auto;
letter-spacing: -0.025em;
text-transform: uppercase;
word-wrap: break-word;
overflow-wrap: break-word;
display: flex;
flex-direction: column;
align-items: center;
}
/* Centered horizontal red underline accent decoration */
.moat-heading::after {
content: "";
display: block;
width: 48px;
height: 3.5px;
background: #c8102e;
margin-top: 16px;
border-radius: 2px;
}
.moat-desc {
font-family: 'Manrope', sans-serif;
font-size: 0.98rem;
line-height: 1.62;
color: #585c67;
margin: 8px auto 0 auto;
max-width: 340px; /* Bounded width for beautiful block wrapping */
}
/* --- RESPONSIVE WORKFLOWS & BREAKPOINTS --- */
@media (max-width: 1200px) {
.comparison-section .container {
padding: 0 24px;
}
.comparison-layout {
gap: 24px;
}
}
@media (max-width: 1024px) {
.comparison-layout {
flex-direction: column-reverse;
gap: 40px;
}
.table-wrapper,
.moat-panel {
flex: 0 0 100%;
max-width: 100%;
}
.moat-panel {
padding: 48px;
}
.moat-heading {
font-size: 2.2rem;
}
}
@media (max-width: 768px) {
.comparison-section {
padding: 80px 0;
}
/* Capability Matrix table gains responsive horizontal swipe scrolls */
.table-wrapper {
width: 100%;
overflow-x: auto;
-webkit-overflow-scrolling: touch;
}
.comparison-table {
min-width: 720px; /* Forces optimal reading width swipe trail */
}
.comparison-table th,
.comparison-table td {
padding: 16px 18px;
font-size: 0.9rem;
}
.capability-cell {
font-size: 0.98rem;
}
}
`}} />
</section>
);
}

View File

@@ -1,206 +1,535 @@
"use client";
import React, { useState } from "react";
import React, { useState, useEffect, useRef } from "react";
import Image from "next/image";
import gsap from "gsap";
import { ScrollTrigger } from "gsap/ScrollTrigger";
if (typeof window !== "undefined") {
gsap.registerPlugin(ScrollTrigger);
}
const ACCORDION_DATA = [
{
index: 1,
num: "01",
title: "Battery-First Planning",
desc: "Routes are optimized around battery levels and charging windows, not retrofitted as an afterthought."
},
{
index: 2,
num: "02",
title: "Energy-Aware Routing",
desc: "Our algorithms factor in terrain, traffic, and payload weight to maximize range efficiency."
},
{
index: 3,
num: "03",
title: "Smart Charging Integration",
desc: "Seamless coordination with charging infrastructure to eliminate range anxiety for drivers."
},
{
index: 4,
num: "04",
title: "Carbon Footprint Tracking",
desc: "Real-time emissions monitoring and sustainability reports for every delivery."
}
];
export default function EVLogisticSection() {
const [openIndex, setOpenIndex] = useState<number | null>(1);
const [openIndex, setOpenIndex] = useState<number | null>(4); // Default to item 4 open to match user's screenshot layout
const containerRef = useRef<HTMLDivElement>(null);
const imageWrapperRef = useRef<HTMLDivElement>(null);
const imageRef = useRef<HTMLImageElement>(null);
const toggleAccordion = (index: number) => {
setOpenIndex((prev) => (prev === index ? null : index));
};
useEffect(() => {
const container = containerRef.current;
const img = imageRef.current;
const imgWrapper = imageWrapperRef.current;
if (!container || !img || !imgWrapper) return;
// 1. Parent Wrapper Loop: Slow Looping float
const floatAnim = gsap.to(imgWrapper, {
y: "-=10",
duration: 4.5,
ease: "sine.inOut",
yoyo: true,
repeat: -1,
});
// 2. Premium Entrance Animation on Scroll (ScrollTrigger based)
const entryTl = gsap.timeline({
scrollTrigger: {
trigger: container,
start: "top 80%",
toggleActions: "play none none none",
}
});
entryTl
.to(container.querySelector(".ev-logistic-kicker"), {
opacity: 1,
y: 0,
letterSpacing: "3px", // Kinetic letter-spacing track expand effect!
duration: 0.8,
ease: "power3.out",
})
.to(container.querySelectorAll(".ev-char"), {
y: "0%",
opacity: 1,
duration: 0.95,
stagger: 0.02, // Rapid letter-by-letter wave reveal!
ease: "power4.out",
}, "-=0.45")
.to(container.querySelectorAll(".ev-logistic-accordion-item"), {
opacity: 1,
y: 0,
duration: 0.6,
stagger: 0.08,
ease: "power3.out",
}, "-=0.6")
.fromTo(img, {
opacity: 0,
scale: 0.95,
}, {
opacity: 1,
scale: 1,
duration: 1.0,
ease: "power4.out",
}, "-=0.8");
return () => {
floatAnim.kill();
};
}, []);
const headingText = "LOGISTICS BUILT FOR ELECTRIC VEHICLES";
const headingWords = headingText.split(" ");
return (
<div className="elementor-63 miletruth-hero about-us-hero" style={{ position: "relative", zIndex: 1 }}>
<>
<style dangerouslySetInnerHTML={{ __html: `
/* Custom CSS Scoped to EV Logistics Section - New Premium Look */
.ev-logistic-section {
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
max-width: 1320px;
margin: 10px auto 120px auto; /* Centered horizontally with auto margins */
padding: 80px 60px; /* Restored original balanced left/right paddings */
box-sizing: border-box;
background: #ffffff;
font-family: 'Manrope', sans-serif;
gap: 60px;
position: relative;
}
/* ENLARGED Left Column - Image columns takes up 60% for high visual weight */
.ev-logistic-image-col {
flex: 1 1 60%;
max-width: 40%;
display: flex;
align-items: center;
justify-content: flex-start; /* Align left edge */
position: relative;
min-height: 580px;
margin-left: -150px; /* Shifted left towards boundary */
}
/* Branded glow spotlight halo behind the vehicle */
.ev-logistic-image-glow {
position: absolute;
left: 50%;
top: 50%;
width: 80%;
height: 70%;
transform: translate(-50%, -50%);
background: radial-gradient(circle, rgba(192, 18, 39, 0.05) 0%, rgba(192, 18, 39, 0.01) 55%, transparent 75%);
filter: blur(54px);
z-index: 0;
pointer-events: none;
}
/* Increased max-width wrapper so image scales much larger */
.ev-logistic-image-wrapper {
width: 100%;
height: 100%;
max-width: 1000px; /* Enlarged vehicle size */
display: flex;
align-items: center;
justify-content: flex-start;
overflow: visible;
position: relative;
will-change: transform;
transform: scale(1.25);
transform-origin: left center;
}
.ev-logistic-image-wrapper img {
width: 100%;
height: auto;
object-fit: contain;
filter: none; /* Blends solid white JPEG edges seamlessly into pure white background */
will-change: transform;
}
/* Balanced right column - takes up 40% for crisp textual reading */
.ev-logistic-content-col {
flex: 1 1 40%;
max-width: 40%;
display: flex;
flex-direction: column;
justify-content: center;
}
.ev-logistic-kicker {
font-size: 13px;
font-weight: 700;
letter-spacing: 0px; /* Expands to 3px on scroll */
text-transform: lowercase;
color: #888888;
margin-bottom: 20px;
margin-left: 10px; /* Shifted exactly 10px to the right as requested */
opacity: 0;
transform: translateY(-12px);
will-change: transform, opacity, letter-spacing;
}
.ev-logistic-title-wrapper {
margin-bottom: 48px;
}
/* Expanded clean headings look from the screenshot */
.ev-logistic-title {
font-size: clamp(45px, 6.2vw, 96px);
font-weight: 500;
line-height: 0.95;
text-transform: uppercase;
color: #111111;
margin: 0 10px 0 0; /* Clean margin-right to shift title away from borders */
letter-spacing: -1.8px;
}
/* CSS for robust letter-by-letter animation wrapping */
.ev-word-inline {
display: inline-block;
white-space: nowrap; /* Prevents awkward character line breaks */
}
.ev-char-wrapper {
display: inline-block;
overflow: hidden;
vertical-align: top;
}
.ev-char {
display: inline-block;
transform: translateY(110%);
opacity: 0;
will-change: transform, opacity;
}
.ev-char-space {
display: inline-block;
}
.ev-logistic-accordion {
display: flex;
flex-direction: column;
width: 100%;
}
/* Sleek horizontal grid borders */
.ev-logistic-accordion-item {
width: 100%;
border-top: 1px solid #e5e7eb;
opacity: 0;
transform: translateY(20px);
will-change: transform, opacity;
transition: background-color 0.4s cubic-bezier(0.25, 1, 0.5, 1);
}
.ev-logistic-accordion-item:last-child {
border-bottom: 1px solid #e5e7eb;
}
/* Soft highlight on row hover */
.ev-logistic-accordion-item:hover {
background: rgba(192, 18, 39, 0.015);
}
/* Spacious row padding for luxurious design - INCREASED font size for headers */
.ev-logistic-accordion-header {
width: 100%;
display: flex;
justify-content: space-between;
align-items: center;
padding: 28px 16px;
cursor: pointer;
background: transparent;
border: none;
text-align: left;
outline: none;
font-family: 'Manrope', sans-serif;
font-size: clamp(24px, 2.2vw, 30px); /* Increased to clamp up to 30px! */
font-weight: 700;
color: #111111;
transition: color 0.3s ease;
}
.ev-logistic-accordion-header span:first-child {
transition: transform 0.35s cubic-bezier(0.25, 1, 0.5, 1);
display: inline-block;
}
/* Row text horizontal slide nudge */
.ev-logistic-accordion-header:hover {
color: #c01227;
}
.ev-logistic-accordion-header:hover span:first-child {
transform: translateX(10px);
}
.ev-logistic-accordion-item.active .ev-logistic-accordion-header {
color: #111111;
}
.ev-logistic-accordion-arrow-container {
display: inline-flex;
align-items: center;
justify-content: center;
width: 32px;
height: 32px;
transition: transform 0.4s cubic-bezier(0.2, 0.8, 0.2, 1), color 0.3s ease;
}
.ev-logistic-accordion-arrow-container svg {
width: 20px;
height: 20px;
stroke-width: 2.5;
}
/* Inactive arrows: point down-right ↘ */
.ev-logistic-accordion-item:not(.active) .ev-logistic-accordion-arrow-container {
transform: rotate(90deg);
color: #111111;
}
/* Active arrows: point up-right ↗ in brand red */
.ev-logistic-accordion-item.active .ev-logistic-accordion-arrow-container {
transform: rotate(0deg);
color: #c01227;
}
/* Hover: rotate smooth to diagonal up-right */
.ev-logistic-accordion-header:hover .ev-logistic-accordion-arrow-container {
transform: rotate(0deg);
color: #c01227;
}
.ev-logistic-accordion-content {
overflow: hidden;
max-height: 0;
opacity: 0;
transition: max-height 0.45s cubic-bezier(0.25, 1, 0.5, 1), opacity 0.45s ease;
}
.ev-logistic-accordion-item.active .ev-logistic-accordion-content {
max-height: 160px;
opacity: 1;
}
/* Balanced text spacing inside descriptions - INCREASED font size for descriptions */
.ev-logistic-accordion-content-inner {
padding: 0 16px 28px 16px;
font-size: clamp(18px, 1.5vw, 20px); /* Increased to clamp up to 20px! */
line-height: 1.6;
color: #555555;
font-weight: 500;
}
/* Underline track & sweeping active red bar */
.ev-logistic-accordion-progress-track {
position: relative;
width: 100%;
height: 1.5px;
background: transparent;
margin-top: -1.5px;
overflow: hidden;
}
.ev-logistic-accordion-progress-bar {
position: absolute;
left: 0;
top: 0;
height: 100%;
width: 100%;
background: #c01227;
transform: scaleX(0);
transform-origin: left center;
transition: transform 0.6s cubic-bezier(0.25, 1, 0.5, 1);
will-change: transform;
}
.ev-logistic-accordion-item.active .ev-logistic-accordion-progress-bar {
transform: scaleX(1);
}
/* Responsiveness constraints */
@media (max-width: 1024px) {
.ev-logistic-section {
flex-direction: column;
padding: 60px 24px;
gap: 50px;
margin-bottom: 60px;
}
.ev-logistic-image-col {
flex: 1 1 100%;
max-width: 100%;
min-height: auto;
margin-left: 0; /* Reset margins on mobile */
justify-content: center; /* Center layout on mobile */
}
.ev-logistic-image-wrapper {
max-width: 580px;
transform: none; /* Reset scaling on mobile */
}
.ev-logistic-content-col {
flex: 1 1 100%;
max-width: 100%;
}
.ev-logistic-title {
font-size: 38px;
}
}
@media (max-width: 768px) {
.ev-logistic-section {
padding: 40px 16px;
gap: 40px;
}
.ev-logistic-image-wrapper {
max-width: 100%;
}
.ev-logistic-title {
font-size: 32px;
}
.ev-logistic-accordion-header {
font-size: 19px;
padding: 22px 8px;
}
.ev-logistic-accordion-content-inner {
padding: 0;
font-size: 15.5px;
}
}
`}} />
<div
style={{ marginBottom: "180px" }}
className="elementor-element ev-log elementor-element-ead59d3 e-con-full e-flex cut-corner-no sticky-container-off e-con e-parent"
data-id="ead59d3"
data-element_type="container"
data-e-type="container"
ref={containerRef}
className="ev-logistic-section"
>
<div
className="elementor-element elementor-element-f35119c elementor-widget__width-initial elementor-absolute elementor-widget elementor-widget-image"
data-id="f35119c"
data-element_type="widget"
data-e-type="widget"
style={{ position: "absolute" }}
>
<div className="elementor-widget-container">
{/* Left Column: Enlarged Floating Wrapper & Ambient glow */}
<div className="ev-logistic-image-col">
<div className="ev-logistic-image-glow"></div>
<div ref={imageWrapperRef} className="ev-logistic-image-wrapper">
<Image
ref={imageRef as any}
src="/images/ev.jpeg"
alt="EV Logistics"
width={1050}
height={854}
style={{ width: "100%", height: "auto" }}
priority
/>
</div>
</div>
<div
className="elementor-element elementor-element-56ecbb3 e-flex e-con-boxed cut-corner-no sticky-container-off e-con e-child"
data-id="56ecbb3"
data-element_type="container"
data-e-type="container"
>
<div className="e-con-inner">
<div
className="elementor-element elementor-element-47f8cbe e-con-full e-flex cut-corner-no sticky-container-off e-con e-child"
data-id="47f8cbe"
data-element_type="container"
data-e-type="container"
>
{/* Right Column: Refined Accordion list with letter-by-letter animation */}
<div className="ev-logistic-content-col">
{/* Animated features kicker */}
<div className="ev-logistic-kicker">/ features /</div>
{/* Character-by-character masked entrance wave reveal on scroll */}
<div className="ev-logistic-title-wrapper">
<h3 className="ev-logistic-title">
{headingWords.map((word, wordIndex) => (
<span key={wordIndex} className="ev-word-inline">
{word.split("").map((letter, letterIndex) => (
<span key={letterIndex} className="ev-char-wrapper">
<span className="ev-char">{letter}</span>
</span>
))}
<span className="ev-char-space">&nbsp;</span>
</span>
))}
</h3>
</div>
<div className="ev-logistic-accordion">
{ACCORDION_DATA.map((item) => (
<div
className="elementor-element elementor-element-cd6daaf elementor-widget elementor-widget-logico_heading"
data-id="cd6daaf"
data-element_type="widget"
data-e-type="widget"
key={item.index}
className={`ev-logistic-accordion-item ${openIndex === item.index ? "active" : ""}`}
>
<div className="elementor-widget-container">
<div className="logico-title">/ features /</div>
</div>
</div>
<div
className="elementor-element elementor-element-1b3f232 elementor-widget__width-initial elementor-widget elementor-widget-logico_heading"
data-id="1b3f232"
data-element_type="widget"
data-e-type="widget"
>
<div className="elementor-widget-container">
<h3 className="logico-title">Logistics Built for Electric Vehicles</h3>
</div>
</div>
<div
className="elementor-element elementor-element-9b7e9c9 elementor-widget__width-initial elementor-widget elementor-widget-accordion"
data-id="9b7e9c9"
data-element_type="widget"
data-e-type="widget"
>
<div className="elementor-widget-container">
<div className="elementor-accordion">
{/* Accordion 1 */}
<div className="elementor-accordion-item">
<div
className={`elementor-tab-title ${openIndex === 1 ? "elementor-active" : ""}`}
role="button"
aria-expanded={openIndex === 1}
onClick={() => toggleAccordion(1)}
style={{ cursor: "pointer" }}
>
<span className="elementor-accordion-icon elementor-accordion-icon-right" aria-hidden="true">
<span className="elementor-accordion-icon-closed" style={{ display: openIndex === 1 ? "none" : "inline" }}>
<i className="fontello icon-arrow-x-r-down"></i>
</span>
<span className="elementor-accordion-icon-opened" style={{ display: openIndex === 1 ? "inline" : "none" }}>
<i className="fontello icon-arrow-x-r-top"></i>
</span>
</span>
<span className="elementor-accordion-title">01. Battery-First Planning</span>
</div>
<div
className="elementor-tab-content elementor-clearfix"
role="region"
style={{ display: openIndex === 1 ? "block" : "none" }}
>
<p>Routes are optimized around battery levels and charging windows, not retrofitted as an afterthought.</p>
</div>
</div>
{/* Accordion 2 */}
<div className="elementor-accordion-item">
<div
className={`elementor-tab-title ${openIndex === 2 ? "elementor-active" : ""}`}
role="button"
aria-expanded={openIndex === 2}
onClick={() => toggleAccordion(2)}
style={{ cursor: "pointer" }}
>
<span className="elementor-accordion-icon elementor-accordion-icon-right" aria-hidden="true">
<span className="elementor-accordion-icon-closed" style={{ display: openIndex === 2 ? "none" : "inline" }}>
<i className="fontello icon-arrow-x-r-down"></i>
</span>
<span className="elementor-accordion-icon-opened" style={{ display: openIndex === 2 ? "inline" : "none" }}>
<i className="fontello icon-arrow-x-r-top"></i>
</span>
</span>
<span className="elementor-accordion-title">02. Energy-Aware Routing</span>
</div>
<div
className="elementor-tab-content elementor-clearfix"
role="region"
style={{ display: openIndex === 2 ? "block" : "none" }}
>
<p>Our algorithms factor in terrain, traffic, and payload weight to maximize range efficiency.</p>
</div>
</div>
{/* Accordion 3 */}
<div className="elementor-accordion-item">
<div
className={`elementor-tab-title ${openIndex === 3 ? "elementor-active" : ""}`}
role="button"
aria-expanded={openIndex === 3}
onClick={() => toggleAccordion(3)}
style={{ cursor: "pointer" }}
>
<span className="elementor-accordion-icon elementor-accordion-icon-right" aria-hidden="true">
<span className="elementor-accordion-icon-closed" style={{ display: openIndex === 3 ? "none" : "inline" }}>
<i className="fontello icon-arrow-x-r-down"></i>
</span>
<span className="elementor-accordion-icon-opened" style={{ display: openIndex === 3 ? "inline" : "none" }}>
<i className="fontello icon-arrow-x-r-top"></i>
</span>
</span>
<span className="elementor-accordion-title">03. Smart Charging Integration</span>
</div>
<div
className="elementor-tab-content elementor-clearfix"
role="region"
style={{ display: openIndex === 3 ? "block" : "none" }}
>
<p>Seamless coordination with charging infrastructure to eliminate range anxiety for drivers.</p>
</div>
</div>
{/* Accordion 4 */}
<div className="elementor-accordion-item">
<div
className={`elementor-tab-title ${openIndex === 4 ? "elementor-active" : ""}`}
role="button"
aria-expanded={openIndex === 4}
onClick={() => toggleAccordion(4)}
style={{ cursor: "pointer" }}
>
<span className="elementor-accordion-icon elementor-accordion-icon-right" aria-hidden="true">
<span className="elementor-accordion-icon-closed" style={{ display: openIndex === 4 ? "none" : "inline" }}>
<i className="fontello icon-arrow-x-r-down"></i>
</span>
<span className="elementor-accordion-icon-opened" style={{ display: openIndex === 4 ? "inline" : "none" }}>
<i className="fontello icon-arrow-x-r-top"></i>
</span>
</span>
<span className="elementor-accordion-title">04. Carbon Footprint Tracking</span>
</div>
<div
className="elementor-tab-content elementor-clearfix"
role="region"
style={{ display: openIndex === 4 ? "block" : "none" }}
>
<p>Real-time emissions monitoring and sustainability reports for every delivery.</p>
</div>
</div>
<button
className="ev-logistic-accordion-header"
onClick={() => toggleAccordion(item.index)}
aria-expanded={openIndex === item.index}
>
<span>{item.num}. {item.title}</span>
<span className="ev-logistic-accordion-arrow-container">
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
>
<line x1="7" y1="17" x2="17" y2="7"></line>
<polyline points="7 7 17 7 17 17"></polyline>
</svg>
</span>
</button>
<div className="ev-logistic-accordion-content">
<div className="ev-logistic-accordion-content-inner">
{/* Kinetic slide-up and fade subtitle reveal */}
<p style={{
transform: openIndex === item.index ? "translateY(0)" : "translateY(12px)",
opacity: openIndex === item.index ? 1 : 0,
transition: "transform 0.5s cubic-bezier(0.25, 1, 0.5, 1), opacity 0.5s ease",
transitionDelay: "0.08s",
margin: 0
}}>
{item.desc}
</p>
</div>
</div>
</div>
</div>
{/* Underline track & sweep animated red bar */}
<div className="ev-logistic-accordion-progress-track">
<div className="ev-logistic-accordion-progress-bar"></div>
</div>
</div>
))}
</div>
</div>
</div>
</div>
</>
);
}

View File

@@ -0,0 +1,138 @@
"use client";
import React, { useEffect, useRef } from "react";
/**
* EV-Native Design background — drifting SQUARE particles with 3D depth.
* Each square has a depth (0.31): nearer squares are larger, brighter, and
* parallax further on mouse-move + a slow auto-sway, creating a layered 3D
* field. Mix of brand-red (#dc2626) and soft gray/white squares. Full section,
* pointer-events:none, behind content.
*/
export default function EVParticles() {
const canvasRef = useRef<HTMLCanvasElement>(null);
useEffect(() => {
const canvas = canvasRef.current;
const parent = canvas?.parentElement;
if (!canvas || !parent) return;
const ctx = canvas.getContext("2d");
if (!ctx) return;
const reduced = window.matchMedia?.("(prefers-reduced-motion: reduce)").matches;
const COUNT = 120;
type P = { x: number; y: number; vx: number; vy: number; s: number; red: boolean; a: number; d: number };
let particles: P[] = [];
let w = 0, h = 0, raf = 0, startTs = 0;
// mouse parallax (canvas is pointer-events:none, so track on window)
const mouse = { x: 0, y: 0 };
const cur = { x: 0, y: 0 };
const onMove = (e: MouseEvent) => {
mouse.x = (e.clientX / window.innerWidth) * 2 - 1;
mouse.y = (e.clientY / window.innerHeight) * 2 - 1;
};
const init = () => {
particles = [];
for (let i = 0; i < COUNT; i++) {
const t = Math.random();
const s = t > 0.92 ? 12 + Math.random() * 6 : t > 0.68 ? 7 + Math.random() * 5 : 3 + Math.random() * 4;
const red = Math.random() < 0.3;
particles.push({
x: Math.random() * w,
y: Math.random() * h,
vx: (Math.random() - 0.5) * 0.22,
vy: (Math.random() - 0.5) * 0.22,
s,
red,
a: red ? Math.random() * 0.4 + 0.35 : Math.random() * 0.28 + 0.12,
d: Math.random() * 0.7 + 0.3, // depth 0.3 (far) .. 1 (near)
});
}
};
const resize = () => {
const rect = parent.getBoundingClientRect();
w = Math.max(1, rect.width);
h = Math.max(1, rect.height);
const dpr = Math.min(window.devicePixelRatio || 1, 2);
canvas.width = Math.round(w * dpr);
canvas.height = Math.round(h * dpr);
canvas.style.width = w + "px";
canvas.style.height = h + "px";
ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
if (!particles.length) init();
};
const render = (time: number, move: boolean) => {
ctx.clearRect(0, 0, w, h);
// ease the parallax origin toward the pointer
cur.x += (mouse.x - cur.x) * 0.04;
cur.y += (mouse.y - cur.y) * 0.04;
// slow auto-sway so the 3D depth animates even without mouse input
const swayX = Math.sin(time * 0.00026) * 0.6;
const swayY = Math.cos(time * 0.0002) * 0.45;
const ox = (cur.x + swayX) * 34;
const oy = (cur.y + swayY) * 26;
for (const p of particles) {
if (move) {
p.x += p.vx * p.d;
p.y += p.vy * p.d;
const m = p.s + 6;
if (p.x < -m) p.x = w + m;
else if (p.x > w + m) p.x = -m;
if (p.y < -m) p.y = h + m;
else if (p.y > h + m) p.y = -m;
}
// depth-scaled size + parallax offset (near squares move/scale more)
const size = p.s * (0.55 + p.d * 0.75);
const dx = p.x + ox * p.d;
const dy = p.y + oy * p.d;
const alpha = p.a * (0.55 + p.d * 0.45);
if (p.red) {
ctx.shadowColor = "rgba(220,38,38,0.55)";
ctx.shadowBlur = 8 * p.d;
ctx.fillStyle = `rgba(220,38,38,${alpha})`;
} else {
ctx.shadowBlur = 0;
ctx.fillStyle = `rgba(200,202,210,${alpha})`;
}
ctx.fillRect(dx - size / 2, dy - size / 2, size, size);
}
ctx.shadowBlur = 0;
};
const loop = (ts: number) => {
if (!startTs) startTs = ts;
render(ts - startTs, true);
raf = requestAnimationFrame(loop);
};
resize();
init();
if (reduced) {
render(0, false);
} else {
window.addEventListener("mousemove", onMove, { passive: true });
raf = requestAnimationFrame(loop);
}
const ro = new ResizeObserver(() => {
resize();
if (reduced) render(0, false);
});
ro.observe(parent);
return () => {
cancelAnimationFrame(raf);
ro.disconnect();
window.removeEventListener("mousemove", onMove);
};
}, []);
return <canvas ref={canvasRef} className="evnd__canvas" aria-hidden="true" />;
}

View File

@@ -1,46 +1,122 @@
"use client";
import React, { useEffect, useRef } from "react";
import Link from "next/link";
import { ScrollReveal, SlideReveal } from "@/animations/Reveal";
import React, { useEffect, useRef, useState } from "react";
import dynamic from "next/dynamic";
import gsap from "gsap";
import { ScrollTrigger } from "gsap/ScrollTrigger";
// Drifting particle background — client-only, mounted behind the section.
const EVParticles = dynamic(() => import("./EVParticles"), { ssr: false });
if (typeof window !== "undefined") {
gsap.registerPlugin(ScrollTrigger);
}
const PILLS: { value: string; label: string }[] = [
{ value: "100%", label: "Electric Fleet" },
{ value: "Live", label: "Route Sync" },
{ value: "Real-time", label: "Battery Monitoring" },
];
const MINI_STATS: { value: number; decimals?: number; suffix: string; label: string }[] = [
{ value: 94, suffix: "K+", label: "Routes Optimised" },
{ value: 23, suffix: "%", label: "Avg Battery Saved" },
{ value: 1.4, decimals: 1, suffix: "x", label: "Charging Stops Saved" },
];
const FEATURES: { icon: string; title: string; desc: string }[] = [
{
icon: "⚡",
title: "Battery-Aware Routing",
desc: "Battery level, health, and degradation are first-class inputs to route optimization — not afterthoughts.",
},
{
icon: "🔌",
title: "Charging Integration",
desc: "Seamlessly integrate charging stops without compromising delivery windows or SLA commitments.",
},
{
icon: "⛰",
title: "Energy-Optimized Paths",
desc: "Factor in elevation, speed limits, payload weight, and live weather for maximum range efficiency.",
},
{
icon: "🛡",
title: "Predictable Operations",
desc: "EVs become predictable assets, not operational risks. Full visibility from depot to doorstep.",
},
];
const BOTTOM_STATS: { value: number; decimals?: number; suffix: string; label: string }[] = [
{ value: 120, suffix: "K+", label: "Deliveries Completed" },
{ value: 98, suffix: "%", label: "On-Time Rate" },
{ value: 31, suffix: "%", label: "Range Efficiency Gain" },
{ value: 340, suffix: "ms", label: "Avg Route Calc Time" },
];
/** Count-up that fires once when scrolled ~20% into view (ease-out cubic). */
function CountUp({
value,
decimals = 0,
suffix = "",
duration = 1700,
className,
}: {
value: number;
decimals?: number;
suffix?: string;
duration?: number;
className?: string;
}) {
const [n, setN] = useState(0);
const ref = useRef<HTMLElement>(null);
const done = useRef(false);
useEffect(() => {
const el = ref.current;
if (!el) return;
const reduced = window.matchMedia?.("(prefers-reduced-motion: reduce)").matches;
if (reduced) {
setN(value);
return;
}
const io = new IntersectionObserver(
(entries) => {
for (const e of entries) {
if (e.isIntersecting && !done.current) {
done.current = true;
const start = performance.now();
const ease = (t: number) => 1 - Math.pow(1 - t, 3);
const tick = (now: number) => {
const p = Math.min(1, (now - start) / duration);
setN(value * ease(p));
if (p < 1) requestAnimationFrame(tick);
else setN(value);
};
requestAnimationFrame(tick);
io.disconnect();
}
}
},
{ threshold: 0.2 }
);
io.observe(el);
return () => io.disconnect();
}, [value, duration]);
return (
<b ref={ref as React.RefObject<HTMLElement>} className={className}>
{n.toFixed(decimals)}
{suffix}
</b>
);
}
export default function EVSection() {
const headingContainerRef = useRef<HTMLDivElement>(null);
const bannerRef = useRef<HTMLDivElement>(null);
useEffect(() => {
// 1. Heading Scroll-Triggered Animation (Up & Down, Replay)
const headingEl = headingContainerRef.current;
if (headingEl) {
const trigger = ScrollTrigger.create({
trigger: headingEl,
start: "top 88%",
onEnter: () => {
headingEl.classList.add("animated");
},
onEnterBack: () => {
headingEl.classList.add("animated");
},
onLeave: () => {
headingEl.classList.remove("animated");
},
onLeaveBack: () => {
headingEl.classList.remove("animated");
},
});
return () => trigger?.kill();
}
}, []);
useEffect(() => {
// 2. Banner Native Background Parallax (GSAP ScrollTrigger)
// Banner Scroll-Triggered Parallax (Replicating background_image_parallax from theme.js exactly)
const banner = bannerRef.current;
if (!banner) return;
@@ -49,86 +125,279 @@ export default function EVSection() {
start: "top bottom",
end: "bottom top",
scrub: true,
onUpdate: (self) => {
// Subtle background offset to create beautiful native parallax depth
const yOffset = self.progress * 120;
gsap.set(banner, {
backgroundPosition: `center ${yOffset}px`,
});
onUpdate: () => {
if (window.innerWidth >= 1021) {
const scrollTop = window.scrollY;
const rect = banner.getBoundingClientRect();
const offsetTop = rect.top + scrollTop;
const from_top = scrollTop - offsetTop;
const yOffset = 0.3 * from_top;
gsap.set(banner, { backgroundPosition: `center ${yOffset}px` });
} else {
gsap.set(banner, { backgroundPosition: "" });
}
},
});
return () => parallaxTrigger?.kill();
}, []);
const renderAnimatedText = () => {
const lines = [
{ text: "Built for Electric.", highlight: true },
{ text: "Not Adapted.", highlight: false }
];
let letterCount = 0;
return lines.map((line, lineIdx) => {
const words = line.text.split(/\s+/);
return (
<div key={lineIdx} style={{ display: "block" }}>
{words.map((word, wordIdx) => {
const letters = word.split("");
return (
<span key={wordIdx} className="word" style={{ display: "inline-block", marginRight: "0.2em", whiteSpace: "nowrap" }}>
{letters.map((letter, letterIdx) => {
const delay = `${letterCount / 50}s`;
letterCount++;
return (
<span
key={letterIdx}
className="letter"
style={{
animationDelay: delay,
["--delay" as any]: delay,
}}
>
{letter}
</span>
);
})}
{/* Non-breaking space */}
&nbsp;
</span>
);
})}
</div>
);
});
};
return (
<>
<style dangerouslySetInnerHTML={{ __html: `
.logico-title .word {
display: inline-block;
white-space: nowrap;
margin-right: 0.15em;
}
.letter {
display: inline-block;
}
/* ============================================================
EV-Native Design — redesigned section
bg #0d0d0d · red #dc2626 / #ef4444 · Syne + DM Sans
============================================================ */
/* Native, scroll-triggered heading reveal matching WordPress/Elementor */
.logico_heading_animation .word .letter {
opacity: 0 !important;
transform: translateY(120%) !important;
animation: none !important;
#evnd, #evnd * { font-family: "Manrope", Sans-serif !important; }
.evnd {
position: relative;
isolation: isolate;
overflow: hidden;
background: #0d0d0d;
/* flat top so it connects seamlessly to the banner above; rounded
bottom only, and no top margin so there is no white gap */
border-radius: 0 0 clamp(16px, 2vw, 28px) clamp(16px, 2vw, 28px);
margin: 0 0 clamp(28px, 5vw, 64px);
padding: 56px 48px 64px;
}
.logico_heading_animation.animated .word .letter {
opacity: 0 !important;
transform: translateY(120%) !important;
animation: fadeIn 0.35s forwards, logico_heading_animation 0.7s cubic-bezier(.26, -.14, 0, 1.01) forwards !important;
/* subtle diagonal light band for depth (matches reference) */
.evnd::before {
content: '';
position: absolute;
inset: 0;
z-index: 0;
pointer-events: none;
background: linear-gradient(120deg, transparent 28%, rgba(255,255,255,0.025) 50%, transparent 72%);
}
.evnd__canvas {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
z-index: 0;
pointer-events: none;
}
.evnd__inner { position: relative; z-index: 1; max-width: 1280px; margin: 0 auto; }
/* ---- TOP ROW ---- */
.evnd__top {
display: grid;
grid-template-columns: 1.5fr 1fr;
gap: 44px;
align-items: center;
margin-bottom: 48px;
}
.evnd__eyebrow {
display: inline-flex;
align-items: center;
gap: 12px;
color: #dc2626 !important;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.16em;
font-size: 13px;
margin-bottom: 16px;
}
.evnd__eyebrow::before { content: ''; width: 24px; height: 2px; background: #dc2626; }
.evnd__title {
color: #fff !important;
font-weight: 800 !important;
font-size: clamp(30px, 4.4vw, 56px) !important;
line-height: 1.04 !important;
letter-spacing: -0.01em;
margin: 0;
}
.evnd__title .accent { color: #ef4444 !important; }
.evnd__pills { display: flex; flex-direction: column; gap: 12px; }
.evnd__pill {
display: flex;
align-items: center;
gap: 12px;
padding: 13px 20px;
background: rgba(255,255,255,0.04);
border: 1px solid rgba(255,255,255,0.08);
border-radius: 100px;
}
.evnd__pill .dot {
flex: 0 0 auto;
width: 8px; height: 8px;
border-radius: 50%;
background: #22c55e;
box-shadow: 0 0 8px #22c55e;
animation: evndBlink 1.4s ease-in-out infinite;
}
.evnd__pill b { color: #ef4444 !important; font-weight: 800; font-size: 15px; }
.evnd__pill span { color: rgba(255,255,255,0.62) !important; font-size: 13px; }
/* ---- MAIN GRID ---- */
.evnd__grid { display: grid; grid-template-columns: 1fr 1fr; gap: 40px; align-items: start; }
.evnd__media { position: relative; }
.evnd__glow {
position: absolute;
left: 50%; bottom: -4%;
width: 72%; height: 64px;
transform: translateX(-50%);
background: radial-gradient(50% 50% at 50% 50%, rgba(220,38,38,0.5), transparent 72%);
filter: blur(30px);
z-index: 0;
animation: evndGlow 4s ease-in-out infinite;
}
.evnd__imgwrap { position: relative; z-index: 1; animation: evndFloat 7s ease-in-out infinite; will-change: transform; }
.evnd__img {
display: block;
width: 100%;
height: auto;
border-radius: 14px;
box-shadow: 0 30px 60px -25px rgba(0,0,0,0.7);
}
.evnd__badge {
position: absolute;
z-index: 2;
display: flex;
flex-direction: column;
gap: 2px;
padding: 10px 14px;
background: rgba(10,10,10,0.88);
border: 1px solid rgba(255,255,255,0.1);
border-radius: 8px;
}
.evnd__badge b { color: #ef4444 !important; font-weight: 800; font-size: 24px; line-height: 1; }
.evnd__badge span { color: rgba(255,255,255,0.55) !important; font-size: 10px; letter-spacing: 0.08em; text-transform: uppercase; }
.evnd__badge--tl { top: 14px; left: 14px; }
.evnd__badge--br { bottom: 14px; right: 14px; }
.evnd__ministats { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; margin-top: 20px; }
.evnd__mini {
position: relative;
background: rgba(255,255,255,0.03);
border: 1px solid rgba(255,255,255,0.06);
border-radius: 10px;
padding: 18px 14px 14px;
overflow: hidden;
}
.evnd__mini::before {
content: '';
position: absolute; top: 0; left: 0; right: 0;
height: 2px;
background: linear-gradient(90deg, #dc2626, transparent);
}
.evnd__mini b { display: block; color: #fff !important; font-weight: 800; font-size: clamp(20px, 2.3vw, 28px); line-height: 1; margin-bottom: 6px; }
.evnd__mini span { color: rgba(255,255,255,0.5) !important; font-size: 11px; letter-spacing: 0.04em; text-transform: uppercase; line-height: 1.3; display: block; }
/* ---- Feature cards ---- */
.evnd__features { display: flex; flex-direction: column; gap: 10px; }
.evnd-feature {
position: relative;
display: grid;
grid-template-columns: 40px 1fr auto;
gap: 16px;
align-items: start;
background: rgba(255,255,255,0.028);
border: 1px solid rgba(255,255,255,0.07);
border-radius: 12px;
padding: 18px 20px;
overflow: hidden;
transition: background-color 0.35s ease, border-color 0.35s ease, transform 0.35s cubic-bezier(.25,1,.5,1);
}
.evnd-feature::before {
content: '';
position: absolute;
left: 0; top: 0; bottom: 0;
width: 3px;
background: #dc2626;
transform: scaleY(0);
transform-origin: bottom;
transition: transform 0.35s ease;
}
.evnd-feature:hover { background: rgba(220,38,38,0.06); border-color: rgba(220,38,38,0.25); transform: translateX(4px); }
.evnd-feature:hover::before { transform: scaleY(1); }
.evnd-feature__icon {
width: 40px; height: 40px;
display: flex; align-items: center; justify-content: center;
background: rgba(220,38,38,0.1);
border: 1px solid rgba(220,38,38,0.2);
border-radius: 10px;
font-size: 18px;
}
.evnd-feature__title {
color: #fff !important;
font-weight: 700;
font-size: 15px !important;
text-transform: uppercase;
letter-spacing: 0.04em;
margin: 3px 0 7px;
transition: color 0.3s ease;
}
.evnd-feature:hover .evnd-feature__title { color: #ef4444 !important; }
.evnd-feature__desc {
color: rgba(255,255,255,0.75) !important;
font-weight: 400 !important;
font-size: 14.5px !important;
line-height: 1.65 !important;
margin: 0;
}
.evnd-feature__arrow {
color: rgba(255,255,255,0.2);
font-size: 14px;
align-self: flex-start;
transition: color 0.3s ease, transform 0.3s ease;
}
.evnd-feature:hover .evnd-feature__arrow { color: #ef4444; transform: translate(3px, -3px); }
/* ---- BOTTOM BAR ---- */
.evnd__bar {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 1px;
background: rgba(255,255,255,0.06);
border-radius: 12px;
overflow: hidden;
margin-top: 40px;
}
.evnd__bar-item {
background: #0d0d0d;
padding: 24px 22px;
display: flex;
flex-direction: column;
gap: 8px;
align-items: flex-start;
}
.evnd__bar-item .dot {
width: 7px; height: 7px;
border-radius: 50%;
background: #dc2626;
box-shadow: 0 0 8px rgba(220,38,38,0.85);
animation: evndBlink 1.4s ease-in-out infinite;
}
.evnd__bar-item b { color: #fff !important; font-weight: 800; font-size: clamp(22px, 2.6vw, 30px); line-height: 1; }
.evnd__bar-item span { color: rgba(255,255,255,0.45) !important; font-size: 11px; letter-spacing: 0.06em; text-transform: uppercase; }
@keyframes evndFloat { 0%,100% { transform: translateY(0); } 50% { transform: translateY(-7px); } }
@keyframes evndGlow { 0%,100% { opacity: 0.6; } 50% { opacity: 1; } }
@keyframes evndBlink { 0%,100% { opacity: 1; } 50% { opacity: 0.3; } }
/* ---- Responsive ---- */
@media (max-width: 900px) {
.evnd { padding: 48px 28px 52px; }
.evnd__top { grid-template-columns: 1fr; gap: 28px; margin-bottom: 36px; }
.evnd__grid { grid-template-columns: 1fr; gap: 36px; }
}
@media (max-width: 600px) {
.evnd { padding: 40px 18px 44px; }
.evnd__bar { grid-template-columns: repeat(2, 1fr); }
.evnd__pill { padding: 11px 16px; }
}
@media (prefers-reduced-motion: reduce) {
.evnd__imgwrap, .evnd__glow, .evnd__pill .dot, .evnd__bar-item .dot { animation: none !important; }
}
`}} />
<div className="elementor-element elementor-element-bbc6760 e-con-full e-flex cut-corner-no sticky-container-off e-con e-parent" data-id="bbc6760" data-element_type="container" data-e-type="container">
<div className="elementor-element elementor-element-bbc6760 e-con-full e-flex cut-corner-no sticky-container-off e-con e-parent" data-id="bbc6760" data-element_type="container" data-e-type="container" style={{ backgroundColor: "#0d0d0d", width: "calc(100% - 40px)", marginLeft: "20px", marginRight: "20px", borderRadius: "25px", overflow: "hidden" }}>
{/* Background Banner with Native GSAP Background Scroll Parallax */}
<div
@@ -140,9 +409,13 @@ export default function EVSection() {
data-settings="{&quot;background_background&quot;:&quot;classic&quot;}"
style={{
backgroundPosition: "center 0px",
backgroundImage: "url(/images/home4-banner-4.png)",
backgroundImage: "url(/images/bg-header-5.png)",
backgroundSize: "cover",
backgroundRepeat: "no-repeat"
backgroundRepeat: "no-repeat",
position: "relative",
zIndex: 2,
borderRadius: "25px 25px 0 0",
overflow: "hidden"
}}
></div>
@@ -169,164 +442,89 @@ export default function EVSection() {
</div>
</div>
<div className="elementor-element elementor-element-b6e14bd e-flex e-con-boxed cut-corner-no sticky-container-off e-con e-child" data-id="b6e14bd" data-element_type="container" data-e-type="container" data-settings="{&quot;background_background&quot;:&quot;classic&quot;}">
<div className="e-con-inner">
<div className="elementor-element elementor-element-90cc867 e-con-full e-flex cut-corner-no sticky-container-off e-con e-child" data-id="90cc867" data-element_type="container" data-e-type="container">
{/* ===== EV-Native Design (redesigned) ===== */}
<section className="evnd" id="evnd" aria-label="EV-Native Design">
<div className="evnd__canvas-wrap" style={{ position: "absolute", inset: 0, zIndex: 0, pointerEvents: "none" }}>
<EVParticles />
</div>
<ScrollReveal delay={0.05} duration={0.7} yOffset={20}>
<div className="elementor-element elementor-element-24c0280 elementor-widget__width-inherit elementor-widget elementor-widget-logico_heading" data-id="24c0280" data-element_type="widget" data-e-type="widget" data-widget_type="logico_heading.default">
<div className="elementor-widget-container">
<div className="logico-title">/ EV-Native Design /</div>
</div>
<div className="evnd__inner">
{/* TOP ROW */}
<div className="evnd__top">
<div className="evnd__head">
<span className="evnd__eyebrow">/ EV-Native Design /</span>
<div className="evnd__title">
BUILT FOR ELECTRIC. <span className="accent">NOT ADAPTED.</span>
</div>
</ScrollReveal>
<div className="elementor-element elementor-element-2ed47f3 e-con-full e-grid cut-corner-no sticky-container-off e-con e-child" data-id="2ed47f3" data-element_type="container" data-e-type="container">
<div className="elementor-element elementor-element-36efec7 e-con-full e-flex cut-corner-no sticky-container-off e-con e-child" data-id="36efec7" data-element_type="container" data-e-type="container">
<div ref={headingContainerRef} className="elementor-element elementor-element-778840d elementor-widget elementor-widget-logico_heading logico_heading_animation" data-id="778840d" data-element_type="widget" data-e-type="widget" data-widget_type="logico_heading.default">
<div className="elementor-widget-container">
<h3 className="logico-title" data-animate="true">
{renderAnimatedText()}
</h3>
</div>
</div>
<div className="evnd__pills">
{PILLS.map((p) => (
<div className="evnd__pill" key={p.label}>
<span className="dot" />
<b>{p.value}</b>
<span>{p.label}</span>
</div>
<div className="elementor-element elementor-element-bbfb67f elementor-widget elementor-widget-image" data-id="bbfb67f" data-element_type="widget" data-e-type="widget" data-widget_type="image.default">
<div className="elementor-widget-container">
<img decoding="async" width="626" height="692" src="/images/home4-pic-1.png" className="attachment-full size-full wp-image-6789" alt="EV Truck" style={{ objectFit: "cover", width: "100%", height: "auto" }} />
))}
</div>
</div>
{/* MAIN GRID */}
<div className="evnd__grid">
{/* Left column */}
<div className="evnd__left">
<div className="evnd__media">
<div className="evnd__glow" />
<div className="evnd__imgwrap">
{/* eslint-disable-next-line @next/next/no-img-element */}
<img className="evnd__img" src="/images/premium-ev-van.png" alt="DoorMile electric delivery van" decoding="async" />
<div className="evnd__badge evnd__badge--tl">
<b>100%</b>
<span>Electric Fleet</span>
</div>
<div className="evnd__badge evnd__badge--br">
<b>&minus;40%</b>
<span>Cost / Mile</span>
</div>
</div>
</div>
<SlideReveal direction="right" delay={0.15} duration={0.9}>
<div className="elementor-element elementor-element-b2c956f e-con-full e-flex cut-corner-no sticky-container-off e-con e-child" data-id="b2c956f" data-element_type="container" data-e-type="container">
<div className="elementor-element elementor-element-1a450c2 elementor-absolute elementor-widget elementor-widget-image" data-id="1a450c2" data-element_type="widget" data-e-type="widget" data-settings="{&quot;_position&quot;:&quot;absolute&quot;}" data-widget_type="image.default">
<div className="elementor-widget-container">
<img loading="lazy" decoding="async" width="965" height="474" src="/images/bg-map.png" className="attachment-full size-full wp-image-1148" alt="Map Grid" />
<div className="evnd__ministats">
{MINI_STATS.map((s) => (
<div className="evnd__mini" key={s.label}>
<CountUp value={s.value} decimals={s.decimals} suffix={s.suffix} />
<span>{s.label}</span>
</div>
</div>
{/* Icon Boxes */}
<div className="elementor-element elementor-element-6b51278 elementor-view-stacked elementor-position-inline-start elementor-shape-circle elementor-mobile-position-block-start elementor-widget elementor-widget-icon-box" data-id="6b51278" data-element_type="widget" data-e-type="widget" data-widget_type="icon-box.default">
<div className="elementor-widget-container">
<div className="elementor-icon-box-wrapper">
<div className="elementor-icon-box-icon">
<span className="elementor-icon">
<i aria-hidden="true" className="fontello icon-arrow-x-r-top"></i>
</span>
</div>
<div className="elementor-icon-box-content">
<div className="elementor-icon-box-title">
<span>Battery-Aware Routing</span>
</div>
<p className="elementor-icon-box-description">
Battery level, health, and degradation are first-class inputs to route optimization.
</p>
</div>
</div>
</div>
</div>
<div className="elementor-element elementor-element-e34beb2 elementor-widget-divider--view-line elementor-widget elementor-widget-divider" data-id="e34beb2" data-element_type="widget" data-e-type="widget" data-widget_type="divider.default">
<div className="elementor-widget-container">
<div className="elementor-divider">
<span className="elementor-divider-separator"></span>
</div>
</div>
</div>
<div className="elementor-element elementor-element-27ba815 elementor-view-stacked elementor-position-inline-start elementor-shape-circle elementor-mobile-position-block-start elementor-widget elementor-widget-icon-box" data-id="27ba815" data-element_type="widget" data-e-type="widget" data-widget_type="icon-box.default">
<div className="elementor-widget-container">
<div className="elementor-icon-box-wrapper">
<div className="elementor-icon-box-icon">
<span className="elementor-icon">
<i aria-hidden="true" className="fontello icon-arrow-x-r-top"></i>
</span>
</div>
<div className="elementor-icon-box-content">
<div className="elementor-icon-box-title">
<span>Charging Integration</span>
</div>
<p className="elementor-icon-box-description">
Seamlessly integrate charging stops without compromising delivery windows.
</p>
</div>
</div>
</div>
</div>
<div className="elementor-element elementor-element-6895eb5 elementor-widget-divider--view-line elementor-widget elementor-widget-divider" data-id="6895eb5" data-element_type="widget" data-e-type="widget" data-widget_type="divider.default">
<div className="elementor-widget-container">
<div className="elementor-divider">
<span className="elementor-divider-separator"></span>
</div>
</div>
</div>
<div className="elementor-element elementor-element-332c78f elementor-view-stacked elementor-position-inline-start elementor-shape-circle elementor-mobile-position-block-start elementor-widget elementor-widget-icon-box" data-id="332c78f" data-element_type="widget" data-e-type="widget" data-widget_type="icon-box.default">
<div className="elementor-widget-container">
<div className="elementor-icon-box-wrapper">
<div className="elementor-icon-box-icon">
<span className="elementor-icon">
<i aria-hidden="true" className="fontello icon-arrow-x-r-top"></i>
</span>
</div>
<div className="elementor-icon-box-content">
<div className="elementor-icon-box-title">
<span>Energy-Optimized Paths</span>
</div>
<p className="elementor-icon-box-description">
Factor in elevation, speed limits, and weather for maximum efficiency.
</p>
</div>
</div>
</div>
</div>
<div className="elementor-element elementor-element-6895eb5 elementor-widget-divider--view-line elementor-widget elementor-widget-divider" data-id="6895eb5" data-element_type="widget" data-e-type="widget" data-widget_type="divider.default">
<div className="elementor-widget-container">
<div className="elementor-divider">
<span className="elementor-divider-separator"></span>
</div>
</div>
</div>
<div className="elementor-element elementor-element-332c78f elementor-view-stacked elementor-position-inline-start elementor-shape-circle elementor-mobile-position-block-start elementor-widget elementor-widget-icon-box" data-id="332c78f" data-element_type="widget" data-e-type="widget" data-widget_type="icon-box.default">
<div className="elementor-widget-container">
<div className="elementor-icon-box-wrapper">
<div className="elementor-icon-box-icon">
<span className="elementor-icon">
<i aria-hidden="true" className="fontello icon-arrow-x-r-top"></i>
</span>
</div>
<div className="elementor-icon-box-content">
<div className="elementor-icon-box-title">
<span>Predictable Operations</span>
</div>
<p className="elementor-icon-box-description">
EVs become predictable assets, not operational risks.
</p>
</div>
</div>
</div>
</div>
<div className="elementor-element elementor-element-e70d3b7 elementor-widget elementor-widget-logico_button" data-id="e70d3b7" data-element_type="widget" data-e-type="widget" data-widget_type="logico_button.default">
<div className="elementor-widget-container">
<div className="button-widget">
<div className="button-container">
<Link href="/solutions" className="logico-alter-button">Explore more</Link>
</div>
</div>
</div>
</div>
))}
</div>
</SlideReveal>
</div>
{/* Right column */}
<div className="evnd__features">
{FEATURES.map((f) => (
<div className="evnd-feature" key={f.title}>
<span className="evnd-feature__icon" aria-hidden="true">{f.icon}</span>
<div className="evnd-feature__body">
<div className="evnd-feature__title">{f.title}</div>
<p className="evnd-feature__desc">{f.desc}</p>
</div>
<span className="evnd-feature__arrow" aria-hidden="true"></span>
</div>
))}
</div>
</div>
{/* BOTTOM BAR */}
<div className="evnd__bar">
{BOTTOM_STATS.map((s) => (
<div className="evnd__bar-item" key={s.label}>
<span className="dot" />
<CountUp value={s.value} decimals={s.decimals} suffix={s.suffix} />
<span>{s.label}</span>
</div>
))}
</div>
</div>
</div>
</section>
</div>
</>

View File

@@ -83,16 +83,16 @@ export default function IndexHero() {
backgroundSize: "cover"
}}
>
<div className="slide-content">
<div className="slide-content-inner">
<h1 className="content-slider-item-heading logico-content-wrapper-1">
<div className="slide-content" style={{ display: "flex", flexDirection: "column", justifyContent: "center", alignItems: "center", width: "100%", height: "100%" }}>
<div className="slide-content-inner" style={{ display: "flex", flexDirection: "column", justifyContent: "center", alignItems: "center", textAlign: "center", margin: "0 auto", width: "100%", maxWidth: "1000px" }}>
<h1 className="content-slider-item-heading logico-content-wrapper-1" style={{ textAlign: "center", width: "100%" }}>
<span className="heading-content block">
ONE CONNECTED SYSTEM.<br />
<ShimmerText className="font-extrabold">ONE PROMISE KEPT.</ShimmerText>
</span>
</h1>
<div className="content-slider-item-text logico-content-wrapper-2">
<div className="text-content">
<div className="content-slider-item-text logico-content-wrapper-2" style={{ display: "flex", justifyContent: "center", width: "100%", marginTop: "23px" }}>
<div className="text-content" style={{ textAlign: "center", maxWidth: "680px", margin: "0 auto" }}>
<p>Stop managing three separate logistics services. Doormile unifies first, mid and last mile into a single intelligent delivery system powered by MileTruth AI.</p>
</div>
</div>
@@ -124,16 +124,16 @@ export default function IndexHero() {
backgroundSize: "cover"
}}
>
<div className="slide-content">
<div className="slide-content-inner">
<h1 className="content-slider-item-heading logico-content-wrapper-1">
<div className="slide-content" style={{ display: "flex", flexDirection: "column", justifyContent: "center", alignItems: "center", width: "100%", height: "100%" }}>
<div className="slide-content-inner" style={{ display: "flex", flexDirection: "column", justifyContent: "center", alignItems: "center", textAlign: "center", margin: "0 auto", width: "100%", maxWidth: "1000px" }}>
<h1 className="content-slider-item-heading logico-content-wrapper-1" style={{ textAlign: "center", width: "100%" }}>
<span className="heading-content block">
<ShimmerText className="font-extrabold">AI-POWERED</ShimmerText><br />
CONNECTED LOGISTICS
</span>
</h1>
<div className="content-slider-item-text logico-content-wrapper-2">
<div className="text-content">
<div className="content-slider-item-text logico-content-wrapper-2" style={{ display: "flex", justifyContent: "center", width: "100%", marginTop: "23px" }}>
<div className="text-content" style={{ textAlign: "center", maxWidth: "680px", margin: "0 auto" }}>
<p>Behind every successful business is a strong supply chain. Logistics turns plans into reality.</p>
</div>
</div>

View File

@@ -0,0 +1,226 @@
"use client";
import React, { useEffect, useRef } from "react";
/**
* Animated dotted world map (Canvas 2D) for the Solutions industry section.
* - Continents drawn as a grid of dots clipped to rough continent polygons.
* - Major logistics hub cities with continuous double red pulse rings.
* - Red glowing packets travelling along arced quadratic-bezier routes.
* - Low-opacity dashed connection lines between hubs.
* Continent / city coordinates are normalized (0..1): x west→east, y north→south.
*/
const CONTINENTS: number[][][] = [
// North America
[[0.04,0.20],[0.10,0.12],[0.18,0.10],[0.24,0.13],[0.29,0.12],[0.30,0.18],
[0.27,0.22],[0.26,0.28],[0.22,0.30],[0.20,0.38],[0.17,0.44],[0.15,0.40],
[0.16,0.32],[0.12,0.30],[0.09,0.26],[0.06,0.24]],
// South America
[[0.21,0.50],[0.27,0.48],[0.31,0.52],[0.31,0.60],[0.29,0.66],[0.27,0.74],
[0.24,0.82],[0.22,0.80],[0.22,0.70],[0.205,0.62],[0.20,0.55]],
// Europe
[[0.45,0.16],[0.50,0.13],[0.55,0.15],[0.57,0.19],[0.55,0.24],[0.50,0.27],
[0.47,0.25],[0.455,0.20]],
// Africa
[[0.46,0.34],[0.53,0.32],[0.58,0.36],[0.585,0.44],[0.56,0.52],[0.53,0.60],
[0.50,0.66],[0.47,0.62],[0.46,0.52],[0.45,0.44],[0.45,0.38]],
// Asia
[[0.56,0.14],[0.64,0.10],[0.74,0.10],[0.84,0.14],[0.90,0.20],[0.92,0.26],
[0.86,0.30],[0.80,0.30],[0.74,0.34],[0.70,0.34],[0.66,0.30],[0.60,0.30],
[0.575,0.24],[0.565,0.18]],
// Australia
[[0.81,0.66],[0.87,0.64],[0.92,0.68],[0.92,0.74],[0.86,0.77],[0.81,0.74],[0.80,0.70]],
];
const CITIES: [number, number][] = [
[0.115, 0.30], // 0 Los Angeles
[0.265, 0.255],// 1 New York
[0.285, 0.66], // 2 São Paulo
[0.475, 0.185],// 3 London
[0.605, 0.345],// 4 Dubai
[0.655, 0.40], // 5 Mumbai
[0.745, 0.50], // 6 Singapore
[0.815, 0.275],// 7 Shanghai
[0.865, 0.715],// 8 Sydney
];
const ROUTES: [number, number][] = [
[0, 1], [1, 3], [3, 4], [4, 5], [5, 6], [6, 7], [7, 8], [1, 2], [3, 7], [0, 7],
];
function pointInPoly(x: number, y: number, poly: number[][]) {
let inside = false;
for (let i = 0, j = poly.length - 1; i < poly.length; j = i++) {
const xi = poly[i][0], yi = poly[i][1];
const xj = poly[j][0], yj = poly[j][1];
const intersect = yi > y !== yj > y && x < ((xj - xi) * (y - yi)) / (yj - yi) + xi;
if (intersect) inside = !inside;
}
return inside;
}
export default function IndustryWorldMap() {
const canvasRef = useRef<HTMLCanvasElement>(null);
useEffect(() => {
const canvas = canvasRef.current;
const parent = canvas?.parentElement;
if (!canvas || !parent) return;
const ctx = canvas.getContext("2d");
if (!ctx) return;
const reduced = window.matchMedia?.("(prefers-reduced-motion: reduce)").matches;
let w = 0, h = 0;
let dots: { x: number; y: number }[] = [];
let raf = 0;
let startTs = 0;
const buildDots = () => {
dots = [];
const gap = Math.max(11, Math.min(17, w / 70));
for (let gx = gap / 2; gx < w; gx += gap) {
for (let gy = gap / 2; gy < h; gy += gap) {
const nx = gx / w, ny = gy / h;
for (const poly of CONTINENTS) {
if (pointInPoly(nx, ny, poly)) { dots.push({ x: gx, y: gy }); break; }
}
}
}
};
const resize = () => {
const rect = parent.getBoundingClientRect();
w = Math.max(1, rect.width);
h = Math.max(1, rect.height);
const dpr = Math.min(window.devicePixelRatio || 1, 2);
canvas.width = Math.round(w * dpr);
canvas.height = Math.round(h * dpr);
canvas.style.width = w + "px";
canvas.style.height = h + "px";
ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
buildDots();
};
const cityPx = () => CITIES.map(([cx, cy]) => ({ x: cx * w, y: cy * h }));
const ctrl = (p0: { x: number; y: number }, p1: { x: number; y: number }) => {
const mx = (p0.x + p1.x) / 2, my = (p0.y + p1.y) / 2;
const lift = Math.hypot(p1.x - p0.x, p1.y - p0.y) * 0.28;
return { x: mx, y: my - lift };
};
const bezier = (p0: any, c: any, p1: any, t: number) => {
const u = 1 - t;
return {
x: u * u * p0.x + 2 * u * t * c.x + t * t * p1.x,
y: u * u * p0.y + 2 * u * t * c.y + t * t * p1.y,
};
};
const draw = (time: number) => {
ctx.clearRect(0, 0, w, h);
// Continent dots
ctx.fillStyle = "rgba(120,122,130,0.55)";
for (const d of dots) {
ctx.beginPath();
ctx.arc(d.x, d.y, 1.15, 0, Math.PI * 2);
ctx.fill();
}
const cs = cityPx();
// Dashed connection lines (low opacity)
ctx.save();
ctx.setLineDash([4, 7]);
ctx.lineWidth = 1;
ctx.strokeStyle = "rgba(239,68,68,0.13)";
for (const [a, b] of ROUTES) {
const c = ctrl(cs[a], cs[b]);
ctx.beginPath();
ctx.moveTo(cs[a].x, cs[a].y);
ctx.quadraticCurveTo(c.x, c.y, cs[b].x, cs[b].y);
ctx.stroke();
}
ctx.restore();
// Travelling red glowing packets
ctx.save();
for (let r = 0; r < ROUTES.length; r++) {
const [a, b] = ROUTES[r];
const c = ctrl(cs[a], cs[b]);
const t = ((time * 0.11 + r * 0.137) % 1 + 1) % 1;
const p = bezier(cs[a], c, cs[b], t);
// soft trail
const tt = Math.max(0, t - 0.04);
const pt = bezier(cs[a], c, cs[b], tt);
const grad = ctx.createLinearGradient(pt.x, pt.y, p.x, p.y);
grad.addColorStop(0, "rgba(239,68,68,0)");
grad.addColorStop(1, "rgba(239,68,68,0.5)");
ctx.strokeStyle = grad;
ctx.lineWidth = 2;
ctx.beginPath();
ctx.moveTo(pt.x, pt.y);
ctx.lineTo(p.x, p.y);
ctx.stroke();
ctx.shadowColor = "#ef4444";
ctx.shadowBlur = 12;
ctx.fillStyle = "#ef4444";
ctx.beginPath();
ctx.arc(p.x, p.y, 2.6, 0, Math.PI * 2);
ctx.fill();
ctx.shadowBlur = 0;
}
ctx.restore();
// City hub nodes + double pulse rings
for (const c of cs) {
for (let k = 0; k < 2; k++) {
const period = 2.6;
const phase = (((time + (k * period) / 2) % period) + period) % period / period;
const radius = 3 + phase * 24;
const alpha = (1 - phase) * 0.45;
ctx.beginPath();
ctx.strokeStyle = `rgba(239,68,68,${alpha})`;
ctx.lineWidth = 1.5;
ctx.arc(c.x, c.y, radius, 0, Math.PI * 2);
ctx.stroke();
}
ctx.fillStyle = "#ef4444";
ctx.shadowColor = "#ef4444";
ctx.shadowBlur = 8;
ctx.beginPath();
ctx.arc(c.x, c.y, 2.6, 0, Math.PI * 2);
ctx.fill();
ctx.shadowBlur = 0;
}
};
const loop = (ts: number) => {
if (!startTs) startTs = ts;
draw((ts - startTs) / 1000);
raf = requestAnimationFrame(loop);
};
resize();
if (reduced) {
draw(0);
} else {
raf = requestAnimationFrame(loop);
}
const ro = new ResizeObserver(() => {
resize();
if (reduced) draw(0);
});
ro.observe(parent);
return () => {
cancelAnimationFrame(raf);
ro.disconnect();
};
}, []);
return <canvas ref={canvasRef} className="ind__map" aria-hidden="true" />;
}

File diff suppressed because it is too large Load Diff

View File

@@ -31,6 +31,52 @@ export default function OurTeam() {
];
return (
<>
<style dangerouslySetInnerHTML={{ __html: `
/* Team photos: grayscale by default, full colour on hover (matches design) */
.team-listing-wrapper.team-grid-listing .team-item .post-media img {
filter: grayscale(100%);
transition: filter 0.45s ease;
}
.team-listing-wrapper.team-grid-listing .team-item:hover .post-media img {
filter: grayscale(0%);
}
/* Self-contained layout (does not rely on the cached vendor CSS). */
/* Grid: three columns that wrap, with tightened row/column gaps. */
.team-listing-wrapper.team-grid-listing {
display: flex;
flex-wrap: wrap;
margin: 0 -16px -44px;
}
.team-listing-wrapper.team-grid-listing .team-item-wrapper {
width: 33.3333%;
padding: 0 16px;
margin-bottom: 44px;
box-sizing: border-box;
}
@media (max-width: 1020px) {
.team-listing-wrapper.team-grid-listing .team-item-wrapper { width: 50%; }
}
@media (max-width: 660px) {
.team-listing-wrapper.team-grid-listing .team-item-wrapper { width: 100%; }
}
/* Card: photo on the LEFT, name/position on the RIGHT (side by side). */
.team-listing-wrapper.team-grid-listing .team-item {
display: flex;
flex-direction: row;
align-items: center;
gap: 16px;
}
.team-listing-wrapper.team-grid-listing .team-item-media {
flex-shrink: 0;
width: 160px;
}
.team-listing-wrapper.team-grid-listing .team-item-content {
flex: 1;
}
`}} />
<div className="elementor-element elementor-element-c2c601a e-flex e-con-boxed cut-corner-no sticky-container-off e-con e-parent" data-id="c2c601a" data-element_type="container" data-e-type="container">
<div className="e-con-inner">
<div className="elementor-element elementor-element-3306a27 e-con-full e-flex cut-corner-no sticky-container-off e-con e-child" data-id="3306a27" data-element_type="container" data-e-type="container">
@@ -42,7 +88,7 @@ export default function OurTeam() {
<div style={{ alignSelf: "flex-start", width: "100%" }} className="elementor-element elementor-element-c46350e elementor-widget__width-initial elementor-widget elementor-widget-logico_heading" data-id="c46350e" data-element_type="widget" data-e-type="widget" data-widget_type="logico_heading.default">
<div className="elementor-widget-container">
<h3 className="logico-title" style={{ textAlign: "left" }}>Meet our best crew</h3>
<h3 className="logico-title" style={{ textAlign: "left" }}>Meet our the best crew</h3>
</div>
</div>
@@ -93,5 +139,6 @@ export default function OurTeam() {
</div>
</div>
</div>
</>
);
}

View File

@@ -1,432 +1,498 @@
"use client";
import React, { useState } from "react";
import Image from "next/image";
import IndustryWorldMap from "./IndustryWorldMap";
type Tab = "challenges" | "solutions";
interface Industry {
id: string;
tab: string;
eyebrow: string;
title: string;
image: string;
alt: string;
desc: string;
chips: [string, string];
challenges: string[];
solutions: string[];
}
const INDUSTRIES: Industry[] = [
{
id: "fmcg",
tab: "FMCG",
eyebrow: "Fast-Moving Consumer Goods",
title: "FMCG",
image: "/images/tab-pic-1-solution.jpeg",
alt: "FMCG logistics",
desc:
"FMCG logistics demands speed, precision, and continuous fulfillment across high-volume delivery networks — balancing tight timelines, inventory movement, and efficiency without compromising availability.",
chips: ["99.2% On-Time", "Live Route Sync"],
challenges: [
"Unpredictable demand spikes create delivery pressure during peak periods.",
"Fresh-product expiry constraints require faster, precisely timed deliveries.",
"Multi-stop route complexity increases travel time and coordination cost.",
"Inventory stockout risks rise when delays disrupt fast-moving distribution.",
],
solutions: [
"AI demand forecasting adapts delivery plans instantly to real-time order demand.",
"Expiry-aware routing prioritises perishable goods for on-time freshness.",
"Smart multi-stop optimisation groups orders to cut cost and travel time.",
"Real-time inventory sync prevents stockouts and improves fulfilment accuracy.",
],
},
{
id: "pharma",
tab: "Pharma",
eyebrow: "Pharmaceutical Logistics",
title: "Pharma",
image: "/images/tab-pic-2-solution.jpeg",
alt: "Pharma logistics",
desc:
"Pharma logistics requires precision, compliance, and real-time monitoring so every shipment arrives safely and on time — from temperature-sensitive medicines to urgent emergency deliveries.",
chips: ["Cold Chain Active", "Zero Delay SLA"],
challenges: [
"Cold chain integrity demands precise temperature control throughout transit.",
"Regulatory compliance must be tracked and documented on every delivery.",
"Critical delivery time windows require highly accurate scheduling.",
"Emergency shipments need instant dispatch and zero-delay execution.",
],
solutions: [
"Cold chain monitoring with automatic re-routing keeps shipments in-spec.",
"Compliance engine with audit trails ensures full chain-of-custody visibility.",
"Precision scheduling locks in critical delivery windows reliably.",
"Priority dispatch queue fast-tracks urgent, life-critical shipments.",
],
},
{
id: "b2b",
tab: "Enterprise & B2B",
eyebrow: "Enterprise & B2B",
title: "Enterprise & B2B",
image: "/images/tab-pic-3-solution.jpeg",
alt: "Enterprise and B2B logistics",
desc:
"Enterprise and B2B logistics require coordination and reliability to manage high-value shipments at scale — with appointment scheduling, white-glove standards, and strict SLA commitments.",
chips: ["SLA Guaranteed", "White-Glove Ready"],
challenges: [
"Appointment scheduling requires precise timing across many locations.",
"White-glove delivery standards demand premium handling and accuracy.",
"Multi-location routing complexity grows with large-scale operations.",
"Strict SLA commitments pressure teams to stay timely and error-free.",
],
solutions: [
"Intelligent appointment engine streamlines and automates delivery slots.",
"White-glove workflow module enforces premium handling end to end.",
"Enterprise route planner coordinates efficient multi-location delivery.",
"SLA monitoring dashboard tracks commitments and flags risk in real time.",
],
},
];
export default function SolutionCard1() {
const [activeTabFmcg, setActiveTabFmcg] = useState<"challenges" | "solutions">("challenges");
const [activeTabPharma, setActiveTabPharma] = useState<"challenges" | "solutions">("challenges");
const [activeTabB2b, setActiveTabB2b] = useState<"challenges" | "solutions">("challenges");
const [active, setActive] = useState(0);
const [tab, setTab] = useState<Tab>("challenges");
const ind = INDUSTRIES[active];
const selectIndustry = (i: number) => {
setActive(i);
setTab("challenges"); // reset to Challenges on industry switch
};
return (
<>
<style dangerouslySetInnerHTML={{ __html: `
/* Alternate tabs style: full-width blue tabs, larger size and font */
.solution-freight-tabs-alt {
/* ============================================================
Solutions — Industry section (FMCG / Pharma / Enterprise & B2B)
Brand red #dc2626 / #ef4444 · bg #0d0d0d · Syne + DM Sans
============================================================ */
/* The theme forces Manrope on every element via a high-specificity
universal :not() !important rule; re-assert Syne / DM Sans from the
ID selector (which outranks it) directly on each text node. */
#ind-solutions .ind__eyebrow,
#ind-solutions .ind__title,
#ind-solutions .ind__tab,
#ind-solutions .ind__toggle-btn {
font-family: var(--font-syne), 'Syne', sans-serif !important;
}
#ind-solutions .ind__desc,
#ind-solutions .ind__chip,
#ind-solutions .ind__list li {
font-family: var(--font-dm-sans), 'DM Sans', sans-serif !important;
}
/* kit-5 also forces heading color/size on the title (an <h3>). */
#ind-solutions .ind__title {
color: #fff !important;
font-size: clamp(34px, 5.5vw, 68px) !important;
font-weight: 800 !important;
line-height: 1.02 !important;
margin: 0 0 16px !important;
letter-spacing: -0.01em !important;
}
#ind-solutions .ind__list li { color: #c9c9c9 !important; }
.ind {
position: relative;
isolation: isolate;
overflow: hidden;
background: #0d0d0d;
border-radius: clamp(16px, 2vw, 26px);
max-width: 1400px;
margin: clamp(24px, 4vw, 56px) auto;
padding: clamp(34px, 5vw, 76px) clamp(18px, 4vw, 64px);
}
.ind__map {
position: absolute;
inset: 0;
width: 100%;
margin: 18px 0 28px;
font-family: 'Manrope', sans-serif;
height: 100%;
opacity: 0.55;
z-index: 0;
pointer-events: none;
}
.ind__inner {
position: relative;
z-index: 1;
max-width: 1240px;
margin: 0 auto;
}
/* Centered, non-full-width tabs */
.solution-freight-tabs-alt .solution-freight-tabs__nav {
/* ---- Top tab bar ---- */
.ind__tabs {
display: flex;
gap: 12px;
align-items: flex-end;
width: auto;
margin: 0 auto 6px;
gap: clamp(10px, 3vw, 36px);
border-bottom: 1px solid rgba(255,255,255,0.1);
margin-bottom: clamp(28px, 4vw, 52px);
flex-wrap: wrap;
}
.solution-freight-tabs-alt .solution-freight-tabs__button {
.ind__tab {
appearance: none;
border: 1px solid rgba(0, 0, 0, 0.06);
background: linear-gradient(180deg, #f9ccd1, #f9ccd1);
color: #111;
padding: 12px 36px;
display: inline-block;
min-width: 180px;
text-align: center;
border-radius: 6px 6px 0 0;
background: none;
border: none;
cursor: pointer;
font-weight: 800;
text-transform: uppercase;
letter-spacing: 0.6px;
box-shadow: none;
transition: background-color 0.12s ease, color 0.12s ease, transform 0.08s ease;
padding: 10px 2px 16px;
font-weight: 700;
font-size: clamp(14px, 1.4vw, 18px);
color: #888;
position: relative;
letter-spacing: 0.01em;
transition: color 0.3s ease;
}
.ind__tab::after {
content: '';
position: absolute;
left: 0; right: 0; bottom: -1px;
height: 2px;
background: #dc2626;
transform: scaleX(0);
transform-origin: left;
transition: transform 0.35s cubic-bezier(.25,1,.5,1);
}
.ind__tab:hover { color: #ccc; }
.ind__tab.active { color: #fff; }
.ind__tab.active::after { transform: scaleX(1); }
/* ---- Grid ---- */
.ind__grid {
display: grid;
grid-template-columns: 0.9fr 1.1fr;
gap: clamp(28px, 4vw, 64px);
align-items: center;
}
.solution-freight-tabs-alt .solution-freight-tabs__button h6 {
margin: 0;
font-size: 16px;
color: inherit;
font-weight: 800;
/* ---- Left media ---- */
.ind__media {
position: relative;
display: flex;
align-items: center;
justify-content: center;
min-height: 300px;
}
.solution-freight-tabs-alt .solution-freight-tabs__button:hover {
transform: translateY(-2px);
background: linear-gradient(180deg, #f9ccd1, #f9ccd1);
.ind__glow {
position: absolute;
left: 50%; bottom: 4%;
width: 74%; height: 70px;
transform: translateX(-50%);
background: radial-gradient(50% 50% at 50% 50%, rgba(220,38,38,0.5), transparent 72%);
filter: blur(32px);
z-index: 0;
animation: indGlow 4s ease-in-out infinite;
}
.solution-freight-tabs-alt .solution-freight-tabs__button.active {
background: #C01227;
color: #ffffff;
border-color: #C01227;
box-shadow: none;
transform: none;
.ind__img-wrap {
position: relative;
z-index: 1;
width: 100%;
max-width: 460px;
animation: indFloat 6s ease-in-out infinite;
will-change: transform;
}
.ind__img-wrap::before,
.ind__img-wrap::after {
content: '';
position: absolute;
width: 44px; height: 44px;
border: 2px solid #dc2626;
z-index: 3;
}
.solution-freight-tabs-alt .solution-freight-tabs__content {
margin-top: 2px;
padding: 18px 20px;
border: 1px solid rgba(0, 0, 0, 0.06);
border-top: none;
border-radius: 0 6px 6px 6px;
background: #ffffff00;
max-width: 620px;
margin-right: auto;
.ind__img-wrap::before {
top: -10px; left: -10px;
border-right: none; border-bottom: none;
border-radius: 10px 0 0 0;
}
.solution-freight-tabs-alt .point-box li::before {
content: "";
width: 8px;
height: 8px;
border-radius: 50%;
background: #C01227;
left: 6px;
top: 8px;
.ind__img-wrap::after {
bottom: -10px; right: -10px;
border-left: none; border-top: none;
border-radius: 0 0 10px 0;
}
@media (max-width: 767px) {
.solution-freight-tabs-alt .solution-freight-tabs__button {
padding: 10px 18px;
min-width: 120px;
}
.solution-freight-tabs-alt .solution-freight-tabs__content {
max-width: 100%;
margin: 0 12px;
}
.ind__img {
display: block;
width: 100%;
height: auto;
border-radius: 12px;
object-fit: cover;
box-shadow: 0 30px 60px -25px rgba(0,0,0,0.7);
animation: indImgFade 0.55s ease both;
}
@media (max-width: 767px) {
.solution-freight-tabs-alt .solution-freight-tabs__button {
padding: 12px 0;
font-size: 14px;
}
.solution-freight-tabs-alt .solution-freight-tabs__button h6 {
font-size: 14px;
}
}
@media (max-width: 1024px) {
.solution-freight-tabs__button {
font-size: 18px;
}
.point-box li {
font-size: 15px;
}
}
@media (max-width: 480px) {
.solution-freight-tabs__button {
font-size: 14px;
}
.solution-freight-tabs__panel p {
font-size: 14px;
}
.point-box li {
font-size: 14px;
}
}
/* Point Box List Styling */
.point-box {
list-style: none;
padding: 0;
margin: 0;
}
.point-box li {
position: relative;
margin: 0 0 20px 0;
padding-left: 32px;
color: #666;
font-size: 16px;
font-weight: 500;
line-height: 1.7;
}
.point-box li:last-child {
margin-bottom: 0;
}
.point-box li::before {
content: "✓";
.ind__chip {
position: absolute;
left: 0;
top: -2px;
color: #C01227;
font-size: 18px;
z-index: 4;
display: inline-flex;
align-items: center;
gap: 8px;
padding: 9px 16px;
border-radius: 999px;
background: rgba(16,16,16,0.82);
border: 1px solid rgba(239,68,68,0.4);
backdrop-filter: blur(8px);
color: #fff;
font-weight: 500;
font-size: 13px;
white-space: nowrap;
box-shadow: 0 12px 28px -12px rgba(0,0,0,0.7);
animation: indFloat 6s ease-in-out infinite;
}
.ind__chip .dot {
width: 7px; height: 7px;
border-radius: 50%;
background: #ef4444;
box-shadow: 0 0 8px #ef4444;
animation: indDot 1.6s ease-in-out infinite;
}
.ind__chip--1 { top: 7%; left: -5%; animation-delay: 0.4s; }
.ind__chip--2 { bottom: 12%; right: -5%; animation-delay: 1.3s; }
/* ---- Right text ---- */
.ind__text { min-width: 0; }
.ind__eyebrow {
display: inline-flex;
align-items: center;
gap: 12px;
color: #ef4444;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.16em;
font-size: clamp(11px, 1vw, 13px);
margin-bottom: 14px;
}
.ind__eyebrow::before {
content: '';
width: 30px; height: 2px;
background: #ef4444;
}
.ind__desc {
color: #b4b4b4;
font-size: clamp(15px, 1.2vw, 18px);
line-height: 1.7;
font-weight: 400;
margin: 0 0 24px;
max-width: 580px;
}
.point-box li.spacer {
height: 12px;
margin: 10px 0 0;
padding-left: 32px;
visibility: hidden;
/* ---- Challenges / Solutions toggle ---- */
.ind__toggle {
display: inline-flex;
gap: 4px;
padding: 5px;
border-radius: 999px;
background: rgba(255,255,255,0.05);
border: 1px solid rgba(255,255,255,0.09);
margin-bottom: 24px;
}
.ind__toggle-btn {
appearance: none;
border: none;
cursor: pointer;
padding: 9px 28px;
border-radius: 999px;
font-weight: 700;
font-size: 14px;
color: #9a9a9a;
background: transparent;
transition: color 0.3s ease, background-color 0.3s ease, box-shadow 0.3s ease;
}
.ind__toggle-btn:hover { color: #ddd; }
.ind__toggle-btn.active {
background: #dc2626;
color: #fff;
box-shadow: 0 8px 20px -8px rgba(220,38,38,0.6);
}
.point-box li.spacer::before {
content: none;
/* ---- Sliding panels ---- */
.ind__slider { overflow: hidden; }
.ind__track {
display: flex;
width: 200%;
transition: transform 0.4s cubic-bezier(.4,0,.2,1);
}
.ind__panel { width: 50%; flex: 0 0 50%; }
.ind__list { list-style: none; margin: 0; padding: 0; }
.ind__list li {
position: relative;
padding-left: 30px;
margin-bottom: 16px;
font-size: clamp(14px, 1.1vw, 16px);
line-height: 1.6;
opacity: 0;
transform: translateX(-16px);
}
.ind__list li:last-child { margin-bottom: 0; }
.ind__list li::before {
content: '';
position: absolute;
left: 4px; top: 8px;
width: 8px; height: 8px;
border-radius: 50%;
background: #dc2626;
box-shadow: 0 0 8px rgba(220,38,38,0.7);
}
.ind__panel.is-active .ind__list li {
animation: indBullet 0.5s cubic-bezier(.25,1,.5,1) forwards;
}
.ind__panel.is-active .ind__list li:nth-child(1) { animation-delay: 0.05s; }
.ind__panel.is-active .ind__list li:nth-child(2) { animation-delay: 0.13s; }
.ind__panel.is-active .ind__list li:nth-child(3) { animation-delay: 0.21s; }
.ind__panel.is-active .ind__list li:nth-child(4) { animation-delay: 0.29s; }
.ind__panel.is-active .ind__list li:nth-child(5) { animation-delay: 0.37s; }
@keyframes indFloat { 0%,100% { transform: translateY(0); } 50% { transform: translateY(-14px); } }
@keyframes indGlow { 0%,100% { opacity: 0.6; } 50% { opacity: 1; } }
@keyframes indDot { 0%,100% { opacity: 1; } 50% { opacity: 0.35; } }
@keyframes indBullet { to { opacity: 1; transform: translateX(0); } }
@keyframes indImgFade { from { opacity: 0; transform: scale(0.97); } to { opacity: 1; transform: scale(1); } }
/* ---- Responsive ---- */
@media (max-width: 900px) {
.ind__grid { grid-template-columns: 1fr; gap: clamp(40px, 8vw, 56px); }
.ind__media { order: -1; }
.ind__img-wrap { max-width: 380px; }
}
@media (max-width: 600px) {
.ind__chip { font-size: 12px; padding: 7px 12px; }
.ind__chip--1 { left: 0; }
.ind__chip--2 { right: 0; }
.ind__toggle-btn { padding: 9px 20px; }
}
@media (prefers-reduced-motion: reduce) {
.ind__img-wrap, .ind__glow, .ind__chip, .ind__chip .dot { animation: none !important; }
.ind__track { transition: none !important; }
.ind__panel.is-active .ind__list li { animation: none !important; opacity: 1; transform: none; }
}
`}} />
<div className="elementor-61">
<section id="ind-solutions" className="ind" aria-label="Industry solutions">
<IndustryWorldMap />
{/* FMCG Section */}
<div style={{ marginTop: "0px" }} className="elementor-element elementor-element-89a0ca1 e-con-full e-flex cut-corner-no sticky-container-off e-con e-parent" data-id="89a0ca1" data-element_type="container" data-e-type="container">
<div className="elementor-element elementor-element-9ffed33 e-con-full e-flex cut-corner-no sticky-container-off e-con e-child" data-id="9ffed33" data-element_type="container" data-e-type="container" data-settings='{"background_background":"classic"}'>
<div className="elementor-element elementor-element-96343ba e-con-full e-flex cut-corner-no sticky-container-off e-con e-child elementor-image-section" data-id="96343ba" data-element_type="container" data-e-type="container">
<div className="elementor-element elementor-element-99768ba elementor-widget elementor-widget-image" data-id="99768ba" data-element_type="widget" data-e-type="widget" data-widget_type="image.default" style={{ width: "100%", display: "flex", alignItems: "center", justifyContent: "center" }}>
<div className="elementor-widget-container" style={{ margin: 0, width: "100%", height: "100%", display: "flex", alignItems: "center", justifyContent: "center" }}>
<Image
src="/images/tab-pic-1-solution.jpeg"
alt="FMCG Solutions"
width={578}
height={790}
priority
style={{ maxWidth: "100%", maxHeight: "100%", objectFit: "contain" }}
/>
</div>
<div className="ind__inner">
{/* Top tab bar */}
<div className="ind__tabs" role="tablist" aria-label="Industries">
{INDUSTRIES.map((it, i) => (
<button
key={it.id}
type="button"
role="tab"
aria-selected={i === active}
className={`ind__tab ${i === active ? "active" : ""}`}
onClick={() => selectIndustry(i)}
>
{it.tab}
</button>
))}
</div>
<div className="ind__grid">
{/* Left media */}
<div className="ind__media">
<div className="ind__glow" />
<div className="ind__img-wrap">
{/* eslint-disable-next-line @next/next/no-img-element */}
<img key={active} className="ind__img" src={ind.image} alt={ind.alt} decoding="async" />
</div>
<div className="ind__chip ind__chip--1">
<span className="dot" />
{ind.chips[0]}
</div>
<div className="ind__chip ind__chip--2">
<span className="dot" />
{ind.chips[1]}
</div>
</div>
<div className="elementor-element elementor-element-71c3e1d e-con-full e-flex cut-corner-no sticky-container-off e-con e-child section-2-content" data-id="71c3e1d" data-element_type="container" data-e-type="container">
<div className="elementor-element elementor-element-fdb2e58 e-con-full e-flex cut-corner-no sticky-container-off e-con e-child" data-id="fdb2e58" data-element_type="container" data-e-type="container">
<div className="elementor-element elementor-element-7500280 elementor-widget elementor-widget-logico_heading" data-id="7500280" data-element_type="widget" data-e-type="widget" data-widget_type="logico_heading.default">
<div className="elementor-widget-container" style={{ margin: 0 }}>
<h3 className="logico-title">FMCG</h3>
</div>
</div>
<div className="elementor-element elementor-element-165dfa5 elementor-widget__width-initial elementor-widget elementor-widget-text-editor" data-id="165dfa5" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
<div className="elementor-widget-container" style={{ margin: 0, fontSize: "20px", lineHeight: 1.7 }}>
<p>FMCG logistics demands speed, precision, and continuous fulfillment across high-volume delivery networks. Businesses must balance tight delivery timelines, inventory movement, and operational efficiency without compromising product availability.</p>
</div>
</div>
{/* Right text */}
<div className="ind__text">
<span className="ind__eyebrow">{ind.eyebrow}</span>
<h3 className="ind__title">{ind.title}</h3>
<p className="ind__desc">{ind.desc}</p>
{/* FMCG Tabs */}
<div className="solution-freight-tabs-alt">
<div className="solution-freight-tabs__nav" role="tablist" aria-label="FMCG Details">
<button
className={`solution-freight-tabs__button ${activeTabFmcg === "challenges" ? "active" : ""}`}
type="button"
role="tab"
aria-selected={activeTabFmcg === "challenges"}
onClick={() => setActiveTabFmcg("challenges")}
>
<h6>Challenges</h6>
</button>
<button
className={`solution-freight-tabs__button ${activeTabFmcg === "solutions" ? "active" : ""}`}
type="button"
role="tab"
aria-selected={activeTabFmcg === "solutions"}
onClick={() => setActiveTabFmcg("solutions")}
>
<h6>Solutions</h6>
</button>
<div className="ind__toggle" role="tablist" aria-label="Challenges or Solutions">
<button
type="button"
role="tab"
aria-selected={tab === "challenges"}
className={`ind__toggle-btn ${tab === "challenges" ? "active" : ""}`}
onClick={() => setTab("challenges")}
>
Challenges
</button>
<button
type="button"
role="tab"
aria-selected={tab === "solutions"}
className={`ind__toggle-btn ${tab === "solutions" ? "active" : ""}`}
onClick={() => setTab("solutions")}
>
Solutions
</button>
</div>
<div className="ind__slider">
<div
className="ind__track"
key={active}
style={{ transform: tab === "challenges" ? "translateX(0)" : "translateX(-50%)" }}
>
<div className={`ind__panel ${tab === "challenges" ? "is-active" : ""}`}>
<ul className="ind__list">
{ind.challenges.map((c, idx) => (
<li key={idx}>{c}</li>
))}
</ul>
</div>
<div className="solution-freight-tabs__content">
{activeTabFmcg === "challenges" ? (
<div className="solution-freight-tabs__panel active" role="tabpanel">
<ul className="point-box">
<li>Unpredictable demand spikes create delivery pressure and reduce operational efficiency during peak periods.</li>
<li>Fresh product expiry constraints require faster, precisely timed deliveries to maintain product quality.</li>
<li>Multi-stop route complexity increases travel time, operational costs, and delivery coordination challenges.</li>
<li>Inventory stockout risks increase when delivery delays disrupt fast-moving product distribution.</li>
<li className="spacer" aria-hidden="true"></li>
</ul>
</div>
) : (
<div className="solution-freight-tabs__panel active" role="tabpanel">
<ul className="point-box">
<li>AI-driven demand-responsive routing adapts delivery plans instantly based on real-time order demand.</li>
<li>Freshness-aware delivery prioritization ensures perishable products are delivered at the right time.</li>
<li>Dynamic batch optimization intelligently groups orders to maximize delivery efficiency and reduce costs.</li>
<li>Real-time inventory visibility helps prevent stockouts and improves fulfillment accuracy across delivery zones.</li>
<li className="spacer" aria-hidden="true"></li>
</ul>
</div>
)}
<div className={`ind__panel ${tab === "solutions" ? "is-active" : ""}`}>
<ul className="ind__list">
{ind.solutions.map((s, idx) => (
<li key={idx}>{s}</li>
))}
</ul>
</div>
</div>
</div>
</div>
</div>
</div>
{/* Pharma Section */}
<div style={{ marginTop: "20px" }} className="elementor-element elementor-element-89a0ca1 e-con-full e-flex cut-corner-no sticky-container-off e-con e-parent" data-id="89a0ca1" data-element_type="container" data-e-type="container">
<div className="elementor-element elementor-element-9ffed33 e-con-full e-flex cut-corner-no sticky-container-off e-con e-child" data-id="9ffed33" data-element_type="container" data-e-type="container" data-settings='{"background_background":"classic"}'>
<div className="elementor-element elementor-element-96343ba e-con-full e-flex cut-corner-no sticky-container-off e-con e-child elementor-image-section" data-id="96343ba" data-element_type="container" data-e-type="container">
<div className="elementor-element elementor-element-99768ba elementor-widget elementor-widget-image" data-id="99768ba" data-element_type="widget" data-e-type="widget" data-widget_type="image.default" style={{ width: "100%", display: "flex", alignItems: "center", justifyContent: "center" }}>
<div className="elementor-widget-container" style={{ margin: 0, width: "100%", height: "100%", display: "flex", alignItems: "center", justifyContent: "center" }}>
<Image
src="/images/tab-pic-2-solution.jpeg"
alt="Pharma Solutions"
width={578}
height={790}
style={{ maxWidth: "100%", maxHeight: "100%", objectFit: "contain" }}
/>
</div>
</div>
</div>
<div style={{ paddingRight: "60px", paddingLeft: "0px" }} className="elementor-element elementor-element-71c3e1d e-con-full e-flex cut-corner-no sticky-container-off e-con e-child" data-id="71c3e1d" data-element_type="container" data-e-type="container">
<div className="elementor-element elementor-element-fdb2e58 e-con-full e-flex cut-corner-no sticky-container-off e-con e-child" data-id="fdb2e58" data-element_type="container" data-e-type="container">
<div className="elementor-element elementor-element-7500280 elementor-widget elementor-widget-logico_heading" data-id="7500280" data-element_type="widget" data-e-type="widget" data-widget_type="logico_heading.default">
<div className="elementor-widget-container" style={{ margin: 0 }}>
<h3 className="logico-title">Pharma</h3>
</div>
</div>
<div className="elementor-element elementor-element-165dfa5 elementor-widget__width-initial elementor-widget elementor-widget-text-editor" data-id="165dfa5" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
<div className="elementor-widget-container" style={{ margin: 0, fontSize: "20px", lineHeight: 1.7 }}>
<p>Pharma logistics requires precision, compliance, and real-time monitoring to ensure every shipment reaches safely and on time. From temperature-sensitive medicines to emergency deliveries, operational reliability is critical at every stage.</p>
</div>
</div>
{/* Pharma Tabs */}
<div className="solution-freight-tabs-alt">
<div className="solution-freight-tabs__nav" role="tablist" aria-label="Pharma Details">
<button
className={`solution-freight-tabs__button ${activeTabPharma === "challenges" ? "active" : ""}`}
type="button"
role="tab"
aria-selected={activeTabPharma === "challenges"}
onClick={() => setActiveTabPharma("challenges")}
>
<h6>Challenges</h6>
</button>
<button
className={`solution-freight-tabs__button ${activeTabPharma === "solutions" ? "active" : ""}`}
type="button"
role="tab"
aria-selected={activeTabPharma === "solutions"}
onClick={() => setActiveTabPharma("solutions")}
>
<h6>Solutions</h6>
</button>
</div>
<div className="solution-freight-tabs__content">
{activeTabPharma === "challenges" ? (
<div className="solution-freight-tabs__panel active" role="tabpanel">
<ul className="point-box">
<li>Cold chain integrity requirements demand precise temperature-controlled delivery management throughout transit.</li>
<li>Regulatory compliance tracking ensures every delivery meets industry standards and operational guidelines.</li>
<li>Critical delivery time windows require highly accurate scheduling and real-time route coordination.</li>
<li>Emergency and high-priority medical shipments require instant dispatch coordination and zero-delay execution.</li>
<li className="spacer" aria-hidden="true"></li>
</ul>
</div>
) : (
<div className="solution-freight-tabs__panel active" role="tabpanel">
<ul className="point-box">
<li>Real-time temperature monitoring ensures sensitive shipments remain within safe delivery conditions at all times.</li>
<li>Chain-of-custody documentation provides complete shipment visibility and compliance tracking throughout transit.</li>
<li>Priority override for critical shipments enables faster response and immediate routing for urgent deliveries.</li>
<li>Automated compliance alerts help teams proactively identify temperature deviations and delivery risks in real time.</li>
<li className="spacer" aria-hidden="true"></li>
</ul>
</div>
)}
</div>
</div>
</div>
</div>
</div>
</div>
{/* Enterprise & B2B Section */}
<div style={{ marginTop: "20px" }} className="elementor-element elementor-element-89a0ca1 e-con-full e-flex cut-corner-no sticky-container-off e-con e-parent" data-id="89a0ca1" data-element_type="container" data-e-type="container">
<div className="elementor-element elementor-element-9ffed33 e-con-full e-flex cut-corner-no sticky-container-off e-con e-child" data-id="9ffed33" data-element_type="container" data-e-type="container" data-settings='{"background_background":"classic"}'>
<div className="elementor-element elementor-element-96343ba e-con-full e-flex cut-corner-no sticky-container-off e-con e-child elementor-image-section" data-id="96343ba" data-element_type="container" data-e-type="container">
<div className="elementor-element elementor-element-99768ba elementor-widget elementor-widget-image" data-id="99768ba" data-element_type="widget" data-e-type="widget" data-widget_type="image.default" style={{ width: "100%", display: "flex", alignItems: "center", justifyContent: "center" }}>
<div className="elementor-widget-container" style={{ margin: 0, width: "100%", height: "100%", display: "flex", alignItems: "center", justifyContent: "center" }}>
<Image
src="/images/tab-pic-3-solution.jpeg"
alt="Enterprise & B2B Solutions"
width={578}
height={790}
style={{ maxWidth: "100%", maxHeight: "100%", objectFit: "contain" }}
/>
</div>
</div>
</div>
<div className="elementor-element elementor-element-71c3e1d e-con-full e-flex cut-corner-no sticky-container-off e-con e-child section-2-content" data-id="71c3e1d" data-element_type="container" data-e-type="container">
<div className="elementor-element elementor-element-fdb2e58 e-con-full e-flex cut-corner-no sticky-container-off e-con e-child" data-id="fdb2e58" data-element_type="container" data-e-type="container">
<div className="elementor-element elementor-element-7500280 elementor-widget elementor-widget-logico_heading" data-id="7500280" data-element_type="widget" data-e-type="widget" data-widget_type="logico_heading.default">
<div className="elementor-widget-container" style={{ margin: 0 }}>
<h3 className="logico-title">Enterprise & B2B</h3>
</div>
</div>
<div className="elementor-element elementor-element-165dfa5 elementor-widget__width-initial elementor-widget elementor-widget-text-editor" data-id="165dfa5" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
<div className="elementor-widget-container" style={{ margin: 0, fontSize: "20px", lineHeight: 1.7 }}>
<p>Enterprise and B2B logistics require precision, coordination, and reliability to manage high-value shipments at scale. Complex delivery expectations, appointment scheduling, and service-level commitments demand intelligent operational control.</p>
</div>
</div>
{/* Enterprise & B2B Tabs */}
<div className="solution-freight-tabs-alt">
<div className="solution-freight-tabs__nav" role="tablist" aria-label="B2B Details">
<button
className={`solution-freight-tabs__button ${activeTabB2b === "challenges" ? "active" : ""}`}
type="button"
role="tab"
aria-selected={activeTabB2b === "challenges"}
onClick={() => setActiveTabB2b("challenges")}
>
<h6>Challenges</h6>
</button>
<button
className={`solution-freight-tabs__button ${activeTabB2b === "solutions" ? "active" : ""}`}
type="button"
role="tab"
aria-selected={activeTabB2b === "solutions"}
onClick={() => setActiveTabB2b("solutions")}
>
<h6>Solutions</h6>
</button>
</div>
<div className="solution-freight-tabs__content">
{activeTabB2b === "challenges" ? (
<div className="solution-freight-tabs__panel active" role="tabpanel">
<ul className="point-box">
<li>Appointment scheduling coordination requires precise timing and seamless delivery planning across multiple customer locations.</li>
<li>White-glove delivery standards demand high-quality handling, accuracy, and premium customer service execution.</li>
<li>Multi-location routing complexity increases operational challenges in managing efficient large-scale deliveries.</li>
<li>Strict SLA commitments increase pressure on teams to maintain timely and error-free deliveries across multiple locations.</li>
<li className="spacer" aria-hidden="true"></li>
</ul>
</div>
) : (
<div className="solution-freight-tabs__panel active" role="tabpanel">
<ul className="point-box">
<li>Automated appointment optimization streamlines delivery scheduling for faster and more efficient operations.</li>
<li>Service level guarantee tracking ensures every delivery meets committed SLA and customer expectations.</li>
<li>Enterprise integration APIs enable seamless connectivity across logistics, warehouse, and business systems.</li>
<li>Real-time SLA monitoring helps teams proactively manage delays and maintain enterprise delivery commitments.</li>
<li className="spacer" aria-hidden="true"></li>
</ul>
</div>
)}
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
</>
);
}

View File

@@ -1,9 +1,196 @@
import React from "react";
import Image from "next/image";
import { ScrollReveal, StaggerChildren } from "@/animations/Reveal";
import IndustryWorldMap from "./IndustryWorldMap";
const WS_STATS = [
{ value: "500", plus: "+", label: "Women Partners" },
{ value: "35", plus: "+", label: "Cities" },
{ value: "10K", plus: "+", label: "Deliveries" },
];
const WS_CARDS = [
{
title: "Women Leadership",
desc: "Women driving decisions across operations, routing, and last-mile delivery every day.",
icon: (
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round">
<circle cx="12" cy="9" r="5" />
<path d="M9 13.5 7.5 21 12 18l4.5 3-1.5-7.5" />
</svg>
),
},
{
title: "Entrepreneurship",
desc: "Enabling women to build, own, and scale their own delivery businesses.",
icon: (
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round">
<rect x="3" y="7" width="18" height="13" rx="2" />
<path d="M8 7V5a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2M3 12h18" />
</svg>
),
},
{
title: "Innovation",
desc: "Fresh thinking that reshapes how first and last-mile logistics actually work.",
icon: (
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round">
<path d="M9 18h6M10 21h4" />
<path d="M12 3a6 6 0 0 0-3.8 10.6c.5.5.8 1.2.8 1.9v.5h6v-.5c0-.7.3-1.4.8-1.9A6 6 0 0 0 12 3Z" />
</svg>
),
},
{
title: "Community Growth",
desc: "Local hiring and training that lifts entire neighbourhoods, not just routes.",
icon: (
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round">
<circle cx="9" cy="8" r="3" />
<path d="M3.5 20c0-3 2.5-5 5.5-5s5.5 2 5.5 5M16 5.5a3 3 0 0 1 0 5.8M20.5 20c0-2.3-1.4-3.9-3.3-4.6" />
</svg>
),
},
];
export default function WomenSection() {
return (
<div className="elementor-element elementor-element-bbc6760 e-con-full e-flex cut-corner-no sticky-container-off e-con e-parent" data-id="bbc6760" data-element_type="container" data-e-type="container">
<>
<style dangerouslySetInnerHTML={{ __html: `
/* ============================================================
Success Stories — redesigned right column (stats + 2x2 cards)
Dark section · red accent #dc2626 / #ef4444 · Manrope
============================================================ */
/* Neutralise the right column's asymmetric 140px left padding so the
box group can be centered instead of pushed to one side. */
.elementor-element.elementor-element-b2c956f { padding: 0 !important; }
/* Vertically center the two columns so the right content lines up with
the image instead of needing a big top gap; tighten row gap. */
.elementor-element.elementor-element-2ed47f3 { align-items: center !important; }
/* Animated map background behind the Success Stories content */
.elementor-element.elementor-element-b6e14bd { position: relative; overflow: hidden; }
.elementor-element.elementor-element-b6e14bd > .e-con-inner { position: relative; z-index: 1; }
.ws-map { position: absolute; inset: 0; z-index: 0; opacity: 0.5; pointer-events: none; }
.ws-map canvas { display: block; }
#ws-stories {
display: flex;
flex-direction: column;
gap: 16px;
width: 100%;
max-width: 620px;
margin: 0 auto; /* center the 7 boxes as a group — no negative margins */
}
#ws-stories .ws__stats {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 12px;
}
#ws-stories .ws__stat {
background: rgba(255,255,255,0.04);
border: 1px solid rgba(255,255,255,0.08);
border-radius: 14px;
padding: 20px 16px;
transition: border-color 0.3s ease, background-color 0.3s ease;
}
#ws-stories .ws__stat:hover { border-color: rgba(220,38,38,0.28); background: rgba(220,38,38,0.05); }
#ws-stories .ws__stat-num {
color: #fff !important;
font-weight: 900;
font-size: clamp(28px, 3vw, 38px);
line-height: 1;
letter-spacing: -0.01em;
}
#ws-stories .ws__stat-num span { color: #dc2626 !important; }
#ws-stories .ws__stat-label {
margin-top: 9px;
color: rgba(255,255,255,0.7) !important;
font-size: 14px !important;
font-weight: 700;
letter-spacing: 0.03em;
text-transform: uppercase;
}
#ws-stories .ws__cards {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 14px;
}
#ws-stories .ws__card {
position: relative;
overflow: hidden;
background: rgba(255,255,255,0.035);
border: 1px solid rgba(255,255,255,0.08);
border-radius: 16px;
padding: 22px 20px;
transition: transform 0.35s cubic-bezier(.25,1,.5,1), border-color 0.35s ease, background-color 0.35s ease, box-shadow 0.35s ease;
}
#ws-stories .ws__card::after {
content: '';
position: absolute;
top: -45%; left: -25%;
width: 150px; height: 150px;
background: radial-gradient(circle, rgba(220,38,38,0.2), transparent 70%);
opacity: 0;
transition: opacity 0.35s ease;
pointer-events: none;
}
#ws-stories .ws__card:hover {
transform: translateY(-4px);
border-color: rgba(220,38,38,0.3);
background: rgba(220,38,38,0.05);
box-shadow: 0 18px 44px -20px rgba(0,0,0,0.7);
}
#ws-stories .ws__card:hover::after { opacity: 1; }
#ws-stories .ws__card-icon {
display: inline-flex;
align-items: center;
justify-content: center;
width: 44px; height: 44px;
border-radius: 12px;
background: rgba(220,38,38,0.12);
border: 1px solid rgba(220,38,38,0.25);
color: #ef4444;
margin-bottom: 14px;
transition: background-color 0.3s ease, color 0.3s ease;
}
#ws-stories .ws__card:hover .ws__card-icon { background: #dc2626; color: #fff; }
#ws-stories .ws__card-icon svg { width: 22px; height: 22px; }
#ws-stories .ws__card-title {
color: #fff !important;
font-weight: 900;
font-size: 17px;
letter-spacing: -0.01em;
margin-bottom: 8px;
}
#ws-stories .ws__card-desc {
color: rgba(255,255,255,0.6) !important;
font-size: 13.5px;
line-height: 1.6;
margin: 0;
font-weight: 900;
font-family: 'Manrope', sans-serif;
font-size: 16px;
}
/* Stack the two columns below the desktop breakpoint so the box group
always gets full width and stays centered — never clipped. */
@media (max-width: 1024px) {
.elementor-element.elementor-element-2ed47f3 { grid-template-columns: 1fr !important; }
#ws-stories { max-width: 640px; margin: 0 auto; }
}
@media (max-width: 600px) {
#ws-stories .ws__stats { grid-template-columns: 1fr 1fr 1fr; gap: 8px; }
#ws-stories .ws__stat { padding: 14px 10px; }
#ws-stories .ws__stat-label { font-size: 11px !important; letter-spacing: 0.02em; }
#ws-stories .ws__cards { grid-template-columns: 1fr; }
}
`}} />
<div className="elementor-element elementor-element-bbc6760 e-con-full e-flex cut-corner-no sticky-container-off e-con e-parent" data-id="bbc6760" data-element_type="container" data-e-type="container" style={{ backgroundColor: "#1f1f1f", width: "calc(100% - 40px)", marginLeft: "20px", marginRight: "20px", borderRadius: "25px", overflow: "hidden" }}>
<div
className="elementor-element elementor-element-13a7637 elementor-widget__width-auto elementor-absolute elementor-widget elementor-widget-logico_decorative_block"
data-id="13a7637"
@@ -65,6 +252,9 @@ export default function WomenSection() {
</div>
<div className="elementor-element elementor-element-b6e14bd e-flex e-con-boxed cut-corner-no sticky-container-off e-con e-child" data-id="b6e14bd" data-element_type="container" data-e-type="container" data-settings='{"background_background":"classic"}'>
<div className="ws-map" aria-hidden="true">
<IndustryWorldMap />
</div>
<div className="e-con-inner">
<div className="elementor-element elementor-element-90cc867 e-con-full e-flex cut-corner-no sticky-container-off e-con e-child" data-id="90cc867" data-element_type="container" data-e-type="container">
<div className="elementor-element elementor-element-24c0280 elementor-widget__width-inherit elementor-widget elementor-widget-logico_heading" data-id="24c0280" data-element_type="widget" data-e-type="widget" data-widget_type="logico_heading.default">
@@ -75,11 +265,13 @@ export default function WomenSection() {
<div className="elementor-element elementor-element-2ed47f3 e-con-full e-grid cut-corner-no sticky-container-off e-con e-child" data-id="2ed47f3" data-element_type="container" data-e-type="container">
<div className="elementor-element elementor-element-36efec7 e-con-full e-flex cut-corner-no sticky-container-off e-con e-child" data-id="36efec7" data-element_type="container" data-e-type="container">
<div className="elementor-element elementor-element-778840d elementor-widget elementor-widget-logico_heading" data-id="778840d" data-element_type="widget" data-e-type="widget" data-widget_type="logico_heading.default">
<div className="elementor-widget-container">
<h3 className="logico-title">Women Leading the Way</h3>
<ScrollReveal duration={0.8} yOffset={28} triggerOnce>
<div className="elementor-element elementor-element-778840d elementor-widget elementor-widget-logico_heading" data-id="778840d" data-element_type="widget" data-e-type="widget" data-widget_type="logico_heading.default">
<div className="elementor-widget-container">
<h3 className="logico-title">Women Leading the Way</h3>
</div>
</div>
</div>
</ScrollReveal>
<div className="elementor-element elementor-element-bbfb67f elementor-widget elementor-widget-image" data-id="bbfb67f" data-element_type="widget" data-e-type="widget" data-widget_type="image.default">
<div className="elementor-widget-container">
<Image
@@ -94,108 +286,32 @@ export default function WomenSection() {
</div>
<div className="elementor-element elementor-element-b2c956f e-con-full e-flex cut-corner-no sticky-container-off e-con e-child" data-id="b2c956f" data-element_type="container" data-e-type="container">
<div
className="elementor-element elementor-element-1a450c2 elementor-absolute elementor-widget elementor-widget-image"
data-id="1a450c2"
data-element_type="widget"
data-e-type="widget"
style={{ position: "absolute" }}
>
<div className="elementor-widget-container">
<Image
src="/images/bg-map.png"
alt="World Map"
width={965}
height={474}
style={{ width: "100%", height: "auto" }}
/>
</div>
</div>
{/* Card 1 */}
<div className="elementor-element elementor-element-6b51278 elementor-view-stacked elementor-position-inline-start elementor-shape-circle elementor-widget elementor-widget-icon-box" data-id="6b51278" data-element_type="widget" data-e-type="widget" data-widget_type="icon-box.default">
<div className="elementor-widget-container">
<div className="elementor-icon-box-wrapper">
<div className="elementor-icon-box-icon">
<span className="elementor-icon">
<i aria-hidden="true" className="fontello icon-arrow-x-r-top"></i>
</span>
<div id="ws-stories">
<StaggerChildren className="ws__stats" stagger={0.1} duration={0.6} yOffset={20} triggerOnce>
{WS_STATS.map((s) => (
<div className="ws__stat" key={s.label}>
<div className="ws__stat-num">{s.value}<span>{s.plus}</span></div>
<div className="ws__stat-label">{s.label}</div>
</div>
<div className="elementor-icon-box-content">
<div className="elementor-icon-box-title">
<span>Women Entrepreneurship</span>
</div>
<p className="elementor-icon-box-description">
Empowering women to lead, manage, and grow in modern logistics operations.
</p>
</div>
</div>
</div>
</div>
))}
</StaggerChildren>
<div className="elementor-element elementor-element-e34beb2 elementor-widget-divider--view-line elementor-widget elementor-widget-divider" data-id="e34beb2" data-element_type="widget" data-e-type="widget" data-widget_type="divider.default">
<div className="elementor-widget-container">
<div className="elementor-divider">
<span className="elementor-divider-separator"></span>
</div>
</div>
</div>
{/* Card 2 */}
<div className="elementor-element elementor-element-27ba815 elementor-view-stacked elementor-position-inline-start elementor-shape-circle elementor-widget elementor-widget-icon-box" data-id="27ba815" data-element_type="widget" data-e-type="widget" data-widget_type="icon-box.default">
<div className="elementor-widget-container">
<div className="elementor-icon-box-wrapper">
<div className="elementor-icon-box-icon">
<span className="elementor-icon">
<i aria-hidden="true" className="fontello icon-arrow-x-r-top"></i>
</span>
<StaggerChildren className="ws__cards" stagger={0.08} duration={0.6} yOffset={24} triggerOnce>
{WS_CARDS.map((c) => (
<div className="ws__card" key={c.title}>
<span className="ws__card-icon" aria-hidden="true">{c.icon}</span>
<div className="ws__card-title">{c.title}</div>
<p className="ws__card-desc">{c.desc}</p>
</div>
<div className="elementor-icon-box-content">
<div className="elementor-icon-box-title">
<span>Leadership in Logistics</span>
</div>
<p className="elementor-icon-box-description">
Creating opportunities for women to drive innovation in last-mile delivery.
</p>
</div>
</div>
</div>
))}
</StaggerChildren>
</div>
<div className="elementor-element elementor-element-6895eb5 elementor-widget-divider--view-line elementor-widget elementor-widget-divider" data-id="6895eb5" data-element_type="widget" data-e-type="widget" data-widget_type="divider.default">
<div className="elementor-widget-container">
<div className="elementor-divider">
<span className="elementor-divider-separator"></span>
</div>
</div>
</div>
{/* Card 3 */}
<div className="elementor-element elementor-element-332c78f elementor-view-stacked elementor-position-inline-start elementor-shape-circle elementor-widget elementor-widget-icon-box" data-id="332c78f" data-element_type="widget" data-e-type="widget" data-widget_type="icon-box.default">
<div className="elementor-widget-container">
<div className="elementor-icon-box-wrapper">
<div className="elementor-icon-box-icon">
<span className="elementor-icon">
<i aria-hidden="true" className="fontello icon-arrow-x-r-top"></i>
</span>
</div>
<div className="elementor-icon-box-content">
<div className="elementor-icon-box-title">
<span>Stronger Together</span>
</div>
<p className="elementor-icon-box-description">
Building a future where women power smarter, faster, and reliable logistics.
</p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</>
);
}