update home,about,solutions
This commit is contained in:
@@ -1932,10 +1932,10 @@ h1:where(.wp-block-heading).has-background,
|
|||||||
--container-widget-flex-grow: 0;
|
--container-widget-flex-grow: 0;
|
||||||
--container-widget-align-self: initial;
|
--container-widget-align-self: initial;
|
||||||
--flex-wrap-mobile: wrap;
|
--flex-wrap-mobile: wrap;
|
||||||
--padding-top: 20px;
|
--padding-top: 32px;
|
||||||
--padding-bottom: 20px;
|
--padding-bottom: 32px;
|
||||||
--padding-left: 20px;
|
--padding-left: 32px;
|
||||||
--padding-right: 20px;
|
--padding-right: 32px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.elementor .elementor-element.elementor-element-6c7cbcb .elementor-repeater-item-3264830 {
|
.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 {
|
.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,
|
.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 {
|
.elementor-61 .elementor-element.elementor-element-6c7cbcb .elementor-repeater-item-6867061 .slide-content-inner {
|
||||||
max-width: 64%;
|
max-width: 88%;
|
||||||
margin: 110px 0px 0px 75px;
|
margin: 0 auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.elementor-61 .elementor-element.elementor-element-6c7cbcb .elementor-repeater-item-6867061 .slide-content {
|
.elementor-61 .elementor-element.elementor-element-6c7cbcb .elementor-repeater-item-6867061 .slide-content {
|
||||||
-webkit-align-items: flex-start;
|
-webkit-align-items: center;
|
||||||
-moz-align-items: flex-start;
|
-moz-align-items: center;
|
||||||
-ms-align-items: flex-start;
|
-ms-align-items: center;
|
||||||
align-items: flex-start;
|
align-items: center;
|
||||||
-webkit-justify-content: center;
|
-webkit-justify-content: center;
|
||||||
-moz-justify-content: center;
|
-moz-justify-content: center;
|
||||||
-ms-justify-content: center;
|
-ms-justify-content: center;
|
||||||
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 {
|
.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-bottom: 0px;
|
||||||
--margin-left: 0px;
|
--margin-left: 0px;
|
||||||
--margin-right: 0px;
|
--margin-right: 0px;
|
||||||
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
.elementor-element.elementor-element-f35119c {
|
.elementor-element.elementor-element-f35119c {
|
||||||
@@ -28753,8 +28754,8 @@ img.wp-smiley,
|
|||||||
--margin-right: 0px;
|
--margin-right: 0px;
|
||||||
--padding-top: 0px;
|
--padding-top: 0px;
|
||||||
--padding-bottom: 0px;
|
--padding-bottom: 0px;
|
||||||
--padding-left: 20px;
|
--padding-left: 0px;
|
||||||
--padding-right: 20px;
|
--padding-right: 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.elementor-element.elementor-element-13a7637 {
|
.elementor-element.elementor-element-13a7637 {
|
||||||
@@ -38655,11 +38656,13 @@ body.rtl .elementor-6473 .elementor-element.elementor-element-13a7637 {
|
|||||||
--column-gap: 0px;
|
--column-gap: 0px;
|
||||||
--background-transition: 0s;
|
--background-transition: 0s;
|
||||||
--border-radius: 25px 25px 25px 25px;
|
--border-radius: 25px 25px 25px 25px;
|
||||||
|
border-radius: 25px;
|
||||||
|
overflow: hidden;
|
||||||
--z-index: 1;
|
--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 {
|
.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-position: center center;
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
background-size: cover;
|
background-size: cover;
|
||||||
|
|||||||
4
public/css/vendor/vendor-theme-core.css
vendored
4
public/css/vendor/vendor-theme-core.css
vendored
@@ -16806,7 +16806,7 @@ html.elementor-html {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* .team-listing-wrapper.team-grid-listing {
|
.team-listing-wrapper.team-grid-listing {
|
||||||
display: block;
|
display: block;
|
||||||
margin: 0 -10px -20px
|
margin: 0 -10px -20px
|
||||||
}
|
}
|
||||||
@@ -17060,7 +17060,7 @@ html.elementor-html {
|
|||||||
padding: 0 22px;
|
padding: 0 22px;
|
||||||
margin-bottom: 78px
|
margin-bottom: 78px
|
||||||
}
|
}
|
||||||
} */
|
}
|
||||||
|
|
||||||
.body-container .single-team {
|
.body-container .single-team {
|
||||||
display: -webkit-box;
|
display: -webkit-box;
|
||||||
|
|||||||
@@ -19,6 +19,11 @@ export default function AnimationProvider({ children }: { children: React.ReactN
|
|||||||
duration: 0.8,
|
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 = () => {
|
const initDecorativeBlocks = () => {
|
||||||
// Clean up previous block triggers to avoid duplicates
|
// Clean up previous block triggers to avoid duplicates
|
||||||
ScrollTrigger.getAll().forEach((t) => {
|
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");
|
const decorativeBlocks = document.querySelectorAll(".block-decoration");
|
||||||
decorativeBlocks.forEach((block) => {
|
decorativeBlocks.forEach((block) => {
|
||||||
ScrollTrigger.create({
|
ScrollTrigger.create({
|
||||||
@@ -50,6 +56,14 @@ export default function AnimationProvider({ children }: { children: React.ReactN
|
|||||||
block.classList.remove("animated");
|
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);
|
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 = () => {
|
const handleResize = () => {
|
||||||
initDecorativeBlocks();
|
clearTimeout(resizeTimer);
|
||||||
ScrollTrigger.refresh(true);
|
resizeTimer = setTimeout(() => {
|
||||||
|
initDecorativeBlocks();
|
||||||
|
ScrollTrigger.refresh(true);
|
||||||
|
}, 200);
|
||||||
};
|
};
|
||||||
window.addEventListener("resize", handleResize);
|
window.addEventListener("resize", handleResize);
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
timeouts.forEach(clearTimeout);
|
timeouts.forEach(clearTimeout);
|
||||||
|
clearTimeout(resizeTimer);
|
||||||
window.removeEventListener("load", handleLoad);
|
window.removeEventListener("load", handleLoad);
|
||||||
window.removeEventListener("resize", handleResize);
|
window.removeEventListener("resize", handleResize);
|
||||||
ScrollTrigger.getAll().forEach((t) => t.kill());
|
ScrollTrigger.getAll().forEach((t) => t.kill());
|
||||||
|
|||||||
@@ -9,6 +9,71 @@ if (typeof window !== "undefined") {
|
|||||||
gsap.registerPlugin(ScrollTrigger);
|
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
|
1. ScrollReveal
|
||||||
Fade-in + slide-up on scroll. The workhorse animation.
|
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 });
|
gsap.set(el, { y: yOffset, x: xOffset, opacity: 0 });
|
||||||
|
|
||||||
const trigger = ScrollTrigger.create({
|
const show = () =>
|
||||||
trigger: el,
|
gsap.to(el, {
|
||||||
start: "top 88%",
|
y: 0,
|
||||||
onEnter: (self) => {
|
x: 0,
|
||||||
gsap.to(el, {
|
opacity: 1,
|
||||||
y: 0,
|
duration,
|
||||||
x: 0,
|
ease: "power3.out",
|
||||||
opacity: 1,
|
delay,
|
||||||
duration,
|
overwrite: "auto",
|
||||||
ease: "power3.out",
|
});
|
||||||
delay,
|
const hide = () => gsap.set(el, { y: yOffset, x: xOffset, opacity: 0 });
|
||||||
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 });
|
|
||||||
}
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
return () => trigger?.kill();
|
return createRevealTrigger({ trigger: el, show, hide, triggerOnce });
|
||||||
}, [delay, duration, yOffset, xOffset, triggerOnce]);
|
}, [delay, duration, yOffset, xOffset, triggerOnce]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -122,47 +159,19 @@ export function RevealText({
|
|||||||
|
|
||||||
gsap.set(items, { y: "110%", opacity: 0 });
|
gsap.set(items, { y: "110%", opacity: 0 });
|
||||||
|
|
||||||
const trigger = ScrollTrigger.create({
|
const show = () =>
|
||||||
trigger: el,
|
gsap.to(items, {
|
||||||
start: "top 88%",
|
y: "0%",
|
||||||
onEnter: (self) => {
|
opacity: 1,
|
||||||
gsap.to(items, {
|
duration,
|
||||||
y: "0%",
|
ease: "power4.out",
|
||||||
opacity: 1,
|
stagger: type === "chars" ? 0.02 : 0.04,
|
||||||
duration,
|
delay,
|
||||||
ease: "power4.out",
|
overwrite: "auto",
|
||||||
stagger: type === "chars" ? 0.02 : 0.04,
|
});
|
||||||
delay,
|
const hide = () => gsap.set(items, { y: "110%", opacity: 0 });
|
||||||
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 });
|
|
||||||
}
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
return () => trigger?.kill();
|
return createRevealTrigger({ trigger: el, show, hide, triggerOnce });
|
||||||
}, [children, type, delay, duration, triggerOnce]);
|
}, [children, type, delay, duration, triggerOnce]);
|
||||||
|
|
||||||
const renderContent = () => {
|
const renderContent = () => {
|
||||||
@@ -290,45 +299,18 @@ export function StaggerChildren({
|
|||||||
|
|
||||||
gsap.set(items, { y: yOffset, opacity: 0 });
|
gsap.set(items, { y: yOffset, opacity: 0 });
|
||||||
|
|
||||||
const trigger = ScrollTrigger.create({
|
const show = () =>
|
||||||
trigger: el,
|
gsap.to(items, {
|
||||||
start: "top 85%",
|
y: 0,
|
||||||
onEnter: (self) => {
|
opacity: 1,
|
||||||
gsap.to(items, {
|
duration,
|
||||||
y: 0,
|
ease: "power3.out",
|
||||||
opacity: 1,
|
stagger,
|
||||||
duration,
|
overwrite: "auto",
|
||||||
ease: "power3.out",
|
});
|
||||||
stagger,
|
const hide = () => gsap.set(items, { y: yOffset, opacity: 0 });
|
||||||
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 });
|
|
||||||
}
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
return () => trigger?.kill();
|
return createRevealTrigger({ trigger: el, start: "top 85%", show, hide, triggerOnce });
|
||||||
}, [stagger, duration, yOffset, triggerOnce]);
|
}, [stagger, duration, yOffset, triggerOnce]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -365,45 +347,18 @@ export function ScaleReveal({
|
|||||||
|
|
||||||
gsap.set(el, { scale: 0.85, opacity: 0 });
|
gsap.set(el, { scale: 0.85, opacity: 0 });
|
||||||
|
|
||||||
const trigger = ScrollTrigger.create({
|
const show = () =>
|
||||||
trigger: el,
|
gsap.to(el, {
|
||||||
start: "top 88%",
|
scale: 1,
|
||||||
onEnter: (self) => {
|
opacity: 1,
|
||||||
gsap.to(el, {
|
duration,
|
||||||
scale: 1,
|
ease: "power3.out",
|
||||||
opacity: 1,
|
delay,
|
||||||
duration,
|
overwrite: "auto",
|
||||||
ease: "power3.out",
|
});
|
||||||
delay,
|
const hide = () => gsap.set(el, { scale: 0.85, opacity: 0 });
|
||||||
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 });
|
|
||||||
}
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
return () => trigger?.kill();
|
return createRevealTrigger({ trigger: el, show, hide, triggerOnce });
|
||||||
}, [delay, duration, triggerOnce]);
|
}, [delay, duration, triggerOnce]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -443,45 +398,18 @@ export function SlideReveal({
|
|||||||
const xStart = direction === "left" ? -60 : 60;
|
const xStart = direction === "left" ? -60 : 60;
|
||||||
gsap.set(el, { x: xStart, opacity: 0 });
|
gsap.set(el, { x: xStart, opacity: 0 });
|
||||||
|
|
||||||
const trigger = ScrollTrigger.create({
|
const show = () =>
|
||||||
trigger: el,
|
gsap.to(el, {
|
||||||
start: "top 88%",
|
x: 0,
|
||||||
onEnter: (self) => {
|
opacity: 1,
|
||||||
gsap.to(el, {
|
duration,
|
||||||
x: 0,
|
ease: "power3.out",
|
||||||
opacity: 1,
|
delay,
|
||||||
duration,
|
overwrite: "auto",
|
||||||
ease: "power3.out",
|
});
|
||||||
delay,
|
const hide = () => gsap.set(el, { x: xStart, opacity: 0 });
|
||||||
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 });
|
|
||||||
}
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
return () => trigger?.kill();
|
return createRevealTrigger({ trigger: el, show, hide, triggerOnce });
|
||||||
}, [direction, delay, duration, triggerOnce]);
|
}, [direction, delay, duration, triggerOnce]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -573,43 +501,18 @@ export function CountUp({
|
|||||||
const el = elementRef.current;
|
const el = elementRef.current;
|
||||||
if (!el) return;
|
if (!el) return;
|
||||||
|
|
||||||
const trigger = ScrollTrigger.create({
|
const show = () => {
|
||||||
trigger: el,
|
const obj = { val: start };
|
||||||
start: "top 90%",
|
gsap.to(obj, {
|
||||||
onEnter: (self) => {
|
val: end,
|
||||||
const obj = { val: start };
|
duration,
|
||||||
gsap.to(obj, {
|
ease: "power2.out",
|
||||||
val: end,
|
onUpdate: () => setValue(obj.val),
|
||||||
duration,
|
});
|
||||||
ease: "power2.out",
|
};
|
||||||
onUpdate: () => setValue(obj.val),
|
const hide = () => setValue(start);
|
||||||
});
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
return () => trigger?.kill();
|
return createRevealTrigger({ trigger: el, start: "top 90%", show, hide, triggerOnce });
|
||||||
}, [start, end, duration, triggerOnce]);
|
}, [start, end, duration, triggerOnce]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -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-wrapper content-wrapper-may-contain-elementor-code content-wrapper-sidebar-position-none">
|
||||||
<div className="content">
|
<div className="content">
|
||||||
<div className="content-inner">
|
<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 />
|
<AboutHero />
|
||||||
<TheDoormileWay />
|
<TheDoormileWay />
|
||||||
<EVLogisticSection />
|
<EVLogisticSection />
|
||||||
|
|||||||
@@ -767,7 +767,7 @@ body {
|
|||||||
content: '' !important;
|
content: '' !important;
|
||||||
position: absolute !important;
|
position: absolute !important;
|
||||||
inset: 0 !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;
|
z-index: 1 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -777,6 +777,13 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Responsive constraints to keep all heroes matching the home page carousel perfectly */
|
/* 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) {
|
@media (max-width: 1024px) {
|
||||||
.custom-standard-hero-container {
|
.custom-standard-hero-container {
|
||||||
padding: 10px 10px 10px 10px !important;
|
padding: 10px 10px 10px 10px !important;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import type { Metadata } from "next";
|
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 "./globals.css";
|
||||||
import Header from "@/components/layout/Header";
|
import Header from "@/components/layout/Header";
|
||||||
import Footer from "@/components/layout/Footer";
|
import Footer from "@/components/layout/Footer";
|
||||||
@@ -21,6 +21,19 @@ const spaceGrotesk = Space_Grotesk({
|
|||||||
weight: ["400", "500", "600", "700"],
|
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 = {
|
export const metadata: Metadata = {
|
||||||
title: "Doormile — Last-Mile Logistics Intelligence",
|
title: "Doormile — Last-Mile Logistics Intelligence",
|
||||||
description: "Doormile powers last-mile logistics with MileTruth™ AI, providing connected miles, SLA protection, and carrier management.",
|
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;
|
children: React.ReactNode;
|
||||||
}>) {
|
}>) {
|
||||||
return (
|
return (
|
||||||
<html lang="en-US" className={`${manrope.variable} ${spaceGrotesk.variable}`}>
|
<html lang="en-US" className={`${manrope.variable} ${spaceGrotesk.variable} ${syne.variable} ${dmSans.variable}`}>
|
||||||
<head>
|
<head>
|
||||||
{/* FontAwesome icons */}
|
{/* FontAwesome icons */}
|
||||||
<link
|
<link
|
||||||
|
|||||||
@@ -515,6 +515,19 @@ export default function Header() {
|
|||||||
background-color: #ffffff !important;
|
background-color: #ffffff !important;
|
||||||
opacity: 1 !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;
|
||||||
|
}
|
||||||
|
}
|
||||||
`,
|
`,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -8,18 +8,18 @@ export default function AboutHero() {
|
|||||||
width: 100% !important;
|
width: 100% !important;
|
||||||
text-align: center !important;
|
text-align: center !important;
|
||||||
color: #fff !important;
|
color: #fff !important;
|
||||||
padding: 60px 40px !important;
|
padding: 60px 40px 100px 40px !important;
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
display: flex !important;
|
display: flex !important;
|
||||||
flex-direction: column !important;
|
flex-direction: column !important;
|
||||||
justify-content: center !important;
|
justify-content: flex-end !important;
|
||||||
align-items: center !important;
|
align-items: center !important;
|
||||||
height: 100% !important;
|
height: 100% !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.about-us-hero-title {
|
.about-us-hero-title {
|
||||||
margin: 0 !important;
|
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-size: clamp(34px, 5.5vw, 68px) !important;
|
||||||
font-weight: 850 !important;
|
font-weight: 850 !important;
|
||||||
line-height: 1.1 !important;
|
line-height: 1.1 !important;
|
||||||
@@ -33,7 +33,8 @@ export default function AboutHero() {
|
|||||||
<div className="custom-standard-hero-container">
|
<div className="custom-standard-hero-container">
|
||||||
<div
|
<div
|
||||||
style={{
|
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"
|
className="custom-standard-hero-card"
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -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() {
|
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 (
|
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="container">
|
||||||
<div className="comparison-layout">
|
<div className="comparison-layout">
|
||||||
{/* Comparison matrix Table */}
|
{/* Comparison Matrix Table (69% on Desktop) */}
|
||||||
<div className="table-wrapper">
|
<div className="table-wrapper" ref={tableWrapperRef}>
|
||||||
<table className="comparison-table">
|
<table className="comparison-table">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
@@ -20,7 +89,7 @@ export default function CompetitiveEdge() {
|
|||||||
<tbody>
|
<tbody>
|
||||||
<tr className="table-row-hover">
|
<tr className="table-row-hover">
|
||||||
<td className="capability-cell">
|
<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>
|
<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>
|
<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>
|
<circle cx="5.5" cy="18.5" r="2.5"></circle>
|
||||||
@@ -35,7 +104,7 @@ export default function CompetitiveEdge() {
|
|||||||
</tr>
|
</tr>
|
||||||
<tr className="table-row-hover">
|
<tr className="table-row-hover">
|
||||||
<td className="capability-cell">
|
<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 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>
|
<path d="M12 6v6l4 2"></path>
|
||||||
</svg>
|
</svg>
|
||||||
@@ -48,7 +117,7 @@ export default function CompetitiveEdge() {
|
|||||||
</tr>
|
</tr>
|
||||||
<tr className="table-row-hover">
|
<tr className="table-row-hover">
|
||||||
<td className="capability-cell">
|
<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>
|
<polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"></polygon>
|
||||||
</svg>
|
</svg>
|
||||||
EV-aware planning
|
EV-aware planning
|
||||||
@@ -60,8 +129,8 @@ export default function CompetitiveEdge() {
|
|||||||
</tr>
|
</tr>
|
||||||
<tr className="table-row-hover">
|
<tr className="table-row-hover">
|
||||||
<td className="capability-cell">
|
<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="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h32a2 2 0 0 0 2-2V8z"></path>
|
<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>
|
<polyline points="14 2 14 8 20 8"></polyline>
|
||||||
<line x1="16" y1="13" x2="8" y2="13"></line>
|
<line x1="16" y1="13" x2="8" y2="13"></line>
|
||||||
<line x1="16" y1="17" x2="8" y2="17"></line>
|
<line x1="16" y1="17" x2="8" y2="17"></line>
|
||||||
@@ -76,7 +145,7 @@ export default function CompetitiveEdge() {
|
|||||||
</tr>
|
</tr>
|
||||||
<tr className="table-row-hover">
|
<tr className="table-row-hover">
|
||||||
<td className="capability-cell">
|
<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>
|
<circle cx="12" cy="12" r="10"></circle>
|
||||||
<polyline points="12 6 12 12 16 14"></polyline>
|
<polyline points="12 6 12 12 16 14"></polyline>
|
||||||
</svg>
|
</svg>
|
||||||
@@ -89,20 +158,20 @@ export default function CompetitiveEdge() {
|
|||||||
</tr>
|
</tr>
|
||||||
<tr className="table-row-hover">
|
<tr className="table-row-hover">
|
||||||
<td className="capability-cell">
|
<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>
|
<path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"></path>
|
||||||
</svg>
|
</svg>
|
||||||
Verified handling
|
Verified handling
|
||||||
</td>
|
</td>
|
||||||
<td className="col-highlight"><span className="yes-badge">✓ Yes</span></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="partial-text">Partial</td>
|
||||||
<td className="no-text">No</td>
|
<td className="no-text">No</td>
|
||||||
|
<td className="no-text">No</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr className="table-row-hover">
|
<tr className="table-row-hover">
|
||||||
<td className="capability-cell">
|
<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="M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h38s-3-2-3-9"></path>
|
<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>
|
<path d="M13.73 21a2 2 0 0 1-3.46 0"></path>
|
||||||
</svg>
|
</svg>
|
||||||
Hyperlocal learning
|
Hyperlocal learning
|
||||||
@@ -114,7 +183,7 @@ export default function CompetitiveEdge() {
|
|||||||
</tr>
|
</tr>
|
||||||
<tr className="table-row-hover">
|
<tr className="table-row-hover">
|
||||||
<td className="capability-cell">
|
<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>
|
<circle cx="12" cy="12" r="10"></circle>
|
||||||
<line x1="22" y1="12" x2="18" y2="12"></line>
|
<line x1="22" y1="12" x2="18" y2="12"></line>
|
||||||
<line x1="6" y1="12" x2="2" y2="12"></line>
|
<line x1="6" y1="12" x2="2" y2="12"></line>
|
||||||
@@ -132,20 +201,379 @@ export default function CompetitiveEdge() {
|
|||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Strategic Moat Side cards */}
|
{/* Moat Highlight Card (28% on Desktop) */}
|
||||||
<div className="moat-panel">
|
<div className="moat-panel" ref={moatRef}>
|
||||||
<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="moat-accent-line" />
|
||||||
<div className="elementor-widget-container">
|
<div className="advantage-badge">DoorMile Advantage</div>
|
||||||
<div className="section-header">
|
<h3 className="moat-heading">WHERE DOORMILE SITS AND WHY IT WINS</h3>
|
||||||
<span className="section-tag">Competitive Edge</span>
|
<p className="moat-desc">
|
||||||
<h3 className="logico-title" style={{ marginTop: "10px", marginBottom: "15px" }}>Where Doormile Sits And Why It Wins</h3>
|
A side-by-side technical capabilities comparison showing how operational fleet ownership and dynamic AI planning disrupt basic aggregators.
|
||||||
<p className="section-desc">A side-by-side technical capabilities comparison showing how operational fleet ownership and dynamic AI planning disrupt basic aggregators.</p>
|
</p>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</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>
|
</section>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,206 +1,535 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import React, { useState } from "react";
|
import React, { useState, useEffect, useRef } from "react";
|
||||||
import Image from "next/image";
|
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() {
|
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) => {
|
const toggleAccordion = (index: number) => {
|
||||||
setOpenIndex((prev) => (prev === index ? null : index));
|
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 (
|
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
|
<div
|
||||||
style={{ marginBottom: "180px" }}
|
ref={containerRef}
|
||||||
className="elementor-element ev-log elementor-element-ead59d3 e-con-full e-flex cut-corner-no sticky-container-off e-con e-parent"
|
className="ev-logistic-section"
|
||||||
data-id="ead59d3"
|
|
||||||
data-element_type="container"
|
|
||||||
data-e-type="container"
|
|
||||||
>
|
>
|
||||||
<div
|
{/* Left Column: Enlarged Floating Wrapper & Ambient glow */}
|
||||||
className="elementor-element elementor-element-f35119c elementor-widget__width-initial elementor-absolute elementor-widget elementor-widget-image"
|
<div className="ev-logistic-image-col">
|
||||||
data-id="f35119c"
|
<div className="ev-logistic-image-glow"></div>
|
||||||
data-element_type="widget"
|
|
||||||
data-e-type="widget"
|
<div ref={imageWrapperRef} className="ev-logistic-image-wrapper">
|
||||||
style={{ position: "absolute" }}
|
|
||||||
>
|
|
||||||
<div className="elementor-widget-container">
|
|
||||||
<Image
|
<Image
|
||||||
|
ref={imageRef as any}
|
||||||
src="/images/ev.jpeg"
|
src="/images/ev.jpeg"
|
||||||
alt="EV Logistics"
|
alt="EV Logistics"
|
||||||
width={1050}
|
width={1050}
|
||||||
height={854}
|
height={854}
|
||||||
style={{ width: "100%", height: "auto" }}
|
priority
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
{/* Right Column: Refined Accordion list with letter-by-letter animation */}
|
||||||
className="elementor-element elementor-element-56ecbb3 e-flex e-con-boxed cut-corner-no sticky-container-off e-con e-child"
|
<div className="ev-logistic-content-col">
|
||||||
data-id="56ecbb3"
|
{/* Animated features kicker */}
|
||||||
data-element_type="container"
|
<div className="ev-logistic-kicker">/ features /</div>
|
||||||
data-e-type="container"
|
|
||||||
>
|
{/* Character-by-character masked entrance wave reveal on scroll */}
|
||||||
<div className="e-con-inner">
|
<div className="ev-logistic-title-wrapper">
|
||||||
<div
|
<h3 className="ev-logistic-title">
|
||||||
className="elementor-element elementor-element-47f8cbe e-con-full e-flex cut-corner-no sticky-container-off e-con e-child"
|
{headingWords.map((word, wordIndex) => (
|
||||||
data-id="47f8cbe"
|
<span key={wordIndex} className="ev-word-inline">
|
||||||
data-element_type="container"
|
{word.split("").map((letter, letterIndex) => (
|
||||||
data-e-type="container"
|
<span key={letterIndex} className="ev-char-wrapper">
|
||||||
>
|
<span className="ev-char">{letter}</span>
|
||||||
|
</span>
|
||||||
|
))}
|
||||||
|
<span className="ev-char-space"> </span>
|
||||||
|
</span>
|
||||||
|
))}
|
||||||
|
</h3>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="ev-logistic-accordion">
|
||||||
|
{ACCORDION_DATA.map((item) => (
|
||||||
<div
|
<div
|
||||||
className="elementor-element elementor-element-cd6daaf elementor-widget elementor-widget-logico_heading"
|
key={item.index}
|
||||||
data-id="cd6daaf"
|
className={`ev-logistic-accordion-item ${openIndex === item.index ? "active" : ""}`}
|
||||||
data-element_type="widget"
|
|
||||||
data-e-type="widget"
|
|
||||||
>
|
>
|
||||||
<div className="elementor-widget-container">
|
<button
|
||||||
<div className="logico-title">/ features /</div>
|
className="ev-logistic-accordion-header"
|
||||||
</div>
|
onClick={() => toggleAccordion(item.index)}
|
||||||
</div>
|
aria-expanded={openIndex === item.index}
|
||||||
|
>
|
||||||
<div
|
<span>{item.num}. {item.title}</span>
|
||||||
className="elementor-element elementor-element-1b3f232 elementor-widget__width-initial elementor-widget elementor-widget-logico_heading"
|
<span className="ev-logistic-accordion-arrow-container">
|
||||||
data-id="1b3f232"
|
<svg
|
||||||
data-element_type="widget"
|
viewBox="0 0 24 24"
|
||||||
data-e-type="widget"
|
fill="none"
|
||||||
>
|
stroke="currentColor"
|
||||||
<div className="elementor-widget-container">
|
strokeLinecap="round"
|
||||||
<h3 className="logico-title">Logistics Built for Electric Vehicles</h3>
|
strokeLinejoin="round"
|
||||||
</div>
|
>
|
||||||
</div>
|
<line x1="7" y1="17" x2="17" y2="7"></line>
|
||||||
|
<polyline points="7 7 17 7 17 17"></polyline>
|
||||||
<div
|
</svg>
|
||||||
className="elementor-element elementor-element-9b7e9c9 elementor-widget__width-initial elementor-widget elementor-widget-accordion"
|
</span>
|
||||||
data-id="9b7e9c9"
|
</button>
|
||||||
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>
|
|
||||||
|
|
||||||
|
<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>
|
||||||
</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>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
138
src/components/sections/EVParticles.tsx
Normal file
138
src/components/sections/EVParticles.tsx
Normal 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.3–1): 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" />;
|
||||||
|
}
|
||||||
@@ -1,46 +1,122 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import React, { useEffect, useRef } from "react";
|
import React, { useEffect, useRef, useState } from "react";
|
||||||
import Link from "next/link";
|
import dynamic from "next/dynamic";
|
||||||
import { ScrollReveal, SlideReveal } from "@/animations/Reveal";
|
|
||||||
import gsap from "gsap";
|
import gsap from "gsap";
|
||||||
import { ScrollTrigger } from "gsap/ScrollTrigger";
|
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") {
|
if (typeof window !== "undefined") {
|
||||||
gsap.registerPlugin(ScrollTrigger);
|
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() {
|
export default function EVSection() {
|
||||||
const headingContainerRef = useRef<HTMLDivElement>(null);
|
|
||||||
const bannerRef = useRef<HTMLDivElement>(null);
|
const bannerRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// 1. Heading Scroll-Triggered Animation (Up & Down, Replay)
|
// Banner Scroll-Triggered Parallax (Replicating background_image_parallax from theme.js exactly)
|
||||||
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)
|
|
||||||
const banner = bannerRef.current;
|
const banner = bannerRef.current;
|
||||||
if (!banner) return;
|
if (!banner) return;
|
||||||
|
|
||||||
@@ -49,86 +125,279 @@ export default function EVSection() {
|
|||||||
start: "top bottom",
|
start: "top bottom",
|
||||||
end: "bottom top",
|
end: "bottom top",
|
||||||
scrub: true,
|
scrub: true,
|
||||||
onUpdate: (self) => {
|
onUpdate: () => {
|
||||||
// Subtle background offset to create beautiful native parallax depth
|
if (window.innerWidth >= 1021) {
|
||||||
const yOffset = self.progress * 120;
|
const scrollTop = window.scrollY;
|
||||||
gsap.set(banner, {
|
const rect = banner.getBoundingClientRect();
|
||||||
backgroundPosition: `center ${yOffset}px`,
|
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();
|
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 */}
|
|
||||||
|
|
||||||
</span>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<style dangerouslySetInnerHTML={{ __html: `
|
<style dangerouslySetInnerHTML={{ __html: `
|
||||||
.logico-title .word {
|
/* ============================================================
|
||||||
display: inline-block;
|
EV-Native Design — redesigned section
|
||||||
white-space: nowrap;
|
bg #0d0d0d · red #dc2626 / #ef4444 · Syne + DM Sans
|
||||||
margin-right: 0.15em;
|
============================================================ */
|
||||||
}
|
|
||||||
.letter {
|
|
||||||
display: inline-block;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Native, scroll-triggered heading reveal matching WordPress/Elementor */
|
#evnd, #evnd * { font-family: "Manrope", Sans-serif !important; }
|
||||||
.logico_heading_animation .word .letter {
|
|
||||||
opacity: 0 !important;
|
.evnd {
|
||||||
transform: translateY(120%) !important;
|
position: relative;
|
||||||
animation: none !important;
|
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 {
|
/* subtle diagonal light band for depth (matches reference) */
|
||||||
opacity: 0 !important;
|
.evnd::before {
|
||||||
transform: translateY(120%) !important;
|
content: '';
|
||||||
animation: fadeIn 0.35s forwards, logico_heading_animation 0.7s cubic-bezier(.26, -.14, 0, 1.01) forwards !important;
|
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 */}
|
{/* Background Banner with Native GSAP Background Scroll Parallax */}
|
||||||
<div
|
<div
|
||||||
@@ -140,9 +409,13 @@ export default function EVSection() {
|
|||||||
data-settings="{"background_background":"classic"}"
|
data-settings="{"background_background":"classic"}"
|
||||||
style={{
|
style={{
|
||||||
backgroundPosition: "center 0px",
|
backgroundPosition: "center 0px",
|
||||||
backgroundImage: "url(/images/home4-banner-4.png)",
|
backgroundImage: "url(/images/bg-header-5.png)",
|
||||||
backgroundSize: "cover",
|
backgroundSize: "cover",
|
||||||
backgroundRepeat: "no-repeat"
|
backgroundRepeat: "no-repeat",
|
||||||
|
position: "relative",
|
||||||
|
zIndex: 2,
|
||||||
|
borderRadius: "25px 25px 0 0",
|
||||||
|
overflow: "hidden"
|
||||||
}}
|
}}
|
||||||
></div>
|
></div>
|
||||||
|
|
||||||
@@ -169,164 +442,89 @@ export default function EVSection() {
|
|||||||
</div>
|
</div>
|
||||||
</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="{"background_background":"classic"}">
|
{/* ===== EV-Native Design (redesigned) ===== */}
|
||||||
<div className="e-con-inner">
|
<section className="evnd" id="evnd" aria-label="EV-Native Design">
|
||||||
<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="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="evnd__inner">
|
||||||
<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">
|
{/* TOP ROW */}
|
||||||
<div className="elementor-widget-container">
|
<div className="evnd__top">
|
||||||
<div className="logico-title">/ EV-Native Design /</div>
|
<div className="evnd__head">
|
||||||
</div>
|
<span className="evnd__eyebrow">/ EV-Native Design /</span>
|
||||||
|
<div className="evnd__title">
|
||||||
|
BUILT FOR ELECTRIC. <span className="accent">NOT ADAPTED.</span>
|
||||||
</div>
|
</div>
|
||||||
</ScrollReveal>
|
</div>
|
||||||
|
<div className="evnd__pills">
|
||||||
<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">
|
{PILLS.map((p) => (
|
||||||
<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="evnd__pill" key={p.label}>
|
||||||
<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">
|
<span className="dot" />
|
||||||
<div className="elementor-widget-container">
|
<b>{p.value}</b>
|
||||||
<h3 className="logico-title" data-animate="true">
|
<span>{p.label}</span>
|
||||||
{renderAnimatedText()}
|
|
||||||
</h3>
|
|
||||||
</div>
|
|
||||||
</div>
|
</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">
|
</div>
|
||||||
<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>
|
||||||
|
|
||||||
|
{/* 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>−40%</b>
|
||||||
|
<span>Cost / Mile</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<SlideReveal direction="right" delay={0.15} duration={0.9}>
|
<div className="evnd__ministats">
|
||||||
<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">
|
{MINI_STATS.map((s) => (
|
||||||
<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="{"_position":"absolute"}" data-widget_type="image.default">
|
<div className="evnd__mini" key={s.label}>
|
||||||
<div className="elementor-widget-container">
|
<CountUp value={s.value} decimals={s.decimals} suffix={s.suffix} />
|
||||||
<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" />
|
<span>{s.label}</span>
|
||||||
</div>
|
</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>
|
</div>
|
||||||
</SlideReveal>
|
|
||||||
</div>
|
</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>
|
</div>
|
||||||
</div>
|
</section>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -83,16 +83,16 @@ export default function IndexHero() {
|
|||||||
backgroundSize: "cover"
|
backgroundSize: "cover"
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div className="slide-content">
|
<div className="slide-content" style={{ display: "flex", flexDirection: "column", justifyContent: "center", alignItems: "center", width: "100%", height: "100%" }}>
|
||||||
<div className="slide-content-inner">
|
<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">
|
<h1 className="content-slider-item-heading logico-content-wrapper-1" style={{ textAlign: "center", width: "100%" }}>
|
||||||
<span className="heading-content block">
|
<span className="heading-content block">
|
||||||
ONE CONNECTED SYSTEM.<br />
|
ONE CONNECTED SYSTEM.<br />
|
||||||
<ShimmerText className="font-extrabold">ONE PROMISE KEPT.</ShimmerText>
|
<ShimmerText className="font-extrabold">ONE PROMISE KEPT.</ShimmerText>
|
||||||
</span>
|
</span>
|
||||||
</h1>
|
</h1>
|
||||||
<div className="content-slider-item-text logico-content-wrapper-2">
|
<div className="content-slider-item-text logico-content-wrapper-2" style={{ display: "flex", justifyContent: "center", width: "100%", marginTop: "23px" }}>
|
||||||
<div className="text-content">
|
<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>
|
<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>
|
||||||
</div>
|
</div>
|
||||||
@@ -124,16 +124,16 @@ export default function IndexHero() {
|
|||||||
backgroundSize: "cover"
|
backgroundSize: "cover"
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div className="slide-content">
|
<div className="slide-content" style={{ display: "flex", flexDirection: "column", justifyContent: "center", alignItems: "center", width: "100%", height: "100%" }}>
|
||||||
<div className="slide-content-inner">
|
<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">
|
<h1 className="content-slider-item-heading logico-content-wrapper-1" style={{ textAlign: "center", width: "100%" }}>
|
||||||
<span className="heading-content block">
|
<span className="heading-content block">
|
||||||
<ShimmerText className="font-extrabold">AI-POWERED</ShimmerText><br />
|
<ShimmerText className="font-extrabold">AI-POWERED</ShimmerText><br />
|
||||||
CONNECTED LOGISTICS
|
CONNECTED LOGISTICS
|
||||||
</span>
|
</span>
|
||||||
</h1>
|
</h1>
|
||||||
<div className="content-slider-item-text logico-content-wrapper-2">
|
<div className="content-slider-item-text logico-content-wrapper-2" style={{ display: "flex", justifyContent: "center", width: "100%", marginTop: "23px" }}>
|
||||||
<div className="text-content">
|
<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>
|
<p>Behind every successful business is a strong supply chain. Logistics turns plans into reality.</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
226
src/components/sections/IndustryWorldMap.tsx
Normal file
226
src/components/sections/IndustryWorldMap.tsx
Normal 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
@@ -31,6 +31,52 @@ export default function OurTeam() {
|
|||||||
];
|
];
|
||||||
|
|
||||||
return (
|
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="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="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">
|
<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 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">
|
<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>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -93,5 +139,6 @@ export default function OurTeam() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,432 +1,498 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import React, { useState } from "react";
|
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() {
|
export default function SolutionCard1() {
|
||||||
const [activeTabFmcg, setActiveTabFmcg] = useState<"challenges" | "solutions">("challenges");
|
const [active, setActive] = useState(0);
|
||||||
const [activeTabPharma, setActiveTabPharma] = useState<"challenges" | "solutions">("challenges");
|
const [tab, setTab] = useState<Tab>("challenges");
|
||||||
const [activeTabB2b, setActiveTabB2b] = useState<"challenges" | "solutions">("challenges");
|
|
||||||
|
const ind = INDUSTRIES[active];
|
||||||
|
|
||||||
|
const selectIndustry = (i: number) => {
|
||||||
|
setActive(i);
|
||||||
|
setTab("challenges"); // reset to Challenges on industry switch
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<style dangerouslySetInnerHTML={{ __html: `
|
<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%;
|
width: 100%;
|
||||||
margin: 18px 0 28px;
|
height: 100%;
|
||||||
font-family: 'Manrope', sans-serif;
|
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 */
|
/* ---- Top tab bar ---- */
|
||||||
.solution-freight-tabs-alt .solution-freight-tabs__nav {
|
.ind__tabs {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 12px;
|
gap: clamp(10px, 3vw, 36px);
|
||||||
align-items: flex-end;
|
border-bottom: 1px solid rgba(255,255,255,0.1);
|
||||||
width: auto;
|
margin-bottom: clamp(28px, 4vw, 52px);
|
||||||
margin: 0 auto 6px;
|
flex-wrap: wrap;
|
||||||
}
|
}
|
||||||
|
.ind__tab {
|
||||||
.solution-freight-tabs-alt .solution-freight-tabs__button {
|
|
||||||
appearance: none;
|
appearance: none;
|
||||||
border: 1px solid rgba(0, 0, 0, 0.06);
|
background: none;
|
||||||
background: linear-gradient(180deg, #f9ccd1, #f9ccd1);
|
border: none;
|
||||||
color: #111;
|
|
||||||
padding: 12px 36px;
|
|
||||||
display: inline-block;
|
|
||||||
min-width: 180px;
|
|
||||||
text-align: center;
|
|
||||||
border-radius: 6px 6px 0 0;
|
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
font-weight: 800;
|
padding: 10px 2px 16px;
|
||||||
text-transform: uppercase;
|
font-weight: 700;
|
||||||
letter-spacing: 0.6px;
|
font-size: clamp(14px, 1.4vw, 18px);
|
||||||
box-shadow: none;
|
color: #888;
|
||||||
transition: background-color 0.12s ease, color 0.12s ease, transform 0.08s ease;
|
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 {
|
/* ---- Left media ---- */
|
||||||
margin: 0;
|
.ind__media {
|
||||||
font-size: 16px;
|
position: relative;
|
||||||
color: inherit;
|
display: flex;
|
||||||
font-weight: 800;
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
min-height: 300px;
|
||||||
}
|
}
|
||||||
|
.ind__glow {
|
||||||
.solution-freight-tabs-alt .solution-freight-tabs__button:hover {
|
position: absolute;
|
||||||
transform: translateY(-2px);
|
left: 50%; bottom: 4%;
|
||||||
background: linear-gradient(180deg, #f9ccd1, #f9ccd1);
|
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;
|
||||||
}
|
}
|
||||||
|
.ind__img-wrap {
|
||||||
.solution-freight-tabs-alt .solution-freight-tabs__button.active {
|
position: relative;
|
||||||
background: #C01227;
|
z-index: 1;
|
||||||
color: #ffffff;
|
width: 100%;
|
||||||
border-color: #C01227;
|
max-width: 460px;
|
||||||
box-shadow: none;
|
animation: indFloat 6s ease-in-out infinite;
|
||||||
transform: none;
|
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;
|
z-index: 3;
|
||||||
}
|
}
|
||||||
|
.ind__img-wrap::before {
|
||||||
.solution-freight-tabs-alt .solution-freight-tabs__content {
|
top: -10px; left: -10px;
|
||||||
margin-top: 2px;
|
border-right: none; border-bottom: none;
|
||||||
padding: 18px 20px;
|
border-radius: 10px 0 0 0;
|
||||||
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::after {
|
||||||
.solution-freight-tabs-alt .point-box li::before {
|
bottom: -10px; right: -10px;
|
||||||
content: "";
|
border-left: none; border-top: none;
|
||||||
width: 8px;
|
border-radius: 0 0 10px 0;
|
||||||
height: 8px;
|
|
||||||
border-radius: 50%;
|
|
||||||
background: #C01227;
|
|
||||||
left: 6px;
|
|
||||||
top: 8px;
|
|
||||||
}
|
}
|
||||||
|
.ind__img {
|
||||||
@media (max-width: 767px) {
|
display: block;
|
||||||
.solution-freight-tabs-alt .solution-freight-tabs__button {
|
width: 100%;
|
||||||
padding: 10px 18px;
|
height: auto;
|
||||||
min-width: 120px;
|
border-radius: 12px;
|
||||||
}
|
object-fit: cover;
|
||||||
|
box-shadow: 0 30px 60px -25px rgba(0,0,0,0.7);
|
||||||
.solution-freight-tabs-alt .solution-freight-tabs__content {
|
animation: indImgFade 0.55s ease both;
|
||||||
max-width: 100%;
|
|
||||||
margin: 0 12px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
.ind__chip {
|
||||||
@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: "✓";
|
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 0;
|
z-index: 4;
|
||||||
top: -2px;
|
display: inline-flex;
|
||||||
color: #C01227;
|
align-items: center;
|
||||||
font-size: 18px;
|
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;
|
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 {
|
/* ---- Challenges / Solutions toggle ---- */
|
||||||
height: 12px;
|
.ind__toggle {
|
||||||
margin: 10px 0 0;
|
display: inline-flex;
|
||||||
padding-left: 32px;
|
gap: 4px;
|
||||||
visibility: hidden;
|
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 {
|
/* ---- Sliding panels ---- */
|
||||||
content: none;
|
.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 className="ind__inner">
|
||||||
<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">
|
{/* Top tab bar */}
|
||||||
<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="ind__tabs" role="tablist" aria-label="Industries">
|
||||||
<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">
|
{INDUSTRIES.map((it, i) => (
|
||||||
<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" }}>
|
<button
|
||||||
<div className="elementor-widget-container" style={{ margin: 0, width: "100%", height: "100%", display: "flex", alignItems: "center", justifyContent: "center" }}>
|
key={it.id}
|
||||||
<Image
|
type="button"
|
||||||
src="/images/tab-pic-1-solution.jpeg"
|
role="tab"
|
||||||
alt="FMCG Solutions"
|
aria-selected={i === active}
|
||||||
width={578}
|
className={`ind__tab ${i === active ? "active" : ""}`}
|
||||||
height={790}
|
onClick={() => selectIndustry(i)}
|
||||||
priority
|
>
|
||||||
style={{ maxWidth: "100%", maxHeight: "100%", objectFit: "contain" }}
|
{it.tab}
|
||||||
/>
|
</button>
|
||||||
</div>
|
))}
|
||||||
|
</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>
|
</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">
|
{/* Right text */}
|
||||||
<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="ind__text">
|
||||||
<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">
|
<span className="ind__eyebrow">{ind.eyebrow}</span>
|
||||||
<div className="elementor-widget-container" style={{ margin: 0 }}>
|
<h3 className="ind__title">{ind.title}</h3>
|
||||||
<h3 className="logico-title">FMCG</h3>
|
<p className="ind__desc">{ind.desc}</p>
|
||||||
</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>
|
|
||||||
|
|
||||||
{/* FMCG Tabs */}
|
<div className="ind__toggle" role="tablist" aria-label="Challenges or Solutions">
|
||||||
<div className="solution-freight-tabs-alt">
|
<button
|
||||||
<div className="solution-freight-tabs__nav" role="tablist" aria-label="FMCG Details">
|
type="button"
|
||||||
<button
|
role="tab"
|
||||||
className={`solution-freight-tabs__button ${activeTabFmcg === "challenges" ? "active" : ""}`}
|
aria-selected={tab === "challenges"}
|
||||||
type="button"
|
className={`ind__toggle-btn ${tab === "challenges" ? "active" : ""}`}
|
||||||
role="tab"
|
onClick={() => setTab("challenges")}
|
||||||
aria-selected={activeTabFmcg === "challenges"}
|
>
|
||||||
onClick={() => setActiveTabFmcg("challenges")}
|
Challenges
|
||||||
>
|
</button>
|
||||||
<h6>Challenges</h6>
|
<button
|
||||||
</button>
|
type="button"
|
||||||
<button
|
role="tab"
|
||||||
className={`solution-freight-tabs__button ${activeTabFmcg === "solutions" ? "active" : ""}`}
|
aria-selected={tab === "solutions"}
|
||||||
type="button"
|
className={`ind__toggle-btn ${tab === "solutions" ? "active" : ""}`}
|
||||||
role="tab"
|
onClick={() => setTab("solutions")}
|
||||||
aria-selected={activeTabFmcg === "solutions"}
|
>
|
||||||
onClick={() => setActiveTabFmcg("solutions")}
|
Solutions
|
||||||
>
|
</button>
|
||||||
<h6>Solutions</h6>
|
</div>
|
||||||
</button>
|
|
||||||
|
<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>
|
||||||
<div className="solution-freight-tabs__content">
|
<div className={`ind__panel ${tab === "solutions" ? "is-active" : ""}`}>
|
||||||
{activeTabFmcg === "challenges" ? (
|
<ul className="ind__list">
|
||||||
<div className="solution-freight-tabs__panel active" role="tabpanel">
|
{ind.solutions.map((s, idx) => (
|
||||||
<ul className="point-box">
|
<li key={idx}>{s}</li>
|
||||||
<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>
|
</ul>
|
||||||
<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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</section>
|
||||||
{/* 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>
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,196 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import Image from "next/image";
|
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() {
|
export default function WomenSection() {
|
||||||
return (
|
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
|
<div
|
||||||
className="elementor-element elementor-element-13a7637 elementor-widget__width-auto elementor-absolute elementor-widget elementor-widget-logico_decorative_block"
|
className="elementor-element elementor-element-13a7637 elementor-widget__width-auto elementor-absolute elementor-widget elementor-widget-logico_decorative_block"
|
||||||
data-id="13a7637"
|
data-id="13a7637"
|
||||||
@@ -65,6 +252,9 @@ export default function WomenSection() {
|
|||||||
</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='{"background_background":"classic"}'>
|
<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="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-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">
|
<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-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-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">
|
<ScrollReveal duration={0.8} yOffset={28} triggerOnce>
|
||||||
<div className="elementor-widget-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">
|
||||||
<h3 className="logico-title">Women Leading the Way</h3>
|
<div className="elementor-widget-container">
|
||||||
|
<h3 className="logico-title">Women Leading the Way</h3>
|
||||||
|
</div>
|
||||||
</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-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">
|
<div className="elementor-widget-container">
|
||||||
<Image
|
<Image
|
||||||
@@ -94,108 +286,32 @@ export default function WomenSection() {
|
|||||||
</div>
|
</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-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
|
<div id="ws-stories">
|
||||||
className="elementor-element elementor-element-1a450c2 elementor-absolute elementor-widget elementor-widget-image"
|
<StaggerChildren className="ws__stats" stagger={0.1} duration={0.6} yOffset={20} triggerOnce>
|
||||||
data-id="1a450c2"
|
{WS_STATS.map((s) => (
|
||||||
data-element_type="widget"
|
<div className="ws__stat" key={s.label}>
|
||||||
data-e-type="widget"
|
<div className="ws__stat-num">{s.value}<span>{s.plus}</span></div>
|
||||||
style={{ position: "absolute" }}
|
<div className="ws__stat-label">{s.label}</div>
|
||||||
>
|
|
||||||
<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>
|
</div>
|
||||||
<div className="elementor-icon-box-content">
|
))}
|
||||||
<div className="elementor-icon-box-title">
|
</StaggerChildren>
|
||||||
<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>
|
|
||||||
|
|
||||||
<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">
|
<StaggerChildren className="ws__cards" stagger={0.08} duration={0.6} yOffset={24} triggerOnce>
|
||||||
<div className="elementor-widget-container">
|
{WS_CARDS.map((c) => (
|
||||||
<div className="elementor-divider">
|
<div className="ws__card" key={c.title}>
|
||||||
<span className="elementor-divider-separator"></span>
|
<span className="ws__card-icon" aria-hidden="true">{c.icon}</span>
|
||||||
</div>
|
<div className="ws__card-title">{c.title}</div>
|
||||||
</div>
|
<p className="ws__card-desc">{c.desc}</p>
|
||||||
</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>
|
|
||||||
</div>
|
</div>
|
||||||
<div className="elementor-icon-box-content">
|
))}
|
||||||
<div className="elementor-icon-box-title">
|
</StaggerChildren>
|
||||||
<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>
|
|
||||||
</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>
|
|
||||||
|
|
||||||
{/* 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>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user