update image and about section

This commit is contained in:
2026-06-13 00:27:45 +05:30
parent 2bc01b5952
commit 205924e057
75 changed files with 418 additions and 308 deletions

View File

@@ -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&trade; AI</Link>
<Link href="/miletruth#miletruth" onClick={(event) => handleNavClick(event, "/miletruth", "miletruth")}>MileTruth&trade; 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&trade; AI</Link>
<Link href="/miletruth#miletruth" onClick={(event) => handleNavClick(event, "/miletruth", "miletruth", true)}>MileTruth&trade; 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>

View File

@@ -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";
}
}}
>

View File

@@ -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() {

View File

@@ -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; }

View File

@@ -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() {
</>
);
}

View File

@@ -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() {
</>
);
}

View File

@@ -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={{

View File

@@ -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) {

View File

@@ -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() {
);
}

View File

@@ -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">&nbsp;</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>

View File

@@ -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

View File

@@ -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;

View File

@@ -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"

View File

@@ -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" }}

View File

@@ -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.",

View File

@@ -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;

View File

@@ -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">

View File

@@ -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) ──────── */}

View File

@@ -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;

View File

@@ -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",

View File

@@ -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}

View File

@@ -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 /"

View File

@@ -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}