update image and about section
This commit is contained in:
@@ -7,7 +7,7 @@
|
||||
* Menu open/close + sidebar state is read from HeaderUIProvider so BodyOverlay (sibling at body level) can react.
|
||||
*/
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
import { MouseEvent, useEffect, useState } from "react";
|
||||
import Link from "next/link";
|
||||
import Image from "next/image";
|
||||
import { usePathname } from "next/navigation";
|
||||
@@ -44,6 +44,34 @@ export default function Header() {
|
||||
const dmHeaderActive = (key: string) =>
|
||||
(CURRENT_PAGE_ALIASES[key] ?? []).includes(currentPage) ? " active" : "";
|
||||
|
||||
const scrollToNavTarget = (targetId: string) => {
|
||||
const target = document.getElementById(targetId);
|
||||
if (target) {
|
||||
target.scrollIntoView({ behavior: "smooth", block: "start" });
|
||||
return;
|
||||
}
|
||||
|
||||
window.scrollTo({ top: 0, behavior: "smooth" });
|
||||
};
|
||||
|
||||
const handleNavClick = (
|
||||
event: MouseEvent<HTMLAnchorElement>,
|
||||
targetPath: string,
|
||||
targetId: string,
|
||||
shouldCloseMenu = false,
|
||||
) => {
|
||||
if (shouldCloseMenu) closeAll();
|
||||
|
||||
if (pathname !== targetPath) return;
|
||||
|
||||
event.preventDefault();
|
||||
const targetUrl = `${targetPath}#${targetId}`;
|
||||
if (`${window.location.pathname}${window.location.hash}` !== targetUrl) {
|
||||
window.history.pushState(null, "", targetUrl);
|
||||
}
|
||||
requestAnimationFrame(() => scrollToNavTarget(targetId));
|
||||
};
|
||||
|
||||
// Mirror of header.php <script> block (lines 628-660):
|
||||
// - on doc.ready: $('.header-hide-until-scroll').addClass('header-visible-scrolled')
|
||||
// - on scroll: toggleClass('dm-header-scrolled', scrollTop > 50)
|
||||
@@ -406,22 +434,22 @@ export default function Header() {
|
||||
<nav>
|
||||
<ul id="menu-main-menu" className="main-menu">
|
||||
<li id="menu-item-10508" className={`menu-item menu-item-type-custom menu-item-object-custom menu-item-10508${dmHeaderActive("home")}`}>
|
||||
<Link href="/">Home</Link>
|
||||
<Link href="/#home" onClick={(event) => handleNavClick(event, "/", "home")}>Home</Link>
|
||||
</li>
|
||||
<li id="menu-item-10509" className={`menu-item menu-item-type-custom menu-item-object-custom menu-item-10509${dmHeaderActive("how-it-works")}`}>
|
||||
<Link href="/how-it-works">How It Works</Link>
|
||||
<Link href="/how-it-works#how-it-works" onClick={(event) => handleNavClick(event, "/how-it-works", "how-it-works")}>How It Works</Link>
|
||||
</li>
|
||||
<li id="menu-item-10510" className={`menu-item menu-item-type-custom menu-item-object-custom menu-item-10510${dmHeaderActive("miletruth")}`}>
|
||||
<Link href="/miletruth">MileTruth™ AI</Link>
|
||||
<Link href="/miletruth#miletruth" onClick={(event) => handleNavClick(event, "/miletruth", "miletruth")}>MileTruth™ AI</Link>
|
||||
</li>
|
||||
<li id="menu-item-10511" className={`menu-item menu-item-type-custom menu-item-10511${dmHeaderActive("solutions")}`}>
|
||||
<Link href="/solutions">Solutions</Link>
|
||||
<Link href="/solutions#solutions" onClick={(event) => handleNavClick(event, "/solutions", "solutions")}>Solutions</Link>
|
||||
</li>
|
||||
<li id="menu-item-10512" className={`menu-item menu-item-type-custom menu-item-object-custom menu-item-10512${dmHeaderActive("about")}`}>
|
||||
<Link href="/about-us">About</Link>
|
||||
<Link href="/about-us#about" onClick={(event) => handleNavClick(event, "/about-us", "about")}>About</Link>
|
||||
</li>
|
||||
<li id="menu-item-10535" className={`menu-item menu-item-type-post_type menu-item-object-page menu-item-10535${dmHeaderActive("blogs")}`}>
|
||||
<Link href="/blog">Blogs</Link>
|
||||
<Link href="/blog#blogs" onClick={(event) => handleNavClick(event, "/blog", "blogs")}>Blogs</Link>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
@@ -454,22 +482,22 @@ export default function Header() {
|
||||
<nav>
|
||||
<ul id="menu-main-menu-1" className="main-menu">
|
||||
<li className={`menu-item menu-item-type-custom menu-item-object-custom menu-item-10508${dmHeaderActive("home")}`}>
|
||||
<Link href="/" onClick={closeAll}>Home</Link>
|
||||
<Link href="/#home" onClick={(event) => handleNavClick(event, "/", "home", true)}>Home</Link>
|
||||
</li>
|
||||
<li className={`menu-item menu-item-type-custom menu-item-object-custom menu-item-10509${dmHeaderActive("how-it-works")}`}>
|
||||
<Link href="/how-it-works" onClick={closeAll}>How It Works</Link>
|
||||
<Link href="/how-it-works#how-it-works" onClick={(event) => handleNavClick(event, "/how-it-works", "how-it-works", true)}>How It Works</Link>
|
||||
</li>
|
||||
<li className={`menu-item menu-item-type-custom menu-item-object-custom menu-item-10510${dmHeaderActive("miletruth")}`}>
|
||||
<Link href="/miletruth" onClick={closeAll}>MileTruth™ AI</Link>
|
||||
<Link href="/miletruth#miletruth" onClick={(event) => handleNavClick(event, "/miletruth", "miletruth", true)}>MileTruth™ AI</Link>
|
||||
</li>
|
||||
<li className={`menu-item menu-item-type-custom menu-item-10511${dmHeaderActive("solutions")}`}>
|
||||
<Link href="/solutions" onClick={closeAll}>Solutions</Link>
|
||||
<Link href="/solutions#solutions" onClick={(event) => handleNavClick(event, "/solutions", "solutions", true)}>Solutions</Link>
|
||||
</li>
|
||||
<li className={`menu-item menu-item-type-custom menu-item-object-custom menu-item-has-children menu-item-10512${dmHeaderActive("about")}`}>
|
||||
<Link href="/about-us" onClick={closeAll}>About</Link>
|
||||
<Link href="/about-us#about" onClick={(event) => handleNavClick(event, "/about-us", "about", true)}>About</Link>
|
||||
</li>
|
||||
<li className={`menu-item menu-item-type-post_type menu-item-object-page menu-item-10535${dmHeaderActive("blogs")}`}>
|
||||
<Link href="/blog" onClick={closeAll}>Blogs</Link>
|
||||
<Link href="/blog#blogs" onClick={(event) => handleNavClick(event, "/blog", "blogs", true)}>Blogs</Link>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
@@ -1,56 +1,161 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { useEffect, useRef, useState, type MutableRefObject } from "react";
|
||||
import Image from "next/image";
|
||||
import { usePathname } from "next/navigation";
|
||||
|
||||
/**
|
||||
* LoadingScreen
|
||||
* ---------------------------------------------------------------------------
|
||||
* Native reimplementation of the legacy WordPress page-loader: a black
|
||||
* full-screen overlay with a centered, pulsing Doormile logo that fades out.
|
||||
* Route-transition loader only: a black full-screen overlay with a centered,
|
||||
* pulsing Doormile logo. It intentionally does not run on initial page render,
|
||||
* image loading, lazy component loading, API requests, or scroll.
|
||||
*
|
||||
* Shows only on initial application boot (until the window finishes loading,
|
||||
* min ~450ms to avoid a flash, capped at 2.5s so it never blocks). It must not
|
||||
* reappear during client-side route transitions: Next keeps the current page
|
||||
* visible while the next route payload is prepared, and a global overlay here
|
||||
* would create an artificial black flash between otherwise-ready pages.
|
||||
* The App Router does not expose the old `next/router` routeChangeStart /
|
||||
* routeChangeComplete event API. This component provides the same behavior by
|
||||
* detecting internal route-link starts and completing when `usePathname()`
|
||||
* reports the committed route.
|
||||
*/
|
||||
type Phase = "visible" | "hiding" | "gone";
|
||||
type Phase = "hidden" | "visible" | "hiding";
|
||||
|
||||
const MIN_SHOW_MS = 450;
|
||||
const MAX_SHOW_MS = 2500;
|
||||
const MIN_VISIBLE_MS = 420;
|
||||
const MAX_VISIBLE_MS = 800;
|
||||
|
||||
function getRoutePath(url: URL) {
|
||||
return `${url.pathname}${url.search}`;
|
||||
}
|
||||
|
||||
export default function LoadingScreen() {
|
||||
const [phase, setPhase] = useState<Phase>("visible");
|
||||
const bootComplete = useRef(false);
|
||||
const pathname = usePathname();
|
||||
const [phase, setPhase] = useState<Phase>("hidden");
|
||||
const phaseRef = useRef<Phase>("hidden");
|
||||
const visibleSince = useRef(0);
|
||||
const pendingPath = useRef<string | null>(null);
|
||||
const currentRoutePath = useRef<string | null>(null);
|
||||
const hideTimer = useRef<ReturnType<typeof setTimeout> | null>(null);
|
||||
const safetyTimer = useRef<ReturnType<typeof setTimeout> | null>(null);
|
||||
|
||||
const setLoaderPhase = (nextPhase: Phase) => {
|
||||
phaseRef.current = nextPhase;
|
||||
setPhase(nextPhase);
|
||||
};
|
||||
|
||||
const clearTimer = (timer: MutableRefObject<ReturnType<typeof setTimeout> | null>) => {
|
||||
if (!timer.current) return;
|
||||
clearTimeout(timer.current);
|
||||
timer.current = null;
|
||||
};
|
||||
|
||||
const completeTransition = () => {
|
||||
pendingPath.current = null;
|
||||
clearTimer(safetyTimer);
|
||||
|
||||
if (phaseRef.current === "hidden" || phaseRef.current === "hiding") return;
|
||||
|
||||
const elapsed = performance.now() - visibleSince.current;
|
||||
const wait = Math.max(0, MIN_VISIBLE_MS - elapsed);
|
||||
clearTimer(hideTimer);
|
||||
hideTimer.current = setTimeout(() => {
|
||||
setLoaderPhase("hiding");
|
||||
hideTimer.current = setTimeout(() => setLoaderPhase("hidden"), 360);
|
||||
}, wait);
|
||||
};
|
||||
|
||||
// Initial load: hide once the page is ready.
|
||||
useEffect(() => {
|
||||
const start = performance.now();
|
||||
let began = false;
|
||||
let fadeTimer: ReturnType<typeof setTimeout>;
|
||||
currentRoutePath.current = `${pathname}${window.location.search}`;
|
||||
completeTransition();
|
||||
// `phase` intentionally stays out of this dependency list. The route commit
|
||||
// is the completion signal; phase changes should not repeatedly restart hide.
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [pathname]);
|
||||
|
||||
const begin = () => {
|
||||
if (began || bootComplete.current) return;
|
||||
began = true;
|
||||
const wait = Math.max(0, MIN_SHOW_MS - (performance.now() - start));
|
||||
fadeTimer = setTimeout(() => setPhase("hiding"), wait);
|
||||
useEffect(() => {
|
||||
const startTransition = (targetPath: string, force = false) => {
|
||||
if (!force && targetPath === getRoutePath(new URL(window.location.href))) return;
|
||||
if (pendingPath.current === targetPath && phaseRef.current === "visible") return;
|
||||
|
||||
pendingPath.current = targetPath;
|
||||
clearTimer(hideTimer);
|
||||
clearTimer(safetyTimer);
|
||||
|
||||
visibleSince.current = performance.now();
|
||||
setLoaderPhase("visible");
|
||||
|
||||
safetyTimer.current = setTimeout(() => {
|
||||
completeTransition();
|
||||
}, MAX_VISIBLE_MS);
|
||||
};
|
||||
|
||||
const cap = setTimeout(begin, MAX_SHOW_MS);
|
||||
const onReady = () => begin();
|
||||
const getInternalRouteTarget = (anchor: HTMLAnchorElement) => {
|
||||
const rawHref = anchor.getAttribute("href");
|
||||
if (!rawHref || rawHref.startsWith("#")) return null;
|
||||
if (anchor.target && anchor.target !== "_self") return null;
|
||||
if (anchor.hasAttribute("download")) return null;
|
||||
if (/^(mailto:|tel:|sms:|javascript:)/i.test(rawHref)) return null;
|
||||
|
||||
if (document.readyState === "complete") begin();
|
||||
else window.addEventListener("load", onReady, { once: true });
|
||||
const url = new URL(rawHref, window.location.href);
|
||||
if (url.origin !== window.location.origin) return null;
|
||||
|
||||
const current = new URL(window.location.href);
|
||||
const sameRoute = url.pathname === current.pathname && url.search === current.search;
|
||||
if (sameRoute) return null;
|
||||
|
||||
return getRoutePath(url);
|
||||
};
|
||||
|
||||
const handleDocumentClick = (event: MouseEvent) => {
|
||||
if (event.defaultPrevented) return;
|
||||
if (event.button !== 0) return;
|
||||
if (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) return;
|
||||
|
||||
const anchor = (event.target as Element | null)?.closest("a[href]");
|
||||
if (!anchor || !(anchor instanceof HTMLAnchorElement)) return;
|
||||
|
||||
const targetPath = getInternalRouteTarget(anchor);
|
||||
if (targetPath) startTransition(targetPath);
|
||||
};
|
||||
|
||||
const originalPushState = window.history.pushState;
|
||||
const originalReplaceState = window.history.replaceState;
|
||||
|
||||
window.history.pushState = function patchedPushState(...args) {
|
||||
const urlArg = args[2];
|
||||
if (typeof urlArg === "string" || urlArg instanceof URL) {
|
||||
const url = new URL(urlArg, window.location.href);
|
||||
if (url.origin === window.location.origin) startTransition(getRoutePath(url));
|
||||
}
|
||||
return originalPushState.apply(this, args);
|
||||
};
|
||||
|
||||
window.history.replaceState = function patchedReplaceState(...args) {
|
||||
const urlArg = args[2];
|
||||
if (typeof urlArg === "string" || urlArg instanceof URL) {
|
||||
const url = new URL(urlArg, window.location.href);
|
||||
if (url.origin === window.location.origin) startTransition(getRoutePath(url));
|
||||
}
|
||||
return originalReplaceState.apply(this, args);
|
||||
};
|
||||
|
||||
const handlePopState = () => {
|
||||
const targetPath = getRoutePath(new URL(window.location.href));
|
||||
if (targetPath !== currentRoutePath.current) startTransition(targetPath, true);
|
||||
};
|
||||
|
||||
document.addEventListener("click", handleDocumentClick, true);
|
||||
window.addEventListener("popstate", handlePopState);
|
||||
|
||||
return () => {
|
||||
clearTimeout(cap);
|
||||
clearTimeout(fadeTimer);
|
||||
window.removeEventListener("load", onReady);
|
||||
document.removeEventListener("click", handleDocumentClick, true);
|
||||
window.removeEventListener("popstate", handlePopState);
|
||||
window.history.pushState = originalPushState;
|
||||
window.history.replaceState = originalReplaceState;
|
||||
clearTimer(hideTimer);
|
||||
clearTimer(safetyTimer);
|
||||
};
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
if (phase === "gone") return null;
|
||||
if (phase === "hidden") return null;
|
||||
|
||||
return (
|
||||
<div
|
||||
@@ -60,8 +165,8 @@ export default function LoadingScreen() {
|
||||
aria-label="Loading"
|
||||
onTransitionEnd={(e) => {
|
||||
if (e.propertyName === "opacity" && phase === "hiding") {
|
||||
bootComplete.current = true;
|
||||
setPhase("gone");
|
||||
setPhase("hidden");
|
||||
phaseRef.current = "hidden";
|
||||
}
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
* ContactMapEmbed
|
||||
* ---------------------------------------------------------------------------
|
||||
* Client boundary that lazy-loads the Leaflet map. `ssr: false` keeps Leaflet
|
||||
* out of the server bundle and off the critical render path; the skeleton fills
|
||||
* the host container's fixed height so there is zero layout shift (CLS) while
|
||||
* the map chunk loads.
|
||||
* out of the server bundle and off the critical render path. The host container
|
||||
* already owns the fixed height, so the loading state stays invisible before
|
||||
* the interactive map is ready.
|
||||
*/
|
||||
|
||||
import dynamic from "next/dynamic";
|
||||
@@ -14,7 +14,7 @@ import styles from "./OfficeMap.module.css";
|
||||
|
||||
const OfficeMap = dynamic(() => import("./OfficeMap"), {
|
||||
ssr: false,
|
||||
loading: () => <div className={styles.skeleton} role="presentation" aria-hidden="true" />,
|
||||
loading: () => <div className={styles.mapMountReserve} role="presentation" aria-hidden="true" />,
|
||||
});
|
||||
|
||||
export default function ContactMapEmbed() {
|
||||
|
||||
@@ -315,30 +315,14 @@
|
||||
}
|
||||
}
|
||||
|
||||
/* ---- Loading skeleton ---- */
|
||||
.skeleton {
|
||||
/* ---- Invisible lazy mount reserve ---- */
|
||||
.mapMountReserve {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: inherit;
|
||||
background:
|
||||
linear-gradient(
|
||||
100deg,
|
||||
rgba(255, 255, 255, 0) 30%,
|
||||
rgba(255, 255, 255, 0.05) 50%,
|
||||
rgba(255, 255, 255, 0) 70%
|
||||
),
|
||||
#101012;
|
||||
background-size: 200% 100%;
|
||||
animation: shimmer 1.4s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@keyframes shimmer {
|
||||
from { background-position: 200% 0; }
|
||||
to { background-position: -200% 0; }
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.skeleton { animation: none; }
|
||||
.markerIcon,
|
||||
.markerIconHq { transition: none; }
|
||||
.pinPulse { animation: none; opacity: 0.45; }
|
||||
|
||||
@@ -3,6 +3,7 @@ import React from "react";
|
||||
export default function AboutHero() {
|
||||
return (
|
||||
<>
|
||||
<link rel="preload" as="image" href="/images/about-bg.webp" />
|
||||
<style dangerouslySetInnerHTML={{ __html: `
|
||||
.about-us-hero-content {
|
||||
width: 100% !important;
|
||||
@@ -33,7 +34,7 @@ export default function AboutHero() {
|
||||
<div className="custom-standard-hero-container">
|
||||
<div
|
||||
style={{
|
||||
backgroundImage: "url('/images/about-bg.png')",
|
||||
backgroundImage: "url('/images/about-bg.webp')",
|
||||
"--hero-overlay": "linear-gradient(to bottom, rgba(0, 0, 0, 0.85) 0%, rgba(0, 0, 0, 0.92) 60%, rgba(0, 0, 0, 0.98) 100%)"
|
||||
} as React.CSSProperties}
|
||||
className="custom-standard-hero-card"
|
||||
@@ -48,4 +49,3 @@ export default function AboutHero() {
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import React from "react";
|
||||
import Link from "next/link";
|
||||
|
||||
export default function BlogsHero() {
|
||||
return (
|
||||
<>
|
||||
<link rel="preload" as="image" href="/images/home2-banner-1.webp" />
|
||||
<style dangerouslySetInnerHTML={{ __html: `
|
||||
.blogs-hero-title {
|
||||
color: #ffffff !important;
|
||||
@@ -19,7 +19,7 @@ export default function BlogsHero() {
|
||||
<div className="custom-standard-hero-container">
|
||||
<div
|
||||
style={{
|
||||
backgroundImage: "url(/images/home2-banner-1.jpg)",
|
||||
backgroundImage: "url(/images/home2-banner-1.webp)",
|
||||
backgroundPosition: "center center",
|
||||
backgroundRepeat: "no-repeat",
|
||||
backgroundSize: "cover"
|
||||
@@ -43,4 +43,3 @@ export default function BlogsHero() {
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -135,7 +135,7 @@ export default function ConnectedLogistics() {
|
||||
priority
|
||||
width={578}
|
||||
height={790}
|
||||
src="/images/home2-pic-3.png"
|
||||
src="/images/home2-pic-3.webp"
|
||||
className="attachment-full size-full wp-image-4481"
|
||||
alt="Connected Logistics"
|
||||
style={{
|
||||
|
||||
@@ -41,7 +41,7 @@ export default function ContactMap() {
|
||||
(bottom was square before, leaving a hard edge above the footer gap). */
|
||||
border-radius: 25px;
|
||||
overflow: hidden;
|
||||
background: #0b0b0b;
|
||||
background: transparent;
|
||||
line-height: 0;
|
||||
}
|
||||
@media (max-width: 840px) {
|
||||
|
||||
@@ -3,10 +3,11 @@ import React from "react";
|
||||
export default function ContactsHero() {
|
||||
return (
|
||||
<>
|
||||
<link rel="preload" as="image" href="/images/home2-banner-3.webp" />
|
||||
<style dangerouslySetInnerHTML={{ __html: `
|
||||
.contacts-hero-custom {
|
||||
background-color: #0b0b0b !important;
|
||||
background-image: url('/images/home2-banner-3.jpg') !important;
|
||||
background-image: url('/images/home2-banner-3.webp') !important;
|
||||
background-size: cover !important;
|
||||
background-position: center !important;
|
||||
}
|
||||
@@ -221,4 +222,3 @@ export default function ContactsHero() {
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -12,8 +12,8 @@ if (typeof window !== "undefined") {
|
||||
const CARDS_DATA = [
|
||||
{
|
||||
index: 1,
|
||||
title: "Battery-First Planning",
|
||||
desc: "Routes are optimized around battery levels and charging windows, not retrofitted as an afterthought.",
|
||||
title: "Operational Visibility",
|
||||
desc: "Real-time tracking and centralized control provide complete visibility across every shipment, vehicle, and delivery milestone.",
|
||||
icon: (
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
||||
<rect x="2" y="7" width="16" height="10" rx="2" ry="2" />
|
||||
@@ -25,8 +25,8 @@ const CARDS_DATA = [
|
||||
},
|
||||
{
|
||||
index: 2,
|
||||
title: "Energy-Aware Routing",
|
||||
desc: "Our algorithms factor in terrain, traffic, and payload weight to maximize range efficiency.",
|
||||
title: "Intelligent Routing",
|
||||
desc: "AI-powered route optimization reduces travel time, improves delivery accuracy, and maximizes fleet utilization.",
|
||||
icon: (
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
||||
<polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2" />
|
||||
@@ -35,8 +35,8 @@ const CARDS_DATA = [
|
||||
},
|
||||
{
|
||||
index: 3,
|
||||
title: "Smart Charging Integration",
|
||||
desc: "Seamless coordination with charging infrastructure to eliminate range anxiety for drivers.",
|
||||
title: "EV-First Logistics",
|
||||
desc: "Purpose-built workflows for electric fleets improve battery efficiency, charging management, and sustainable operations.",
|
||||
icon: (
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
||||
<path d="M12 2v10" />
|
||||
@@ -48,8 +48,8 @@ const CARDS_DATA = [
|
||||
},
|
||||
{
|
||||
index: 4,
|
||||
title: "Carbon Footprint Tracking",
|
||||
desc: "Real-time emissions monitoring and sustainability reports for every delivery.",
|
||||
title: "Scalable Network",
|
||||
desc: "Flexible logistics infrastructure supports growth across cities, regions, and high-volume delivery operations without disruption.",
|
||||
icon: (
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
||||
<path d="M11 20A7 7 0 0 1 9.8 6.1C15.5 5 17 4.48 19 2c1 2 2 3.5 2 5.5a7 7 0 0 1-7 7h-3" />
|
||||
@@ -89,18 +89,16 @@ export default function EVLogisticSection() {
|
||||
});
|
||||
|
||||
entryTl
|
||||
.to(container.querySelector(".ev-logistic-kicker"), {
|
||||
.to(container.querySelector(".ev-logistic-kicker-widget"), {
|
||||
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%",
|
||||
.to(container.querySelector(".ev-logistic-title-widget"), {
|
||||
y: 0,
|
||||
opacity: 1,
|
||||
duration: 0.95,
|
||||
stagger: 0.02, // Rapid letter-by-letter wave reveal!
|
||||
duration: 0.85,
|
||||
ease: "power4.out",
|
||||
}, "-=0.45")
|
||||
.to(container.querySelectorAll(".ev-feature-card"), {
|
||||
@@ -125,20 +123,11 @@ export default function EVLogisticSection() {
|
||||
};
|
||||
}, []);
|
||||
|
||||
const headingText = "LOGISTICS BUILT FOR ELECTRIC VEHICLES";
|
||||
const headingWords = headingText.split(" ");
|
||||
|
||||
return (
|
||||
<>
|
||||
<style dangerouslySetInnerHTML={{ __html: `
|
||||
/* Custom CSS Scoped to EV Logistics Section */
|
||||
.ev-logistic-section {
|
||||
display: flex !important;
|
||||
flex-direction: column !important;
|
||||
width: 100% !important;
|
||||
max-width: 1480px !important;
|
||||
margin: 10px auto 120px auto !important;
|
||||
padding: 80px 40px !important;
|
||||
box-sizing: border-box !important;
|
||||
background: #ffffff !important;
|
||||
font-family: 'Manrope', sans-serif !important;
|
||||
@@ -149,8 +138,6 @@ export default function EVLogisticSection() {
|
||||
width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
align-self: stretch !important;
|
||||
border-bottom: 2px solid rgba(17, 17, 17, 0.09) !important;
|
||||
padding-bottom: 24px !important;
|
||||
margin-bottom: 48px !important;
|
||||
display: block !important;
|
||||
text-align: left !important;
|
||||
@@ -223,57 +210,30 @@ export default function EVLogisticSection() {
|
||||
margin: 0 !important;
|
||||
}
|
||||
|
||||
.ev-logistic-kicker {
|
||||
font-size: 14px !important;
|
||||
font-weight: 400 !important;
|
||||
line-height: 2.1429em !important;
|
||||
letter-spacing: 0px !important;
|
||||
text-transform: lowercase !important;
|
||||
color: #111111 !important;
|
||||
margin: 0 0 16px 0 !important;
|
||||
.ev-logistic-kicker-widget {
|
||||
opacity: 0;
|
||||
transform: translateY(-12px);
|
||||
will-change: transform, opacity, letter-spacing;
|
||||
text-align: left !important;
|
||||
display: inline-block !important;
|
||||
will-change: transform, opacity;
|
||||
}
|
||||
|
||||
.ev-logistic-title-wrapper {
|
||||
margin: 0 !important;
|
||||
}
|
||||
|
||||
/* Expanded clean headings look from the screenshot */
|
||||
.ev-logistic-title {
|
||||
font-size: clamp(40px, 5.5vw, 80px) !important;
|
||||
font-weight: 500 !important;
|
||||
line-height: 0.95 !important;
|
||||
text-transform: uppercase !important;
|
||||
color: #111111 !important;
|
||||
margin: 0 10px 0 0 !important;
|
||||
letter-spacing: -1.8px !important;
|
||||
}
|
||||
|
||||
/* CSS for robust letter-by-letter animation wrapping */
|
||||
.ev-word-inline {
|
||||
display: inline-block !important;
|
||||
white-space: nowrap !important;
|
||||
}
|
||||
|
||||
.ev-char-wrapper {
|
||||
display: inline-block !important;
|
||||
overflow: hidden !important;
|
||||
vertical-align: top !important;
|
||||
}
|
||||
|
||||
.ev-char {
|
||||
display: inline-block !important;
|
||||
transform: translateY(110%);
|
||||
.ev-logistic-title-widget {
|
||||
opacity: 0;
|
||||
transform: translateY(24px);
|
||||
will-change: transform, opacity;
|
||||
}
|
||||
|
||||
.ev-char-space {
|
||||
display: inline-block !important;
|
||||
.ev-logistic-title-widget > .elementor-widget-container {
|
||||
margin: 0 !important;
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
.ev-logistic-title-widget .logico-title {
|
||||
margin: 0 !important;
|
||||
text-align: left !important;
|
||||
}
|
||||
|
||||
/* Card Grid Layout */
|
||||
@@ -360,11 +320,6 @@ export default function EVLogisticSection() {
|
||||
|
||||
/* Responsiveness constraints */
|
||||
@media (max-width: 1024px) {
|
||||
.ev-logistic-section {
|
||||
padding: 60px 24px !important;
|
||||
margin-bottom: 60px !important;
|
||||
}
|
||||
|
||||
.ev-logistic-body-grid {
|
||||
flex-direction: column !important;
|
||||
gap: 50px !important;
|
||||
@@ -389,20 +344,9 @@ export default function EVLogisticSection() {
|
||||
max-width: 100% !important;
|
||||
}
|
||||
|
||||
.ev-logistic-title {
|
||||
font-size: clamp(32px, 5vw, 60px) !important;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.ev-logistic-section {
|
||||
padding: 40px 16px !important;
|
||||
}
|
||||
|
||||
.ev-logistic-title {
|
||||
font-size: 32px !important;
|
||||
}
|
||||
|
||||
.ev-feature-grid {
|
||||
grid-template-columns: 1fr !important;
|
||||
gap: 20px !important;
|
||||
@@ -410,61 +354,76 @@ export default function EVLogisticSection() {
|
||||
}
|
||||
`}} />
|
||||
|
||||
<div
|
||||
ref={containerRef}
|
||||
className="ev-logistic-section"
|
||||
>
|
||||
{/* Top Header Row with / features / kicker and Full-Width Title */}
|
||||
<div className="ev-logistic-header">
|
||||
<div className="ev-logistic-kicker">/ Build Electric Vehicles /</div>
|
||||
<div className="ev-logistic-title-wrapper">
|
||||
<h3 className="ev-logistic-title">
|
||||
{headingWords.map((word, wordIndex) => (
|
||||
<span key={wordIndex} className="ev-word-inline">
|
||||
{word.split("").map((letter, letterIndex) => (
|
||||
<span key={letterIndex} className="ev-char-wrapper">
|
||||
<span className="ev-char">{letter}</span>
|
||||
</span>
|
||||
))}
|
||||
<span className="ev-char-space"> </span>
|
||||
</span>
|
||||
))}
|
||||
</h3>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="ev-logistic-body-grid">
|
||||
{/* Left Column: Enlarged Floating Wrapper & Ambient glow */}
|
||||
<div className="ev-logistic-image-col">
|
||||
<div className="ev-logistic-image-glow"></div>
|
||||
|
||||
<div ref={imageWrapperRef} className="ev-logistic-image-wrapper">
|
||||
<Image
|
||||
ref={imageRef}
|
||||
src="/images/ev.jpeg"
|
||||
alt="EV Logistics"
|
||||
width={1050}
|
||||
height={854}
|
||||
priority
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Right Column: 2x2 Grid of Feature Cards */}
|
||||
<div className="ev-logistic-content-col">
|
||||
<div className="ev-feature-grid">
|
||||
{CARDS_DATA.map((item) => (
|
||||
<div
|
||||
key={item.index}
|
||||
className="ev-feature-card"
|
||||
>
|
||||
<div className="ev-feature-icon-wrapper">
|
||||
{item.icon}
|
||||
<div className="elementor-61">
|
||||
<div
|
||||
ref={containerRef}
|
||||
className="elementor-element elementor-element-88745f4 e-flex e-con-boxed cut-corner-no sticky-container-off e-con e-parent ev-logistic-section"
|
||||
data-id="88745f4"
|
||||
data-element_type="container"
|
||||
data-e-type="container"
|
||||
>
|
||||
<div className="e-con-inner">
|
||||
<div className="elementor-element elementor-element-343b363 e-con-full e-flex cut-corner-no sticky-container-off e-con e-child" data-id="343b363" data-element_type="container" data-e-type="container">
|
||||
{/* Same header hierarchy and container structure as "The Doormile Way". */}
|
||||
<div className="ev-logistic-header">
|
||||
<div className="elementor-element elementor-element-7afb238 elementor-widget elementor-widget-logico_heading ev-logistic-kicker-widget" data-id="7afb238" data-element_type="widget" data-e-type="widget" data-widget_type="logico_heading.default">
|
||||
<div className="elementor-widget-container">
|
||||
<div className="logico-title ev-logistic-kicker">/ Build Electric Vehicles /</div>
|
||||
</div>
|
||||
<h4 className="ev-feature-card-title">{item.title}</h4>
|
||||
<p className="ev-feature-card-desc">{item.desc}</p>
|
||||
</div>
|
||||
))}
|
||||
<div className="ev-logistic-title-wrapper">
|
||||
<div className="elementor-element elementor-element-1cc335a elementor-widget elementor-widget-logico_heading ev-logistic-title-widget" data-id="1cc335a" data-element_type="widget" data-e-type="widget" data-widget_type="logico_heading.default">
|
||||
<div className="elementor-widget-container">
|
||||
<div
|
||||
className="logico-title"
|
||||
style={{
|
||||
WebkitTextStroke: "4px #c01227",
|
||||
color: "#fff",
|
||||
fontWeight: 800,
|
||||
}}
|
||||
>
|
||||
LOGISTICS BUILT FOR ELECTRIC VEHICLES
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="ev-logistic-body-grid">
|
||||
{/* Left Column: Enlarged Floating Wrapper & Ambient glow */}
|
||||
<div className="ev-logistic-image-col">
|
||||
<div className="ev-logistic-image-glow"></div>
|
||||
|
||||
<div ref={imageWrapperRef} className="ev-logistic-image-wrapper">
|
||||
<Image
|
||||
ref={imageRef}
|
||||
src="/images/ev.webp"
|
||||
alt="EV Logistics"
|
||||
width={1050}
|
||||
height={854}
|
||||
priority
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Right Column: 2x2 Grid of Feature Cards */}
|
||||
<div className="ev-logistic-content-col">
|
||||
<div className="ev-feature-grid">
|
||||
{CARDS_DATA.map((item) => (
|
||||
<div
|
||||
key={item.index}
|
||||
className="ev-feature-card"
|
||||
>
|
||||
<div className="ev-feature-icon-wrapper">
|
||||
{item.icon}
|
||||
</div>
|
||||
<h4 className="ev-feature-card-title">{item.title}</h4>
|
||||
<p className="ev-feature-card-desc">{item.desc}</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -325,7 +325,7 @@ function DashboardPanel({
|
||||
}
|
||||
|
||||
export default function EVSection({
|
||||
bannerImage = "/images/bg-header-5.png",
|
||||
bannerImage = "/images/bg-header-5.webp",
|
||||
cardNumber = "",
|
||||
cardTitle = "EV Logistics",
|
||||
cardSubtitle = "Cleaner miles, lower costs",
|
||||
@@ -333,7 +333,7 @@ export default function EVSection({
|
||||
titleLead = "BUILT FOR ELECTRIC. ",
|
||||
titleAccent = "NOT ADAPTED.",
|
||||
features = DEFAULT_FEATURES,
|
||||
image = "/images/premium-ev-van.png",
|
||||
image = "/images/premium-ev-van.webp",
|
||||
imageAlt = "DoorMile electric delivery van",
|
||||
badges = DEFAULT_BADGES,
|
||||
stats = DEFAULT_STATS,
|
||||
@@ -539,12 +539,12 @@ export default function EVSection({
|
||||
(fit-content), so it stays centred with no side bands. The cap is
|
||||
kept below the dashboard height so the image never inflates the row.
|
||||
Scoped to the non-scene wrapper; desktop only, mobile untouched. */
|
||||
.evnd__grid--cards .evnd__imgwrap:not(.evnd__imgwrap--media) {
|
||||
.evnd__grid--cards .evnd__imgwrap:not(.evnd__imgwrap--media):not(.evnd__imgwrap--video) {
|
||||
width: fit-content;
|
||||
max-width: 100%;
|
||||
margin-inline: auto;
|
||||
}
|
||||
.evnd__grid--cards .evnd__imgwrap:not(.evnd__imgwrap--media) .evnd__img {
|
||||
.evnd__grid--cards .evnd__imgwrap:not(.evnd__imgwrap--media):not(.evnd__imgwrap--video) .evnd__img {
|
||||
width: auto;
|
||||
height: auto;
|
||||
max-height: clamp(520px, 46vw, 670px);
|
||||
@@ -552,6 +552,19 @@ export default function EVSection({
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1200px) {
|
||||
.evnd__grid--cards .evnd__imgwrap--video {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
min-height: 100%;
|
||||
}
|
||||
.evnd__grid--cards .evnd__imgwrap--video .evnd__video {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
}
|
||||
|
||||
.evnd__left {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@@ -627,6 +640,12 @@ export default function EVSection({
|
||||
object-fit: cover;
|
||||
transition: transform 0.8s cubic-bezier(0.25, 1, 0.5, 1);
|
||||
}
|
||||
.evnd__video {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: contain;
|
||||
}
|
||||
.evnd__imgwrap:hover .evnd__img {
|
||||
transform: scale(1.03);
|
||||
}
|
||||
@@ -1239,10 +1258,21 @@ export default function EVSection({
|
||||
<div className="evnd__media">
|
||||
<div className="evnd__glow" />
|
||||
<div
|
||||
className={`evnd__imgwrap${mediaSlot ? " evnd__imgwrap--media" : ""}`}
|
||||
className={`evnd__imgwrap${mediaSlot ? " evnd__imgwrap--media" : ""}${image.endsWith(".mp4") ? " evnd__imgwrap--video" : ""}`}
|
||||
>
|
||||
{mediaSlot ? (
|
||||
mediaSlot
|
||||
) : image.endsWith(".mp4") ? (
|
||||
<video
|
||||
className="evnd__video"
|
||||
autoPlay
|
||||
muted
|
||||
loop
|
||||
playsInline
|
||||
aria-label={imageAlt}
|
||||
>
|
||||
<source src={image} type="video/mp4" />
|
||||
</video>
|
||||
) : (
|
||||
/* eslint-disable-next-line @next/next/no-img-element */
|
||||
<img
|
||||
|
||||
@@ -19,19 +19,20 @@ export default function HowItWorksHero() {
|
||||
|
||||
return (
|
||||
<>
|
||||
<link rel="preload" as="image" href="/images/home2-banner-1.webp" />
|
||||
<style
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: `
|
||||
.howits-hero-custom-bg.elementor-repeater-item-3264830,
|
||||
.howits-hero-custom-bg.elementor-repeater-item-6867061 {
|
||||
background-image: linear-gradient(rgba(0, 0, 0, 0.6), rgba(0, 0, 0, 0.1)), url('/images/home2-banner-1.jpg') !important;
|
||||
background-image: linear-gradient(rgba(0, 0, 0, 0.6), rgba(0, 0, 0, 0.1)), url('/images/home2-banner-1.webp') !important;
|
||||
background-position: center !important;
|
||||
background-repeat: no-repeat !important;
|
||||
background-size: cover !important;
|
||||
}
|
||||
|
||||
.howits-hero-custom-bg.elementor-repeater-item-6867061 {
|
||||
background-image: linear-gradient(rgba(0, 0, 0, 0.6), rgba(0, 0, 0, 0.1)), url('/images/home1-slide-2.png') !important;
|
||||
background-image: linear-gradient(rgba(0, 0, 0, 0.6), rgba(0, 0, 0, 0.1)), url('/images/home1-slide-2.webp') !important;
|
||||
background-position: center !important;
|
||||
background-repeat: no-repeat !important;
|
||||
background-size: cover !important;
|
||||
|
||||
@@ -52,6 +52,7 @@ export default function IndexHero() {
|
||||
|
||||
return (
|
||||
<div className="elementor-element elementor-element-741f56c e-con-full e-flex cut-corner-no sticky-container-off e-con e-parent" data-id="741f56c" data-element_type="container" data-e-type="container">
|
||||
<link rel="preload" as="image" href="/images/home-bg-1.webp" />
|
||||
<style dangerouslySetInnerHTML={{ __html: `
|
||||
/* Fluid responsive font size override for hero headings */
|
||||
.logico-content-slider-widget .content-slider-item-heading {
|
||||
@@ -177,7 +178,7 @@ export default function IndexHero() {
|
||||
<div
|
||||
className="content-item slider-item elementor-repeater-item-3264830 slide-style-standard"
|
||||
style={{
|
||||
backgroundImage: "url('/images/home-bg-1.png')",
|
||||
backgroundImage: "url('/images/home-bg-1.webp')",
|
||||
backgroundPosition: "center center",
|
||||
backgroundRepeat: "no-repeat",
|
||||
backgroundSize: "cover"
|
||||
@@ -218,7 +219,7 @@ export default function IndexHero() {
|
||||
<div
|
||||
className="content-item slider-item elementor-repeater-item-6867061 slide-style-standard"
|
||||
style={{
|
||||
backgroundImage: "url('/images/home-bg-1.png')",
|
||||
backgroundImage: "url('/images/home-bg-1.webp')",
|
||||
backgroundPosition: "center center",
|
||||
backgroundRepeat: "no-repeat",
|
||||
backgroundSize: "cover"
|
||||
|
||||
@@ -85,7 +85,7 @@ export default function IndustrySolutions() {
|
||||
<Link href="/solutions" className="industry-card-link">
|
||||
<div className="industry-card-bg">
|
||||
<Image
|
||||
src="/images/tab-pic-1.jpeg"
|
||||
src="/images/tab-pic-1.webp"
|
||||
alt="FMCG Logistics"
|
||||
fill
|
||||
style={{ objectFit: "cover" }}
|
||||
@@ -149,7 +149,7 @@ export default function IndustrySolutions() {
|
||||
<Link href="/solutions" className="industry-card-link">
|
||||
<div className="industry-card-bg">
|
||||
<Image
|
||||
src="/images/tab-pic-2.jpeg"
|
||||
src="/images/tab-pic-2.webp"
|
||||
alt="Pharma Logistics"
|
||||
fill
|
||||
style={{ objectFit: "cover" }}
|
||||
@@ -213,7 +213,7 @@ export default function IndustrySolutions() {
|
||||
<Link href="/solutions" className="industry-card-link">
|
||||
<div className="industry-card-bg">
|
||||
<Image
|
||||
src="/images/tab-pic-3.jpeg"
|
||||
src="/images/tab-pic-3.webp"
|
||||
alt="Enterprise Logistics"
|
||||
fill
|
||||
style={{ objectFit: "cover" }}
|
||||
|
||||
@@ -19,7 +19,7 @@ const SECTIONS: Section[] = [
|
||||
{
|
||||
id: 1,
|
||||
title: "FMCG",
|
||||
image: "/images/tab-pic-1-solution.jpeg",
|
||||
image: "/images/tab-pic-1-solution.webp",
|
||||
alt: "FMCG logistics",
|
||||
desc:
|
||||
"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.",
|
||||
@@ -39,7 +39,7 @@ const SECTIONS: Section[] = [
|
||||
{
|
||||
id: 2,
|
||||
title: "Pharma",
|
||||
image: "/images/tab-pic-2-solution.jpeg",
|
||||
image: "/images/tab-pic-2-solution.webp",
|
||||
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.",
|
||||
@@ -59,7 +59,7 @@ const SECTIONS: Section[] = [
|
||||
{
|
||||
id: 3,
|
||||
title: "Enterprise & B2B",
|
||||
image: "/images/tab-pic-3-solution.jpeg",
|
||||
image: "/images/tab-pic-3-solution.webp",
|
||||
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.",
|
||||
|
||||
@@ -44,6 +44,7 @@ export default function MileTruthHero() {
|
||||
|
||||
return (
|
||||
<>
|
||||
<link rel="preload" as="image" href="/images/miletruth-bg.webp" />
|
||||
<style dangerouslySetInnerHTML={{ __html: `
|
||||
/* ── Hero wrapper: column layout, zero gap between hero + stats ── */
|
||||
.miletruth-hero .elementor-element-86f3204 {
|
||||
@@ -56,7 +57,7 @@ export default function MileTruthHero() {
|
||||
|
||||
/* ── Hero slider card ── */
|
||||
.miletruth-hero-container {
|
||||
background-image: linear-gradient(to bottom, rgba(0, 0, 0, 0.05) 0%, rgba(0, 0, 0, 0.15) 55%, rgba(0, 0, 0, 0.3) 100%), url('/images/miletruth-bg.png') !important;
|
||||
background-image: linear-gradient(to bottom, rgba(0, 0, 0, 0.05) 0%, rgba(0, 0, 0, 0.15) 55%, rgba(0, 0, 0, 0.3) 100%), url('/images/miletruth-bg.webp') !important;
|
||||
background-size: cover !important;
|
||||
background-position: center !important;
|
||||
background-repeat: no-repeat !important;
|
||||
|
||||
@@ -6,28 +6,28 @@ export default function OurTeam() {
|
||||
{
|
||||
name: "Ratan Kumar",
|
||||
position: "COO & Operational Specialist",
|
||||
image: "/images/Investor.png",
|
||||
image: "/images/Investor.webp",
|
||||
},
|
||||
|
||||
{
|
||||
name: "Parthiban",
|
||||
position: "CGO & Growth Specialist",
|
||||
image: "/images/Parthi.png",
|
||||
image: "/images/Parthi.webp",
|
||||
},
|
||||
{
|
||||
name: "Aravinth",
|
||||
position: "CFO & Finance Specialist",
|
||||
image: "/images/Aravinth.png",
|
||||
image: "/images/Aravinth.webp",
|
||||
},
|
||||
{
|
||||
name: "Fazul Ilahi",
|
||||
position: "CTO & Technology Specialist",
|
||||
image: "/images/Fazul.png",
|
||||
image: "/images/Fazul.webp",
|
||||
},
|
||||
{
|
||||
name: "Suriya Kumar",
|
||||
position: "Engineering Head & AI Specialist",
|
||||
image: "/images/Suriya.png",
|
||||
image: "/images/Suriya.webp",
|
||||
},
|
||||
];
|
||||
|
||||
@@ -122,6 +122,10 @@ export default function OurTeam() {
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
}
|
||||
.team-listing-wrapper.team-grid-listing .team-item .post-title .team-member-name {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
`}} />
|
||||
<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">
|
||||
@@ -149,19 +153,17 @@ export default function OurTeam() {
|
||||
<div className="team-item">
|
||||
<div className="team-item-media">
|
||||
<div className="post-media">
|
||||
<a href="#">
|
||||
<Image
|
||||
src={member.image}
|
||||
alt={member.name}
|
||||
width={300}
|
||||
height={360}
|
||||
style={{ objectFit: "cover", width: "100%", height: "100%" }}
|
||||
/>
|
||||
</a>
|
||||
<Image
|
||||
src={member.image}
|
||||
alt={member.name}
|
||||
width={300}
|
||||
height={360}
|
||||
style={{ objectFit: "cover", width: "100%", height: "100%" }}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="team-item-content">
|
||||
<div className="post-title"><a href="#">{member.name}</a></div>
|
||||
<div className="post-title"><span className="team-member-name">{member.name}</span></div>
|
||||
<div className="team-item-position" dangerouslySetInnerHTML={{ __html: member.position }}></div>
|
||||
<div className="team-item-socials">
|
||||
<ul className="team-socials wrapper-socials">
|
||||
|
||||
@@ -74,6 +74,7 @@ export default function SingleBlog({ post }: { post: BlogPost }) {
|
||||
|
||||
return (
|
||||
<article className="dm-single-blog">
|
||||
<link rel="preload" as="image" href={post.image} />
|
||||
<style dangerouslySetInnerHTML={{ __html: STYLES }} />
|
||||
|
||||
{/* ── Full-width page banner (image + badge + title only) ──────── */}
|
||||
|
||||
@@ -19,17 +19,18 @@ export default function SolutionsHero() {
|
||||
|
||||
return (
|
||||
<>
|
||||
<link rel="preload" as="image" href="/images/home1-slide-1.webp" />
|
||||
<style dangerouslySetInnerHTML={{ __html: `
|
||||
.howits-hero-custom-bg.elementor-repeater-item-3264830,
|
||||
.howits-hero-custom-bg.elementor-repeater-item-6867061 {
|
||||
background-image: linear-gradient(rgba(0, 0, 0, 0.6), rgba(0, 0, 0, 0.1)), url('/images/home1-slide-1.png') !important;
|
||||
background-image: linear-gradient(rgba(0, 0, 0, 0.6), rgba(0, 0, 0, 0.1)), url('/images/home1-slide-1.webp') !important;
|
||||
background-position: center !important;
|
||||
background-repeat: no-repeat !important;
|
||||
background-size: cover !important;
|
||||
}
|
||||
|
||||
.howits-hero-custom-bg.elementor-repeater-item-6867061 {
|
||||
background-image: linear-gradient(rgba(0, 0, 0, 0.6), rgba(0, 0, 0, 0.1)), url('/images/home1-slide-2.png') !important;
|
||||
background-image: linear-gradient(rgba(0, 0, 0, 0.6), rgba(0, 0, 0, 0.1)), url('/images/home1-slide-2.webp') !important;
|
||||
background-position: center !important;
|
||||
background-repeat: no-repeat !important;
|
||||
background-size: cover !important;
|
||||
|
||||
@@ -19,7 +19,7 @@ type Stage = {
|
||||
|
||||
const STAGES: Stage[] = [
|
||||
{
|
||||
img: "/images/first-mile-approach.jpg",
|
||||
img: "/images/first-mile-approach.webp",
|
||||
label: "Stage 01",
|
||||
title: "First Mile Warehouse",
|
||||
subtitle: "Consolidation & Prep",
|
||||
@@ -31,7 +31,7 @@ const STAGES: Stage[] = [
|
||||
]
|
||||
},
|
||||
{
|
||||
img: "/images/mid-mile-approach.jpg",
|
||||
img: "/images/mid-mile-approach.webp",
|
||||
label: "Stage 02",
|
||||
title: "Mid Mile Transit",
|
||||
subtitle: "Hub-to-Hub Transport",
|
||||
@@ -43,7 +43,7 @@ const STAGES: Stage[] = [
|
||||
]
|
||||
},
|
||||
{
|
||||
img: "/images/last-mile-approach.jpg",
|
||||
img: "/images/last-mile-approach.webp",
|
||||
label: "Stage 03",
|
||||
title: "Last Mile Delivery",
|
||||
subtitle: "Hub to Doorstep",
|
||||
|
||||
@@ -12,7 +12,7 @@ const WS_STATS = [
|
||||
const WS_CARDS = [
|
||||
{
|
||||
title: "Women Leadership",
|
||||
desc: "Women driving decisions across operations, routing, and last-mile delivery every day.",
|
||||
desc: "Women shaping strategy and driving excellence across logistics operations.",
|
||||
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" />
|
||||
@@ -22,7 +22,7 @@ const WS_CARDS = [
|
||||
},
|
||||
{
|
||||
title: "Entrepreneurship",
|
||||
desc: "Enabling women to build, own, and scale their own delivery businesses.",
|
||||
desc: "Women building sustainable businesses within the logistics ecosystem.",
|
||||
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" />
|
||||
@@ -32,7 +32,7 @@ const WS_CARDS = [
|
||||
},
|
||||
{
|
||||
title: "Innovation",
|
||||
desc: "Fresh thinking that reshapes how first and last-mile logistics actually work.",
|
||||
desc: "Women advancing logistics through practical ideas and operational insight.",
|
||||
icon: (
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round">
|
||||
<path d="M9 18h6M10 21h4" />
|
||||
@@ -42,7 +42,7 @@ const WS_CARDS = [
|
||||
},
|
||||
{
|
||||
title: "Community Growth",
|
||||
desc: "Local hiring and training that lifts entire neighbourhoods, not just routes.",
|
||||
desc: "Creating local opportunities through training, employment, and empowerment.",
|
||||
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" />
|
||||
@@ -117,14 +117,18 @@ export default function WomenSection() {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 14px;
|
||||
align-items: stretch;
|
||||
}
|
||||
#ws-stories .ws__card {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 168px;
|
||||
background: rgba(255,255,255,0.035);
|
||||
border: 1px solid rgba(255,255,255,0.08);
|
||||
border-radius: 16px;
|
||||
padding: 22px 20px;
|
||||
border-radius: 14px;
|
||||
padding: 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 {
|
||||
@@ -148,31 +152,31 @@ export default function WomenSection() {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 44px; height: 44px;
|
||||
border-radius: 12px;
|
||||
width: 40px; height: 40px;
|
||||
border-radius: 11px;
|
||||
background: rgba(220,38,38,0.12);
|
||||
border: 1px solid rgba(220,38,38,0.25);
|
||||
color: #ef4444;
|
||||
margin-bottom: 14px;
|
||||
margin-bottom: 16px;
|
||||
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-icon svg { width: 21px; height: 21px; }
|
||||
#ws-stories .ws__card-title {
|
||||
color: #fff !important;
|
||||
font-weight: 900;
|
||||
font-size: 17px;
|
||||
letter-spacing: -0.01em;
|
||||
margin-bottom: 8px;
|
||||
font-weight: 800;
|
||||
font-size: 19px;
|
||||
line-height: 1.2;
|
||||
letter-spacing: 0;
|
||||
margin-bottom: 9px;
|
||||
}
|
||||
#ws-stories .ws__card-desc {
|
||||
color: rgba(255,255,255,0.6) !important;
|
||||
font-size: 13.5px;
|
||||
line-height: 1.6;
|
||||
max-width: 28ch;
|
||||
color: rgba(255,255,255,0.66) !important;
|
||||
font-size: 15px;
|
||||
line-height: 1.52;
|
||||
margin: 0;
|
||||
font-weight: 900;
|
||||
font-size: 16px;
|
||||
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.elementor-element-778840d .logico-title {
|
||||
@@ -262,7 +266,7 @@ export default function WomenSection() {
|
||||
</div>
|
||||
|
||||
<div
|
||||
style={{ backgroundImage: "url(/images/bg-header-women.png)" }}
|
||||
style={{ backgroundImage: "url(/images/bg-header-women.webp)" }}
|
||||
className="elementor-element elementor-element-7da6646 e-con-full e-flex cut-corner-no sticky-container-off e-con e-child"
|
||||
data-id="7da6646"
|
||||
data-element_type="container"
|
||||
@@ -331,7 +335,7 @@ export default function WomenSection() {
|
||||
<div className="elementor-element elementor-element-bbfb67f elementor-widget elementor-widget-image" data-id="bbfb67f" data-element_type="widget" data-e-type="widget" data-widget_type="image.default">
|
||||
<div className="elementor-widget-container">
|
||||
<Image
|
||||
src="/images/bg-map-women.png"
|
||||
src="/images/bg-map-women.webp"
|
||||
alt="Women Map"
|
||||
width={626}
|
||||
height={692}
|
||||
|
||||
@@ -89,7 +89,7 @@ export default function Workflow1() {
|
||||
ariaLabel="Workflow 1 — Performance"
|
||||
gapTop
|
||||
gapBottom
|
||||
bannerImage="/images/mile-1.png"
|
||||
bannerImage="/images/mile-1.webp"
|
||||
cardTitle="OPTIMIZE EVERY MILE"
|
||||
cardSubtitle="Cut travel distance, reduce operating cost, and improve fleet productivity across every route."
|
||||
eyebrow="/ Performance /"
|
||||
|
||||
@@ -89,13 +89,13 @@ export default function Workflow2() {
|
||||
<EVSection
|
||||
ariaLabel="Workflow 2 — Innovation"
|
||||
gapBottom
|
||||
bannerImage="/images/mid-mile-approach.jpg"
|
||||
bannerImage="/images/mid-mile-approach.webp"
|
||||
cardTitle="CHOOSE THE BEST PLAN"
|
||||
cardSubtitle="Analyze thousands of route possibilities and automatically select the most efficient delivery strategy."
|
||||
eyebrow="/ Innovation /"
|
||||
titleLead="MANY STRATEGIES. "
|
||||
titleAccent="ONE BEST PLAN."
|
||||
image="/images/b5b560fe-aab0-4fe6-9f8c-4b187c2f0e99.png"
|
||||
image="/videos/workflow-2-routing.mp4"
|
||||
imageAlt="AI route-planning engine selecting the best delivery plan"
|
||||
metrics={METRICS}
|
||||
features={FEATURES}
|
||||
|
||||
Reference in New Issue
Block a user