update miletruth page and remove unwanted files

This commit is contained in:
2026-06-03 13:42:12 +05:30
parent 3bad62851c
commit 6eea5636fb
153 changed files with 6089 additions and 36024 deletions

View File

@@ -74,8 +74,10 @@ export default function CompetitiveEdge() {
<div className="container">
{/* Section Header */}
<div className="comparison-header" ref={headerRef}>
<div className="advantage-badge">DoorMile Advantage</div>
<h2 className="moat-heading">WHERE DOORMILE SITS AND WHY IT WINS</h2>
<div className="advantage-eyebrow-container">
<span className="advantage-eyebrow">/ DoorMile wins/</span>
</div>
<h2 className="moat-heading" data-text="WHERE DOORMILE SITS AND WHY IT WINS">WHERE DOORMILE SITS AND WHY IT WINS</h2>
<p className="moat-desc">
A side-by-side technical capabilities comparison showing how operational fleet ownership and dynamic AI planning disrupt basic aggregators.
</p>
@@ -253,59 +255,61 @@ export default function CompetitiveEdge() {
/* Section Header Layout */
.comparison-header {
text-align: center;
text-align: left;
margin-bottom: 60px;
position: relative;
z-index: 2;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
width: 100%;
}
/* DoorMile Advantage Badge */
.advantage-badge {
.advantage-eyebrow-container {
width: 100%;
border-bottom: 2px solid rgba(0, 0, 0, 0.16);
padding-bottom: 16px;
margin-bottom: 28px;
}
/* DoorMile Advantage Eyebrow */
.advantage-eyebrow {
font-family: 'Manrope', sans-serif;
font-weight: 800;
font-size: 0.75rem;
letter-spacing: 0.12em;
font-weight: 700;
font-size: 0.85rem;
letter-spacing: 0.14em;
text-transform: uppercase;
color: #c8102e;
background: rgba(200, 16, 46, 0.06);
padding: 6px 14px;
border-radius: 30px;
margin: 0 auto 24px auto;
border: 1.5px solid rgba(200, 16, 46, 0.15);
color: #060606ff;
display: inline-block;
white-space: nowrap;
}
/* Centered heading with bottom accent underline */
/* Outlined heading style with clean duplicate layering hack */
.moat-heading {
font-family: 'Manrope', sans-serif;
font-size: clamp(2rem, 3.4vw, 3.2rem); /* Slightly enlarged for premium visual weight */
font-weight: 800;
line-height: 1.15;
color: #111111;
margin: 0 auto 20px auto;
letter-spacing: -0.03em;
position: relative;
font-family: var(--font-syne), 'Syne', sans-serif !important;
font-size: clamp(2.4rem, 6.8vw, 6.6rem) !important;
font-weight: 800 !important;
line-height: 1.1 !important;
color: #fafafa !important; /* solid background color to cover inner overlapping outlines */
margin: 0 0 24px 0;
letter-spacing: -0.02em;
text-transform: uppercase;
word-wrap: break-word;
overflow-wrap: break-word;
display: flex;
flex-direction: column;
align-items: center;
z-index: 1;
}
/* Centered horizontal red underline accent decoration */
.moat-heading::after {
content: "";
display: block;
width: 72px;
height: 4px;
background: #c8102e;
margin-top: 18px;
border-radius: 2px;
content: attr(data-text) !important;
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
z-index: -1;
color: transparent !important;
-webkit-text-stroke: 2.2px #c8102e;
-webkit-text-fill-color: transparent !important;
pointer-events: none;
display: block !important; /* override any old display: none */
}
.moat-desc {
@@ -313,9 +317,9 @@ export default function CompetitiveEdge() {
font-size: 1.05rem;
line-height: 1.65;
color: #585c67;
margin: 16px auto 0 auto !important;
max-width: 760px !important;
text-align: center !important;
margin: 16px 0 0 0 !important;
max-width: 820px !important;
text-align: left !important;
}
/* Spacious table styling wrapper (100% width on Desktop) */

View File

@@ -1,405 +0,0 @@
"use client";
import React, { useState } from "react";
import Image from "next/image";
import { ScrollReveal } from "@/animations/Reveal";
import emailjs from "@emailjs/browser";
// Type definitions for EmailJS template parameters
interface EmailJSTemplateParams extends Record<string, unknown> {
name: string;
email: string;
phone: string;
company: string;
subject: string;
message: string;
}
export default function ContactForm() {
const socialIconSpacing = {
"--grid-column-gap": "52px",
"--grid-row-gap": "18px",
columnGap: "52px",
rowGap: "18px",
} as React.CSSProperties;
const [formData, setFormData] = useState({
fullName: "",
email: "",
subject: "",
message: "",
});
const [formStatus, setFormStatus] = useState<"idle" | "submitting" | "success" | "error">("idle");
const [errorMessage, setErrorMessage] = useState<string>("");
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
const { name, value } = e.target;
setFormData((prev) => ({ ...prev, [name]: value }));
};
// Pre-submission validation function
const validateForm = (): string | null => {
if (!formData.fullName.trim()) {
return "Full name is required.";
}
if (formData.fullName.trim().length < 2) {
return "Full name must be at least 2 characters.";
}
if (!formData.email.trim()) {
return "Email is required.";
}
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!emailRegex.test(formData.email.trim())) {
return "Please enter a valid email address.";
}
if (!formData.subject.trim()) {
return "Subject is required.";
}
if (!formData.message.trim()) {
return "Message is required.";
}
if (formData.message.trim().length < 10) {
return "Message must be at least 10 characters.";
}
return null;
};
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
setErrorMessage("");
// Validate inputs before submitting to EmailJS
const validationError = validateForm();
if (validationError) {
setErrorMessage(validationError);
setFormStatus("error");
return;
}
setFormStatus("submitting");
// Fetch credentials from Next.js environment variables
const serviceId = process.env.NEXT_PUBLIC_EMAILJS_SERVICE_ID;
const templateId = process.env.NEXT_PUBLIC_EMAILJS_TEMPLATE_ID;
const publicKey = process.env.NEXT_PUBLIC_EMAILJS_PUBLIC_KEY;
if (!serviceId || !templateId || !publicKey) {
console.error("EmailJS credentials are not configured in environment variables.");
setErrorMessage("Email service configuration error. Please contact the administrator.");
setFormStatus("error");
return;
}
try {
// Map form fields to EmailJS template variables matching user's template config
const templateParams: EmailJSTemplateParams = {
name: formData.fullName.trim(),
email: formData.email.trim(),
phone: "", // phone is not available in the current contact form UI
company: "", // company is not available in the current contact form UI
subject: formData.subject.trim(),
message: formData.message.trim(),
};
// Send email via EmailJS API
await emailjs.send(serviceId, templateId, templateParams, publicKey);
setFormStatus("success");
// Reset form fields after successful submission
setFormData({ fullName: "", email: "", subject: "", message: "" });
} catch (error) {
console.error("EmailJS Error:", error);
setErrorMessage("Failed to send message. Please try again later.");
setFormStatus("error");
}
};
return (
<div className="elementor elementor-6585">
<style dangerouslySetInnerHTML={{ __html: `
/* ---- Clean contact form (scoped to this section) ---- */
.elementor-6585 .elementor-element.elementor-element-a5c503d {
--padding-top: 60px;
--padding-bottom: 60px;
--padding-left: 60px;
--padding-right: 60px;
}
.elementor-6585 .elementor-element.elementor-element-0e6fedf > .elementor-widget-container {
margin: 4px 0 0 0;
}
/* drop the legacy notched / floating-label borders */
.elementor-6585 .wpforms-form .logico-form-field:before,
.elementor-6585 .wpforms-form .logico-form-field:after,
.elementor-6585 .wpforms-form .logico-label-placeholder { display: none !important; }
/* even field rhythm */
.elementor-6585 .wpforms-form .wpforms-field-container {
display: flex;
flex-direction: column;
gap: 16px;
}
.elementor-6585 .wpforms-form .wpforms-field { padding: 0 !important; margin: 0 !important; }
/* labels stay for screen readers; placeholders carry the visible text */
.elementor-6585 .wpforms-form .wpforms-field-label {
position: absolute !important;
width: 1px; height: 1px;
padding: 0; margin: -1px;
overflow: hidden; clip: rect(0 0 0 0);
white-space: nowrap; border: 0;
}
/* clean rounded inputs */
.elementor-6585 .wpforms-form input[type="text"],
.elementor-6585 .wpforms-form input[type="email"],
.elementor-6585 .wpforms-form textarea {
width: 100%;
border: 1px solid #e3e3e3 !important;
border-radius: 12px !important;
padding: 16px 20px !important;
font-size: 15px;
line-height: 1.5;
color: #111;
background: #fff;
box-shadow: none !important;
transition: border-color .25s ease;
}
.elementor-6585 .wpforms-form textarea { min-height: 150px; resize: vertical; }
.elementor-6585 .wpforms-form input::placeholder,
.elementor-6585 .wpforms-form textarea::placeholder { color: #9a9a9a; opacity: 1; }
.elementor-6585 .wpforms-form input:focus,
.elementor-6585 .wpforms-form textarea:focus { border-color: #c01227 !important; outline: none; }
.elementor-6585 .wpforms-form .wpforms-submit-container { padding-top: 26px !important; }
@media (max-width: 1020px) {
.elementor-6585 .elementor-element.elementor-element-a5c503d {
--padding-top: 40px;
--padding-bottom: 40px;
--padding-left: 32px;
--padding-right: 32px;
}
}
` }} />
<div className="elementor-element elementor-element-3cd920c e-con-full e-flex cut-corner-no sticky-container-off e-con e-parent" data-id="3cd920c" data-element_type="container" data-e-type="container">
<div className="elementor-element elementor-element-b29b8fc e-flex e-con-boxed cut-corner-no sticky-container-off e-con e-child" data-id="b29b8fc" data-element_type="container" data-e-type="container" data-settings="{&quot;background_background&quot;:&quot;classic&quot;}">
<div className="e-con-inner">
<div className="elementor-element elementor-element-ef6fa6d e-con-full e-flex cut-corner-no sticky-container-off e-con e-child" data-id="ef6fa6d" data-element_type="container" data-e-type="container">
{/* Left Dark Panel */}
<div className="elementor-element elementor-element-9990148 e-con-full e-flex cut-corner-no sticky-container-off e-con e-child" data-id="9990148" data-element_type="container" data-e-type="container">
<div className="elementor-element elementor-element-8899bdf elementor-absolute elementor-widget elementor-widget-image" data-id="8899bdf" data-element_type="widget" data-e-type="widget" data-settings="{&quot;_position&quot;:&quot;absolute&quot;}" data-widget_type="image.default">
<div className="elementor-widget-container">
<Image width={965} height={474} src="/images/bg-map.png" className="attachment-full size-full wp-image-1148" alt="" />
</div>
</div>
<div className="elementor-element elementor-element-a0e7516 elementor-widget elementor-widget-logico_heading" data-id="a0e7516" data-element_type="widget" data-e-type="widget" data-widget_type="logico_heading.default">
<div className="elementor-widget-container">
<div className="logico-title">/ get in touch /</div>
</div>
</div>
<div className="elementor-element elementor-element-51cdf4f elementor-widget elementor-widget-logico_heading" data-id="51cdf4f" data-element_type="widget" data-e-type="widget" data-widget_type="logico_heading.default">
<div className="elementor-widget-container">
<ScrollReveal delay={0.1} duration={0.8} yOffset={25}>
<h3 className="logico-title">
We are always ready to help you and answer your questions
</h3>
</ScrollReveal>
</div>
</div>
<div className="elementor-element elementor-element-670d1b2 elementor-widget elementor-widget-text-editor" data-id="670d1b2" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
<div className="elementor-widget-container">
<p>Connecting businesses with fast, secure, smart deliveries.</p>
</div>
</div>
<div className="elementor-element elementor-element-2631b42 e-flex e-con-boxed cut-corner-no sticky-container-off e-con e-child" data-id="2631b42" data-element_type="container" data-e-type="container">
<div className="e-con-inner">
<div className="elementor-element elementor-element-df89993 e-con-full e-flex cut-corner-no sticky-container-off e-con e-child" data-id="df89993" data-element_type="container" data-e-type="container">
<div className="elementor-element elementor-element-69b6892 elementor-widget elementor-widget-logico_heading" data-id="69b6892" data-element_type="widget" data-e-type="widget" data-widget_type="logico_heading.default">
<div className="elementor-widget-container">
<div className="logico-title">Call Center</div>
</div>
</div>
<div className="elementor-element elementor-element-87be926 elementor-widget elementor-widget-text-editor" data-id="87be926" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
<div className="elementor-widget-container">
<p>Tel : +91 86886 97941</p>
</div>
</div>
</div>
<div className="elementor-element elementor-element-f5d8e63 e-con-full e-flex cut-corner-no sticky-container-off e-con e-child" data-id="f5d8e63" data-element_type="container" data-e-type="container">
<div className="elementor-element elementor-element-774e540 elementor-widget elementor-widget-logico_heading" data-id="774e540" data-element_type="widget" data-e-type="widget" data-widget_type="logico_heading.default">
<div className="elementor-widget-container">
<div className="logico-title">Our Location</div>
</div>
</div>
<div className="elementor-element elementor-element-9c1cf03 elementor-widget elementor-widget-text-editor" data-id="9c1cf03" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
<div className="elementor-widget-container">
<p>5th Floor, Vision Ultima, Street No.3, Jayabheri Enclave, Gachibowli, Hyderabad, Telangana 500032.</p>
</div>
</div>
</div>
</div>
</div>
<div className="elementor-element elementor-element-645be8d e-flex e-con-boxed cut-corner-no sticky-container-off e-con e-child" data-id="645be8d" data-element_type="container" data-e-type="container">
<div className="e-con-inner">
<div className="elementor-element elementor-element-a96d151 e-con-full e-flex cut-corner-no sticky-container-off e-con e-child" data-id="a96d151" data-element_type="container" data-e-type="container">
<div className="elementor-element elementor-element-37e647f elementor-widget elementor-widget-logico_heading" data-id="37e647f" data-element_type="widget" data-e-type="widget" data-widget_type="logico_heading.default">
<div className="elementor-widget-container">
<div className="logico-title">Email</div>
</div>
</div>
<div className="elementor-element elementor-element-ba67644 elementor-widget elementor-widget-text-editor" data-id="ba67644" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
<div className="elementor-widget-container">
<p>
<a href="mailto:care@doormile.com">care@doormile.com</a>
</p>
</div>
</div>
</div>
<div className="elementor-element elementor-element-9ba4b82 e-con-full e-flex cut-corner-no sticky-container-off e-con e-child" data-id="9ba4b82" data-element_type="container" data-e-type="container">
<div className="elementor-element elementor-element-e9a5d79 elementor-widget elementor-widget-logico_heading" data-id="e9a5d79" data-element_type="widget" data-e-type="widget" data-widget_type="logico_heading.default">
<div className="elementor-widget-container">
<div className="logico-title">Social network</div>
</div>
</div>
<div className="elementor-element elementor-element-a6bccba elementor-shape-square elementor-grid-0 elementor-widget elementor-widget-social-icons" data-id="a6bccba" data-element_type="widget" data-e-type="widget" data-widget_type="social-icons.default">
<div className="elementor-widget-container">
<div className="elementor-social-icons-wrapper elementor-grid" role="list" style={socialIconSpacing}>
<span className="elementor-grid-item" role="listitem" style={{padding:"0 15px"}}>
<a className="elementor-icon elementor-social-icon elementor-social-icon-facebook-f elementor-repeater-item-3fbe893" href="https://www.facebook.com" target="_blank" rel="noopener noreferrer">
<span className="elementor-screen-only">Facebook</span>
<svg aria-hidden="true" className="e-font-icon-svg e-fab-facebook-f" viewBox="0 0 320 512" xmlns="http://www.w3.org/2000/svg">
<path d="M279.14 288l14.22-92.66h-88.91v-60.13c0-25.35 12.42-50.06 52.24-50.06h40.42V6.26S260.43 0 225.36 0c-73.22 0-121.08 44.38-121.08 124.72v70.62H22.89V288h81.39v224h100.17V288z"></path>
</svg>
</a>
</span>
<span className="elementor-grid-item" role="listitem" style={{padding:"0 15px"}}>
<a className="elementor-icon elementor-social-icon elementor-social-icon-x-twitter elementor-repeater-item-64ac94e" href="https://x.com" target="_blank" rel="noopener noreferrer">
<span className="elementor-screen-only">X</span>
<svg aria-hidden="true" className="e-font-icon-svg e-fab-x-twitter" viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg">
<path d="M389.2 48h70.6L305.6 224.2 487 464H345L233.7 318.6 106.5 464H35.8L200.7 275.5 26.8 48H172.4L272.9 180.9 389.2 48zM364.4 421.8h39.1L151.1 88h-42L364.4 421.8z"></path>
</svg>
</a>
</span>
<span className="elementor-grid-item" role="listitem" style={{padding:"0 15px"}}>
<a className="elementor-icon elementor-social-icon elementor-social-icon-linkedin-in elementor-repeater-item-38e1bcc" href="https://www.linkedin.com" target="_blank" rel="noopener noreferrer">
<span className="elementor-screen-only">LinkedIn</span>
<svg aria-hidden="true" className="e-font-icon-svg e-fab-linkedin-in" viewBox="0 0 448 512" xmlns="http://www.w3.org/2000/svg">
<path d="M100.28 448H7.4V148.9h92.88zM53.79 108.1C24.09 108.1 0 83.5 0 53.8a53.79 53.79 0 0 1 107.58 0c0 29.7-24.1 54.3-53.79 54.3zM447.9 448h-92.68V302.4c0-34.7-.7-79.2-48.29-79.2-48.29 0-55.69 37.7-55.69 76.7V448h-92.78V148.9h89.08v40.8h1.3c12.4-23.5 42.69-48.3 87.88-48.3 94 0 111.28 61.9 111.28 142.3V448z"></path>
</svg>
</a>
</span>
<span className="elementor-grid-item" role="listitem" style={{padding:"0 15px"}}>
<a className="elementor-icon elementor-social-icon elementor-social-icon-youtube elementor-repeater-item-b0d5e1f" href="https://www.youtube.com" target="_blank" rel="noopener noreferrer">
<span className="elementor-screen-only">YouTube</span>
<svg aria-hidden="true" className="e-font-icon-svg e-fab-youtube" viewBox="0 0 576 512" xmlns="http://www.w3.org/2000/svg">
<path d="M549.655 124.083c-6.281-23.65-24.787-42.276-48.284-48.597C458.781 64 288 64 288 64S117.22 64 74.629 75.486c-23.497 6.322-42.003 24.947-48.284 48.597-11.412 42.867-11.412 132.305-11.412 132.305s0 89.438 11.412 132.305c6.281 23.65 24.787 41.5 48.284 47.821C117.22 448 288 448 288 448s170.78 0 213.371-11.486c23.497-6.321 42.003-24.171 48.284-47.821 11.412-42.867 11.412-132.305 11.412-132.305s0-89.438-11.412-132.305zm-317.51 213.508V175.185l142.739 81.205-142.739 81.201z"></path>
</svg>
</a>
</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{/* Right White Form Card */}
<div className="elementor-element elementor-element-a5c503d e-con-full e-flex cut-corner-no sticky-container-off e-con e-child" data-id="a5c503d" data-element_type="container" data-e-type="container" data-settings="{&quot;background_background&quot;:&quot;classic&quot;}">
<div className="elementor-element elementor-element-535776a elementor-widget elementor-widget-logico_heading" data-id="535776a" data-element_type="widget" data-e-type="widget" data-widget_type="logico_heading.default">
<div className="elementor-widget-container">
<div className="logico-title">Get in Touch</div>
</div>
</div>
<div className="elementor-element elementor-element-0e6fedf elementor-widget elementor-widget-logico_wpforms" data-id="0e6fedf" data-element_type="widget" data-e-type="widget" data-widget_type="logico_wpforms.default">
<div className="elementor-widget-container">
<div className="logico-wpforms-widget">
<div className="wpforms-container wpforms-render-modern" id="wpforms-369-contact">
<form id="wpforms-form-369-contact" className="wpforms-validate wpforms-form" onSubmit={handleSubmit} noValidate>
<div className="wpforms-field-container">
<div className="wpforms-field logico-form-field">
<label className="wpforms-field-label" htmlFor="contact-field-name">Full name</label>
<input
type="text"
id="contact-field-name"
name="fullName"
placeholder="Full name"
value={formData.fullName}
onChange={handleInputChange}
required
/>
</div>
<div className="wpforms-field logico-form-field">
<label className="wpforms-field-label" htmlFor="contact-field-email">Email</label>
<input
type="email"
id="contact-field-email"
name="email"
placeholder="Email"
value={formData.email}
onChange={handleInputChange}
required
/>
</div>
<div className="wpforms-field logico-form-field">
<label className="wpforms-field-label" htmlFor="contact-field-subject">Subject</label>
<input
type="text"
id="contact-field-subject"
name="subject"
placeholder="Subject"
value={formData.subject}
onChange={handleInputChange}
required
/>
</div>
<div className="wpforms-field logico-form-field">
<label className="wpforms-field-label" htmlFor="contact-field-message">Message</label>
<textarea
id="contact-field-message"
name="message"
placeholder="Message"
value={formData.message}
onChange={handleInputChange}
required
></textarea>
</div>
</div>
<div className="wpforms-submit-container">
<button
type="submit"
id="wpforms-submit-369-contact"
className="logico-alter-button wpforms-submit"
disabled={formStatus === "submitting"}
>
{formStatus === "submitting" ? "Sending..." : "Send a message"}
</button>
{formStatus === "success" && (
<div style={{ color: "#4caf50", marginTop: "10px", fontSize: "14px" }}>
Message sent successfully!
</div>
)}
{formStatus === "error" && (
<div style={{ color: "#f44336", marginTop: "10px", fontSize: "14px" }}>
{errorMessage || "Something went wrong. Please try again."}
</div>
)}
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
);
}

View File

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

View File

@@ -8,46 +8,50 @@ if (typeof window !== "undefined") {
gsap.registerPlugin(ScrollTrigger);
}
const PILLS: { value: string; label: string }[] = [
{ value: "100%", label: "Electric Fleet" },
{ value: "Live", label: "Route Sync" },
{ value: "Real-time", label: "Battery Monitoring" },
];
const MINI_STATS: { value: number; decimals?: number; suffix: string; label: string }[] = [
{ value: 94, suffix: "K+", label: "Routes Optimised" },
{ value: 23, suffix: "%", label: "Avg Battery Saved" },
{ value: 1.4, decimals: 1, suffix: "x", label: "Charging Stops Saved" },
];
const FEATURES: { icon: string; title: string; desc: string }[] = [
const FEATURES: { icon: React.ReactNode; title: string; desc: string }[] = [
{
icon: "⚡",
icon: (
<svg className="evnd-icon" viewBox="0 0 24 24" fill="none" stroke="#f59e0b" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2" />
</svg>
),
title: "Battery-Aware Routing",
desc: "Battery level, health, and degradation are first-class inputs to route optimization — not afterthoughts.",
},
{
icon: "🔌",
icon: (
<svg className="evnd-icon" viewBox="0 0 24 24" fill="none" stroke="#94a3b8" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<path d="M18 10h-1.28A6 6 0 0 0 12 5V3M12 5V3M6 10h1.28A6 6 0 0 0 12 5M12 18v2M12 18v2M8 10v6a4 4 0 0 0 8 0v-6" />
</svg>
),
title: "Charging Integration",
desc: "Seamlessly integrate charging stops without compromising delivery windows or SLA commitments.",
},
{
icon: "⛰",
icon: (
<svg className="evnd-icon" viewBox="0 0 24 24" fill="none" stroke="#ef4444" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<path d="m8 3 4 8 5-5 5 15H2L8 3z" />
</svg>
),
title: "Energy-Optimized Paths",
desc: "Factor in elevation, speed limits, payload weight, and live weather for maximum range efficiency.",
},
{
icon: "🛡",
icon: (
<svg className="evnd-icon" viewBox="0 0 24 24" fill="none" stroke="#ef4444" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z" />
</svg>
),
title: "Predictable Operations",
desc: "EVs become predictable assets, not operational risks. Full visibility from depot to doorstep.",
},
];
const BOTTOM_STATS: { value: number; decimals?: number; suffix: string; label: string }[] = [
{ value: 120, suffix: "K+", label: "Deliveries Completed" },
{ value: 98, suffix: "%", label: "On-Time Rate" },
{ value: 31, suffix: "%", label: "Range Efficiency Gain" },
{ value: 340, suffix: "ms", label: "Avg Route Calc Time" },
{ value: 99.9, decimals: 1, suffix: "%", label: "SLA Compliance" },
{ value: 42, suffix: "%", label: "Distance Saved" },
{ value: 37, suffix: "%", label: "Fewer Vehicles" },
{ value: 45, suffix: "ms", label: "Dispatch Latency" },
];
/** Count-up that fires once when scrolled ~20% into view (ease-out cubic). */
@@ -143,7 +147,7 @@ export default function EVSection() {
<style dangerouslySetInnerHTML={{ __html: `
/* ============================================================
EV-Native Design — redesigned section
bg #0d0d0d · red #dc2626 / #ef4444 · Syne + DM Sans
bg #080808 · red #ef4444 · Manrope
============================================================ */
#evnd, #evnd * { font-family: "Manrope", Sans-serif !important; }
@@ -152,12 +156,12 @@ export default function EVSection() {
position: relative;
isolation: isolate;
overflow: hidden;
background: #0d0d0d;
background: #080808;
/* flat top so it connects seamlessly to the banner above; rounded
bottom only, and no top margin so there is no white gap */
border-radius: 0 0 clamp(16px, 2vw, 28px) clamp(16px, 2vw, 28px);
margin: 0 0 clamp(28px, 5vw, 64px);
padding: 56px 48px 64px;
padding: 64px 48px clamp(48px, 6vw, 80px);
}
/* subtle diagonal light band for depth (matches reference) */
.evnd::before {
@@ -166,181 +170,206 @@ export default function EVSection() {
inset: 0;
z-index: 0;
pointer-events: none;
background: linear-gradient(120deg, transparent 28%, rgba(255,255,255,0.025) 50%, transparent 72%);
}
.evnd__canvas {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
z-index: 0;
pointer-events: none;
background: linear-gradient(120deg, transparent 28%, rgba(255,255,255,0.015) 50%, transparent 72%);
}
.evnd__inner { position: relative; z-index: 1; max-width: 1280px; margin: 0 auto; }
/* ---- TOP ROW ---- */
.evnd__top {
/* ---- MAIN GRID ---- */
.evnd__grid {
display: grid;
grid-template-columns: 1.5fr 1fr;
gap: 44px;
grid-template-columns: 1.15fr 1fr;
gap: clamp(32px, 4vw, 56px);
align-items: center;
margin-bottom: 48px;
}
.evnd__left {
display: flex;
flex-direction: column;
align-items: flex-start;
}
.evnd__right {
display: flex;
flex-direction: column;
}
.evnd__eyebrow {
display: inline-flex;
align-items: center;
gap: 12px;
color: #dc2626 !important;
font-weight: 700;
color: #ef4444 !important;
font-weight: 800;
text-transform: uppercase;
letter-spacing: 0.16em;
font-size: 13px;
margin-bottom: 16px;
margin-bottom: 20px;
}
.evnd__eyebrow::before { content: ''; width: 24px; height: 2px; background: #dc2626; }
.evnd__eyebrow::before {
content: '';
width: 16px;
height: 2px;
background: #ef4444;
}
.evnd__title {
color: #fff !important;
font-weight: 800 !important;
font-size: clamp(30px, 4.4vw, 56px) !important;
line-height: 1.04 !important;
font-size: clamp(32px, 3.8vw, 48px) !important;
line-height: 1.15 !important;
letter-spacing: -0.01em;
margin: 0;
margin: 0 0 36px 0;
}
.evnd__title .accent { color: #ef4444 !important; }
.evnd__pills { display: flex; flex-direction: column; gap: 12px; }
.evnd__pill {
display: flex;
align-items: center;
gap: 12px;
padding: 13px 20px;
background: rgba(255,255,255,0.04);
border: 1px solid rgba(255,255,255,0.08);
border-radius: 100px;
@media (min-width: 768px) {
.evnd__title {
white-space: nowrap;
}
}
.evnd__pill .dot {
flex: 0 0 auto;
width: 8px; height: 8px;
border-radius: 50%;
background: #22c55e;
box-shadow: 0 0 8px #22c55e;
animation: evndBlink 1.4s ease-in-out infinite;
.evnd__title .accent {
color: #ef4444 !important;
}
.evnd__pill b { color: #ef4444 !important; font-weight: 800; font-size: 15px; }
.evnd__pill span { color: rgba(255,255,255,0.62) !important; font-size: 13px; }
/* ---- MAIN GRID ---- */
.evnd__grid { display: grid; grid-template-columns: 1fr 1fr; gap: 40px; align-items: start; }
.evnd__media { position: relative; }
.evnd__media {
position: relative;
width: 100%;
}
.evnd__glow {
position: absolute;
left: 50%; bottom: -4%;
width: 72%; height: 64px;
width: 80%; height: 80px;
transform: translateX(-50%);
background: radial-gradient(50% 50% at 50% 50%, rgba(220,38,38,0.5), transparent 72%);
filter: blur(30px);
background: radial-gradient(50% 50% at 50% 50%, rgba(239,68,68,0.3), transparent 72%);
filter: blur(35px);
z-index: 0;
animation: evndGlow 4s ease-in-out infinite;
}
.evnd__imgwrap { position: relative; z-index: 1; animation: evndFloat 7s ease-in-out infinite; will-change: transform; }
.evnd__imgwrap {
position: relative;
z-index: 1;
overflow: hidden;
border-radius: 16px;
border: 1px solid rgba(255,255,255,0.06);
box-shadow: 0 30px 60px -25px rgba(0,0,0,0.85);
}
.evnd__img {
display: block;
width: 100%;
height: auto;
border-radius: 14px;
box-shadow: 0 30px 60px -25px rgba(0,0,0,0.7);
object-fit: cover;
transition: transform 0.8s cubic-bezier(0.25, 1, 0.5, 1);
}
.evnd__imgwrap:hover .evnd__img {
transform: scale(1.03);
}
/* Badge overlay styling */
.evnd__badge {
position: absolute;
z-index: 2;
display: flex;
flex-direction: column;
gap: 2px;
padding: 10px 14px;
background: rgba(10,10,10,0.88);
border: 1px solid rgba(255,255,255,0.1);
padding: 12px 16px;
background: rgba(13,13,13,0.72);
border: 1px solid rgba(255,255,255,0.08);
border-radius: 8px;
backdrop-filter: blur(12px);
-webkit-backdrop-filter: blur(12px);
}
.evnd__badge b { color: #ef4444 !important; font-weight: 800; font-size: 24px; line-height: 1; }
.evnd__badge span { color: rgba(255,255,255,0.55) !important; font-size: 10px; letter-spacing: 0.08em; text-transform: uppercase; }
.evnd__badge--tl { top: 14px; left: 14px; }
.evnd__badge--br { bottom: 14px; right: 14px; }
.evnd__ministats { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; margin-top: 20px; }
.evnd__mini {
position: relative;
background: rgba(255,255,255,0.03);
border: 1px solid rgba(255,255,255,0.06);
border-radius: 10px;
padding: 18px 14px 14px;
overflow: hidden;
.evnd__badge b {
color: #ef4444 !important;
font-weight: 800;
font-size: 24px;
line-height: 1;
}
.evnd__mini::before {
content: '';
position: absolute; top: 0; left: 0; right: 0;
height: 2px;
background: linear-gradient(90deg, #dc2626, transparent);
.evnd__badge span {
color: rgba(255,255,255,0.7) !important;
font-size: 10px;
font-weight: 700;
letter-spacing: 0.08em;
text-transform: uppercase;
}
.evnd__mini b { display: block; color: #fff !important; font-weight: 800; font-size: clamp(20px, 2.3vw, 28px); line-height: 1; margin-bottom: 6px; }
.evnd__mini span { color: rgba(255,255,255,0.5) !important; font-size: 11px; letter-spacing: 0.04em; text-transform: uppercase; line-height: 1.3; display: block; }
.evnd__badge--tl { top: 20px; left: 20px; }
.evnd__badge--br { bottom: 20px; right: 20px; }
/* ---- Feature cards ---- */
.evnd__features { display: flex; flex-direction: column; gap: 10px; }
.evnd__features {
display: flex;
flex-direction: column;
gap: 16px;
height: 100%;
justify-content: space-between;
}
.evnd-feature {
position: relative;
display: grid;
grid-template-columns: 40px 1fr auto;
gap: 16px;
grid-template-columns: 48px 1fr auto;
gap: 20px;
align-items: start;
background: rgba(255,255,255,0.028);
border: 1px solid rgba(255,255,255,0.07);
border-radius: 12px;
padding: 18px 20px;
background: rgba(255,255,255,0.02);
border: 1px solid rgba(255,255,255,0.05);
border-radius: 16px;
padding: 24px;
overflow: hidden;
transition: background-color 0.35s ease, border-color 0.35s ease, transform 0.35s cubic-bezier(.25,1,.5,1);
transition: background-color 0.4s ease, border-color 0.4s ease, transform 0.4s cubic-bezier(.25,1,.5,1);
}
.evnd-feature::before {
content: '';
position: absolute;
left: 0; top: 0; bottom: 0;
width: 3px;
background: #dc2626;
background: #ef4444;
transform: scaleY(0);
transform-origin: bottom;
transition: transform 0.35s ease;
transition: transform 0.4s ease;
}
.evnd-feature:hover {
background: rgba(239,68,68,0.03);
border-color: rgba(239,68,68,0.2);
transform: translateY(-2px);
}
.evnd-feature:hover { background: rgba(220,38,38,0.06); border-color: rgba(220,38,38,0.25); transform: translateX(4px); }
.evnd-feature:hover::before { transform: scaleY(1); }
.evnd-feature__icon {
width: 40px; height: 40px;
.evnd-feature__icon-container {
width: 48px; height: 48px;
display: flex; align-items: center; justify-content: center;
background: rgba(220,38,38,0.1);
border: 1px solid rgba(220,38,38,0.2);
border-radius: 10px;
font-size: 18px;
background: rgba(255,255,255,0.03);
border: 1px solid rgba(255,255,255,0.08);
border-radius: 12px;
transition: background-color 0.3s ease, border-color 0.3s ease;
}
.evnd-feature:hover .evnd-feature__icon-container {
background: rgba(239,68,68,0.08);
border-color: rgba(239,68,68,0.25);
}
.evnd-icon {
width: 22px;
height: 22px;
display: block;
}
.evnd-feature__title {
color: #fff !important;
font-weight: 700;
font-size: 15px !important;
text-transform: uppercase;
letter-spacing: 0.04em;
margin: 3px 0 7px;
letter-spacing: 0.05em;
margin: 4px 0 8px;
transition: color 0.3s ease;
}
.evnd-feature:hover .evnd-feature__title { color: #ef4444 !important; }
.evnd-feature__desc {
color: rgba(255,255,255,0.75) !important;
color: rgba(255,255,255,0.65) !important;
font-weight: 400 !important;
font-size: 14.5px !important;
line-height: 1.65 !important;
font-size: 14px !important;
line-height: 1.6 !important;
margin: 0;
}
.evnd-feature__arrow {
color: rgba(255,255,255,0.2);
font-size: 14px;
color: rgba(255,255,255,0.25);
font-size: 16px;
align-self: flex-start;
margin-top: 4px;
transition: color 0.3s ease, transform 0.3s ease;
}
.evnd-feature:hover .evnd-feature__arrow { color: #ef4444; transform: translate(3px, -3px); }
@@ -349,47 +378,69 @@ export default function EVSection() {
.evnd__bar {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 1px;
background: rgba(255,255,255,0.06);
border-radius: 12px;
background: rgba(255,255,255,0.02);
border: 1px solid rgba(255,255,255,0.06);
border-radius: 16px;
overflow: hidden;
margin-top: 40px;
margin-top: 60px;
padding: 38px 0;
}
.evnd__bar-item {
background: #0d0d0d;
padding: 24px 22px;
position: relative;
display: flex;
flex-direction: column;
gap: 8px;
align-items: flex-start;
gap: 12px;
align-items: center;
justify-content: center;
text-align: center;
padding: 12px 24px;
}
.evnd__bar-item .dot {
width: 7px; height: 7px;
border-radius: 50%;
background: #dc2626;
box-shadow: 0 0 8px rgba(220,38,38,0.85);
animation: evndBlink 1.4s ease-in-out infinite;
.evnd__bar-item:not(:last-child)::after {
content: '';
position: absolute;
right: 0;
top: 15%;
height: 70%;
width: 1px;
background: rgba(255, 255, 255, 0.08);
}
.evnd__bar-val {
color: #ef4444 !important;
font-weight: 800;
font-size: clamp(32px, 4vw, 56px);
line-height: 1;
}
.evnd__bar-label {
color: #fff !important;
font-size: 14px;
font-weight: 600;
letter-spacing: 0.02em;
text-transform: none;
opacity: 0.9;
}
.evnd__bar-item b { color: #fff !important; font-weight: 800; font-size: clamp(22px, 2.6vw, 30px); line-height: 1; }
.evnd__bar-item span { color: rgba(255,255,255,0.45) !important; font-size: 11px; letter-spacing: 0.06em; text-transform: uppercase; }
@keyframes evndFloat { 0%,100% { transform: translateY(0); } 50% { transform: translateY(-7px); } }
@keyframes evndGlow { 0%,100% { opacity: 0.6; } 50% { opacity: 1; } }
@keyframes evndBlink { 0%,100% { opacity: 1; } 50% { opacity: 0.3; } }
@keyframes evndGlow { 0%,100% { opacity: 0.75; } 50% { opacity: 1; } }
/* ---- Responsive ---- */
@media (max-width: 900px) {
.evnd { padding: 48px 28px 52px; }
.evnd__top { grid-template-columns: 1fr; gap: 28px; margin-bottom: 36px; }
.evnd__grid { grid-template-columns: 1fr; gap: 36px; }
@media (max-width: 991px) {
.evnd { padding: 48px 32px 56px; }
.evnd__grid { grid-template-columns: 1fr; gap: 40px; }
.evnd__title { margin-bottom: 28px; }
.evnd__features { gap: 14px; }
}
@media (max-width: 600px) {
.evnd { padding: 40px 18px 44px; }
.evnd__bar { grid-template-columns: repeat(2, 1fr); }
.evnd__pill { padding: 11px 16px; }
@media (max-width: 767px) {
.evnd__bar { grid-template-columns: repeat(2, 1fr); gap: 24px 0; padding: 24px 0; }
.evnd__bar-item:nth-child(even)::after { display: none; }
.evnd__bar-item:nth-child(2)::after { display: none; }
.evnd__bar-item { padding: 12px 16px; }
}
@media (prefers-reduced-motion: reduce) {
.evnd__imgwrap, .evnd__glow, .evnd__pill .dot, .evnd__bar-item .dot { animation: none !important; }
@media (max-width: 480px) {
.evnd { padding: 40px 16px 48px; }
.evnd__bar { grid-template-columns: 1fr; gap: 28px 0; }
.evnd__bar-item::after { display: none !important; }
.evnd__badge { padding: 8px 12px; }
.evnd__badge b { font-size: 20px; }
}
`}} />
@@ -441,24 +492,10 @@ export default function EVSection() {
{/* ===== EV-Native Design (redesigned) ===== */}
<section className="evnd" id="evnd" aria-label="EV-Native Design">
<div className="evnd__inner">
{/* TOP ROW */}
<div className="evnd__top">
<div className="evnd__head">
<span className="evnd__eyebrow">/ EV-Native Design /</span>
<div className="evnd__title">
BUILT FOR ELECTRIC. <span className="accent">NOT ADAPTED.</span>
</div>
</div>
<div className="evnd__pills">
{PILLS.map((p) => (
<div className="evnd__pill" key={p.label}>
<span className="dot" />
<b>{p.value}</b>
<span>{p.label}</span>
</div>
))}
</div>
</div>
<span className="evnd__eyebrow">/ EV-Native Design /</span>
<h2 className="evnd__title">
BUILT FOR ELECTRIC. <span className="accent">NOT ADAPTED.</span>
</h2>
{/* MAIN GRID */}
<div className="evnd__grid">
@@ -471,37 +508,32 @@ export default function EVSection() {
<img className="evnd__img" src="/images/premium-ev-van.png" alt="DoorMile electric delivery van" decoding="async" />
<div className="evnd__badge evnd__badge--tl">
<b>100%</b>
<span>Electric Fleet</span>
<span>ELECTRIC FLEET</span>
</div>
<div className="evnd__badge evnd__badge--br">
<b>&minus;40%</b>
<span>Cost / Mile</span>
<b>-40%</b>
<span>COST / MILE</span>
</div>
</div>
</div>
<div className="evnd__ministats">
{MINI_STATS.map((s) => (
<div className="evnd__mini" key={s.label}>
<CountUp value={s.value} decimals={s.decimals} suffix={s.suffix} />
<span>{s.label}</span>
</div>
))}
</div>
</div>
{/* Right column */}
<div className="evnd__features">
{FEATURES.map((f) => (
<div className="evnd-feature" key={f.title}>
<span className="evnd-feature__icon" aria-hidden="true">{f.icon}</span>
<div className="evnd-feature__body">
<div className="evnd-feature__title">{f.title}</div>
<p className="evnd-feature__desc">{f.desc}</p>
<div className="evnd__right">
<div className="evnd__features">
{FEATURES.map((f) => (
<div className="evnd-feature" key={f.title}>
<div className="evnd-feature__icon-container" aria-hidden="true">
{f.icon}
</div>
<div className="evnd-feature__body">
<div className="evnd-feature__title">{f.title}</div>
<p className="evnd-feature__desc">{f.desc}</p>
</div>
<span className="evnd-feature__arrow" aria-hidden="true"></span>
</div>
<span className="evnd-feature__arrow" aria-hidden="true"></span>
</div>
))}
))}
</div>
</div>
</div>
@@ -509,9 +541,8 @@ export default function EVSection() {
<div className="evnd__bar">
{BOTTOM_STATS.map((s) => (
<div className="evnd__bar-item" key={s.label}>
<span className="dot" />
<CountUp value={s.value} decimals={s.decimals} suffix={s.suffix} />
<span>{s.label}</span>
<span className="evnd__bar-label">{s.label}</span>
<CountUp value={s.value} decimals={s.decimals} suffix={s.suffix} className="evnd__bar-val" />
</div>
))}
</div>

View File

@@ -25,15 +25,16 @@ export default function IndustrySolutions() {
style={{marginLeft: "50px"}}
>
<div className="elementor-widget-container" style={{ margin: "30px 0 0 0"}}>
<h3 className="logico-title" style={{ fontSize: "clamp(36px, 5.5vw, 62px)", lineHeight: "1.1", fontWeight: 800, textTransform: "uppercase", paddingRight: "clamp(20px, 8vw, 120px)" }}>
<style dangerouslySetInnerHTML={{ __html: `
@media (min-width: 1024px) {
.industry-title-single-line {
white-space: nowrap !important;
}
}
`}} />
<h3 className="logico-title industry-title-single-line" style={{ fontSize: "clamp(28px, 3.5vw, 48px)", lineHeight: "1.1", fontWeight: 800, textTransform: "uppercase" }}>
<ScrollReveal delay={0.05} duration={0.8} yOffset={25}>
<span className="block">Smart solutions built</span>
</ScrollReveal>
<ScrollReveal delay={0.15} duration={0.8} yOffset={25}>
<span className="block">exclusively for your</span>
</ScrollReveal>
<ScrollReveal delay={0.25} duration={0.8} yOffset={25}>
<span className="block" style={{ color: "#c01227" }}>industry</span>
Smart solutions built exclusively for your <span style={{ color: "#c01227" }}>industry</span>
</ScrollReveal>
</h3>
</div>

View File

@@ -1,498 +0,0 @@
"use client";
import React, { useState } from "react";
import IndustryWorldMap from "./IndustryWorldMap";
type Tab = "challenges" | "solutions";
interface Industry {
id: string;
tab: string;
eyebrow: string;
title: string;
image: string;
alt: string;
desc: string;
chips: [string, string];
challenges: string[];
solutions: string[];
}
const INDUSTRIES: Industry[] = [
{
id: "fmcg",
tab: "FMCG",
eyebrow: "Fast-Moving Consumer Goods",
title: "FMCG",
image: "/images/tab-pic-1-solution.jpeg",
alt: "FMCG logistics",
desc:
"FMCG logistics demands speed, precision, and continuous fulfillment across high-volume delivery networks — balancing tight timelines, inventory movement, and efficiency without compromising availability.",
chips: ["99.2% On-Time", "Live Route Sync"],
challenges: [
"Unpredictable demand spikes create delivery pressure during peak periods.",
"Fresh-product expiry constraints require faster, precisely timed deliveries.",
"Multi-stop route complexity increases travel time and coordination cost.",
"Inventory stockout risks rise when delays disrupt fast-moving distribution.",
],
solutions: [
"AI demand forecasting adapts delivery plans instantly to real-time order demand.",
"Expiry-aware routing prioritises perishable goods for on-time freshness.",
"Smart multi-stop optimisation groups orders to cut cost and travel time.",
"Real-time inventory sync prevents stockouts and improves fulfilment accuracy.",
],
},
{
id: "pharma",
tab: "Pharma",
eyebrow: "Pharmaceutical Logistics",
title: "Pharma",
image: "/images/tab-pic-2-solution.jpeg",
alt: "Pharma logistics",
desc:
"Pharma logistics requires precision, compliance, and real-time monitoring so every shipment arrives safely and on time — from temperature-sensitive medicines to urgent emergency deliveries.",
chips: ["Cold Chain Active", "Zero Delay SLA"],
challenges: [
"Cold chain integrity demands precise temperature control throughout transit.",
"Regulatory compliance must be tracked and documented on every delivery.",
"Critical delivery time windows require highly accurate scheduling.",
"Emergency shipments need instant dispatch and zero-delay execution.",
],
solutions: [
"Cold chain monitoring with automatic re-routing keeps shipments in-spec.",
"Compliance engine with audit trails ensures full chain-of-custody visibility.",
"Precision scheduling locks in critical delivery windows reliably.",
"Priority dispatch queue fast-tracks urgent, life-critical shipments.",
],
},
{
id: "b2b",
tab: "Enterprise & B2B",
eyebrow: "Enterprise & B2B",
title: "Enterprise & B2B",
image: "/images/tab-pic-3-solution.jpeg",
alt: "Enterprise and B2B logistics",
desc:
"Enterprise and B2B logistics require coordination and reliability to manage high-value shipments at scale — with appointment scheduling, white-glove standards, and strict SLA commitments.",
chips: ["SLA Guaranteed", "White-Glove Ready"],
challenges: [
"Appointment scheduling requires precise timing across many locations.",
"White-glove delivery standards demand premium handling and accuracy.",
"Multi-location routing complexity grows with large-scale operations.",
"Strict SLA commitments pressure teams to stay timely and error-free.",
],
solutions: [
"Intelligent appointment engine streamlines and automates delivery slots.",
"White-glove workflow module enforces premium handling end to end.",
"Enterprise route planner coordinates efficient multi-location delivery.",
"SLA monitoring dashboard tracks commitments and flags risk in real time.",
],
},
];
export default function SolutionCard1() {
const [active, setActive] = useState(0);
const [tab, setTab] = useState<Tab>("challenges");
const ind = INDUSTRIES[active];
const selectIndustry = (i: number) => {
setActive(i);
setTab("challenges"); // reset to Challenges on industry switch
};
return (
<>
<style dangerouslySetInnerHTML={{ __html: `
/* ============================================================
Solutions — Industry section (FMCG / Pharma / Enterprise & B2B)
Brand red #dc2626 / #ef4444 · bg #0d0d0d · Syne + DM Sans
============================================================ */
/* The theme forces Manrope on every element via a high-specificity
universal :not() !important rule; re-assert Syne / DM Sans from the
ID selector (which outranks it) directly on each text node. */
#ind-solutions .ind__eyebrow,
#ind-solutions .ind__title,
#ind-solutions .ind__tab,
#ind-solutions .ind__toggle-btn {
font-family: var(--font-syne), 'Syne', sans-serif !important;
}
#ind-solutions .ind__desc,
#ind-solutions .ind__chip,
#ind-solutions .ind__list li {
font-family: var(--font-dm-sans), 'DM Sans', sans-serif !important;
}
/* kit-5 also forces heading color/size on the title (an <h3>). */
#ind-solutions .ind__title {
color: #fff !important;
font-size: clamp(34px, 5.5vw, 68px) !important;
font-weight: 800 !important;
line-height: 1.02 !important;
margin: 0 0 16px !important;
letter-spacing: -0.01em !important;
}
#ind-solutions .ind__list li { color: #c9c9c9 !important; }
.ind {
position: relative;
isolation: isolate;
overflow: hidden;
background: #0d0d0d;
border-radius: clamp(16px, 2vw, 26px);
max-width: 1400px;
margin: clamp(24px, 4vw, 56px) auto;
padding: clamp(34px, 5vw, 76px) clamp(18px, 4vw, 64px);
}
.ind__map {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
opacity: 0.55;
z-index: 0;
pointer-events: none;
}
.ind__inner {
position: relative;
z-index: 1;
max-width: 1240px;
margin: 0 auto;
}
/* ---- Top tab bar ---- */
.ind__tabs {
display: flex;
gap: clamp(10px, 3vw, 36px);
border-bottom: 1px solid rgba(255,255,255,0.1);
margin-bottom: clamp(28px, 4vw, 52px);
flex-wrap: wrap;
}
.ind__tab {
appearance: none;
background: none;
border: none;
cursor: pointer;
padding: 10px 2px 16px;
font-weight: 700;
font-size: clamp(14px, 1.4vw, 18px);
color: #888;
position: relative;
letter-spacing: 0.01em;
transition: color 0.3s ease;
}
.ind__tab::after {
content: '';
position: absolute;
left: 0; right: 0; bottom: -1px;
height: 2px;
background: #dc2626;
transform: scaleX(0);
transform-origin: left;
transition: transform 0.35s cubic-bezier(.25,1,.5,1);
}
.ind__tab:hover { color: #ccc; }
.ind__tab.active { color: #fff; }
.ind__tab.active::after { transform: scaleX(1); }
/* ---- Grid ---- */
.ind__grid {
display: grid;
grid-template-columns: 0.9fr 1.1fr;
gap: clamp(28px, 4vw, 64px);
align-items: center;
}
/* ---- Left media ---- */
.ind__media {
position: relative;
display: flex;
align-items: center;
justify-content: center;
min-height: 300px;
}
.ind__glow {
position: absolute;
left: 50%; bottom: 4%;
width: 74%; height: 70px;
transform: translateX(-50%);
background: radial-gradient(50% 50% at 50% 50%, rgba(220,38,38,0.5), transparent 72%);
filter: blur(32px);
z-index: 0;
animation: indGlow 4s ease-in-out infinite;
}
.ind__img-wrap {
position: relative;
z-index: 1;
width: 100%;
max-width: 460px;
animation: indFloat 6s ease-in-out infinite;
will-change: transform;
}
.ind__img-wrap::before,
.ind__img-wrap::after {
content: '';
position: absolute;
width: 44px; height: 44px;
border: 2px solid #dc2626;
z-index: 3;
}
.ind__img-wrap::before {
top: -10px; left: -10px;
border-right: none; border-bottom: none;
border-radius: 10px 0 0 0;
}
.ind__img-wrap::after {
bottom: -10px; right: -10px;
border-left: none; border-top: none;
border-radius: 0 0 10px 0;
}
.ind__img {
display: block;
width: 100%;
height: auto;
border-radius: 12px;
object-fit: cover;
box-shadow: 0 30px 60px -25px rgba(0,0,0,0.7);
animation: indImgFade 0.55s ease both;
}
.ind__chip {
position: absolute;
z-index: 4;
display: inline-flex;
align-items: center;
gap: 8px;
padding: 9px 16px;
border-radius: 999px;
background: rgba(16,16,16,0.82);
border: 1px solid rgba(239,68,68,0.4);
backdrop-filter: blur(8px);
color: #fff;
font-weight: 500;
font-size: 13px;
white-space: nowrap;
box-shadow: 0 12px 28px -12px rgba(0,0,0,0.7);
animation: indFloat 6s ease-in-out infinite;
}
.ind__chip .dot {
width: 7px; height: 7px;
border-radius: 50%;
background: #ef4444;
box-shadow: 0 0 8px #ef4444;
animation: indDot 1.6s ease-in-out infinite;
}
.ind__chip--1 { top: 7%; left: -5%; animation-delay: 0.4s; }
.ind__chip--2 { bottom: 12%; right: -5%; animation-delay: 1.3s; }
/* ---- Right text ---- */
.ind__text { min-width: 0; }
.ind__eyebrow {
display: inline-flex;
align-items: center;
gap: 12px;
color: #ef4444;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.16em;
font-size: clamp(11px, 1vw, 13px);
margin-bottom: 14px;
}
.ind__eyebrow::before {
content: '';
width: 30px; height: 2px;
background: #ef4444;
}
.ind__desc {
color: #b4b4b4;
font-size: clamp(15px, 1.2vw, 18px);
line-height: 1.7;
font-weight: 400;
margin: 0 0 24px;
max-width: 580px;
}
/* ---- Challenges / Solutions toggle ---- */
.ind__toggle {
display: inline-flex;
gap: 4px;
padding: 5px;
border-radius: 999px;
background: rgba(255,255,255,0.05);
border: 1px solid rgba(255,255,255,0.09);
margin-bottom: 24px;
}
.ind__toggle-btn {
appearance: none;
border: none;
cursor: pointer;
padding: 9px 28px;
border-radius: 999px;
font-weight: 700;
font-size: 14px;
color: #9a9a9a;
background: transparent;
transition: color 0.3s ease, background-color 0.3s ease, box-shadow 0.3s ease;
}
.ind__toggle-btn:hover { color: #ddd; }
.ind__toggle-btn.active {
background: #dc2626;
color: #fff;
box-shadow: 0 8px 20px -8px rgba(220,38,38,0.6);
}
/* ---- Sliding panels ---- */
.ind__slider { overflow: hidden; }
.ind__track {
display: flex;
width: 200%;
transition: transform 0.4s cubic-bezier(.4,0,.2,1);
}
.ind__panel { width: 50%; flex: 0 0 50%; }
.ind__list { list-style: none; margin: 0; padding: 0; }
.ind__list li {
position: relative;
padding-left: 30px;
margin-bottom: 16px;
font-size: clamp(14px, 1.1vw, 16px);
line-height: 1.6;
opacity: 0;
transform: translateX(-16px);
}
.ind__list li:last-child { margin-bottom: 0; }
.ind__list li::before {
content: '';
position: absolute;
left: 4px; top: 8px;
width: 8px; height: 8px;
border-radius: 50%;
background: #dc2626;
box-shadow: 0 0 8px rgba(220,38,38,0.7);
}
.ind__panel.is-active .ind__list li {
animation: indBullet 0.5s cubic-bezier(.25,1,.5,1) forwards;
}
.ind__panel.is-active .ind__list li:nth-child(1) { animation-delay: 0.05s; }
.ind__panel.is-active .ind__list li:nth-child(2) { animation-delay: 0.13s; }
.ind__panel.is-active .ind__list li:nth-child(3) { animation-delay: 0.21s; }
.ind__panel.is-active .ind__list li:nth-child(4) { animation-delay: 0.29s; }
.ind__panel.is-active .ind__list li:nth-child(5) { animation-delay: 0.37s; }
@keyframes indFloat { 0%,100% { transform: translateY(0); } 50% { transform: translateY(-14px); } }
@keyframes indGlow { 0%,100% { opacity: 0.6; } 50% { opacity: 1; } }
@keyframes indDot { 0%,100% { opacity: 1; } 50% { opacity: 0.35; } }
@keyframes indBullet { to { opacity: 1; transform: translateX(0); } }
@keyframes indImgFade { from { opacity: 0; transform: scale(0.97); } to { opacity: 1; transform: scale(1); } }
/* ---- Responsive ---- */
@media (max-width: 900px) {
.ind__grid { grid-template-columns: 1fr; gap: clamp(40px, 8vw, 56px); }
.ind__media { order: -1; }
.ind__img-wrap { max-width: 380px; }
}
@media (max-width: 600px) {
.ind__chip { font-size: 12px; padding: 7px 12px; }
.ind__chip--1 { left: 0; }
.ind__chip--2 { right: 0; }
.ind__toggle-btn { padding: 9px 20px; }
}
@media (prefers-reduced-motion: reduce) {
.ind__img-wrap, .ind__glow, .ind__chip, .ind__chip .dot { animation: none !important; }
.ind__track { transition: none !important; }
.ind__panel.is-active .ind__list li { animation: none !important; opacity: 1; transform: none; }
}
`}} />
<section id="ind-solutions" className="ind" aria-label="Industry solutions">
<IndustryWorldMap />
<div className="ind__inner">
{/* Top tab bar */}
<div className="ind__tabs" role="tablist" aria-label="Industries">
{INDUSTRIES.map((it, i) => (
<button
key={it.id}
type="button"
role="tab"
aria-selected={i === active}
className={`ind__tab ${i === active ? "active" : ""}`}
onClick={() => selectIndustry(i)}
>
{it.tab}
</button>
))}
</div>
<div className="ind__grid">
{/* Left media */}
<div className="ind__media">
<div className="ind__glow" />
<div className="ind__img-wrap">
{/* eslint-disable-next-line @next/next/no-img-element */}
<img key={active} className="ind__img" src={ind.image} alt={ind.alt} decoding="async" />
</div>
<div className="ind__chip ind__chip--1">
<span className="dot" />
{ind.chips[0]}
</div>
<div className="ind__chip ind__chip--2">
<span className="dot" />
{ind.chips[1]}
</div>
</div>
{/* Right text */}
<div className="ind__text">
<span className="ind__eyebrow">{ind.eyebrow}</span>
<h3 className="ind__title">{ind.title}</h3>
<p className="ind__desc">{ind.desc}</p>
<div className="ind__toggle" role="tablist" aria-label="Challenges or Solutions">
<button
type="button"
role="tab"
aria-selected={tab === "challenges"}
className={`ind__toggle-btn ${tab === "challenges" ? "active" : ""}`}
onClick={() => setTab("challenges")}
>
Challenges
</button>
<button
type="button"
role="tab"
aria-selected={tab === "solutions"}
className={`ind__toggle-btn ${tab === "solutions" ? "active" : ""}`}
onClick={() => setTab("solutions")}
>
Solutions
</button>
</div>
<div className="ind__slider">
<div
className="ind__track"
key={active}
style={{ transform: tab === "challenges" ? "translateX(0)" : "translateX(-50%)" }}
>
<div className={`ind__panel ${tab === "challenges" ? "is-active" : ""}`}>
<ul className="ind__list">
{ind.challenges.map((c, idx) => (
<li key={idx}>{c}</li>
))}
</ul>
</div>
<div className={`ind__panel ${tab === "solutions" ? "is-active" : ""}`}>
<ul className="ind__list">
{ind.solutions.map((s, idx) => (
<li key={idx}>{s}</li>
))}
</ul>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
</>
);
}

View File

@@ -2,6 +2,7 @@
import React, { useState } from "react";
import { motion, AnimatePresence } from "framer-motion";
import LogisticsBrainSection from "../logisticsbrain/LogisticsBrainSection";
export default function Workflow2() {
const [activeSlide, setActiveSlide] = useState(0);
@@ -22,83 +23,67 @@ export default function Workflow2() {
];
return (
<section className="dm-workflow" aria-label="Workflow 2 — Competitive Edge & Innovation">
<div className="dm-workflow__container">
<section className="dm-wf2" aria-label="Workflow 2 — How Our Logistics Brain Works & Innovation">
{/* ── Top sub-section: Competitive Edge banner ── */}
<div className="dm-workflow-banner">
{/* eslint-disable-next-line @next/next/no-img-element */}
<img
className="dm-workflow-banner__img"
src="/images/miletruth-2.png"
alt="Our Competitive Edge"
width={1733}
height={773}
loading="lazy"
decoding="async"
/>
<div className="dm-workflow-banner__caption">
<span className="dm-workflow-banner__title-text">Our Competitive Edge</span>
</div>
{/* ── Top sub-section: the complete "How Our Logistics Brain Works" experience ── */}
<LogisticsBrainSection connected />
{/* ── Bottom sub-section: Innovation content, flush + colour-matched to the
logistics-brain card above so the whole workflow reads as one container ── */}
<div className="dm-wf2-card">
{/* Left Column: Overlapping Chevron Graphic */}
<div className="dm-workflow-left">
<svg viewBox="0 0 320 280" fill="none" xmlns="http://www.w3.org/2000/svg" className="dm-workflow-svg">
<path
d="M 30,20 C 22,20 16,26 16,34 L 78,85 C 81,88 81,92 78,95 L 16,146 C 16,154 22,160 30,160 L 130,160 C 138,160 145,154 148,146 L 204,95 C 207,92 207,88 204,85 L 148,34 C 145,26 138,20 130,20 Z"
stroke="white" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round" opacity="0.25"
/>
<path
d="M 110,100 C 102,100 96,106 96,114 L 158,165 C 161,168 161,172 158,175 L 96,226 C 96,234 102,240 110,240 L 210,240 C 218,240 225,234 228,226 L 284,175 C 287,172 287,168 284,165 L 228,114 C 225,106 218,100 210,100 Z"
stroke="white" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round" opacity="0.85"
/>
</svg>
</div>
{/* ── Bottom sub-section: Innovation content ── */}
<div className="dm-workflow-card">
{/* Left Column: Overlapping Chevron Graphic */}
<div className="dm-workflow-left">
<svg viewBox="0 0 320 280" fill="none" xmlns="http://www.w3.org/2000/svg" className="dm-workflow-svg">
<path
d="M 30,20 C 22,20 16,26 16,34 L 78,85 C 81,88 81,92 78,95 L 16,146 C 16,154 22,160 30,160 L 130,160 C 138,160 145,154 148,146 L 204,95 C 207,92 207,88 204,85 L 148,34 C 145,26 138,20 130,20 Z"
stroke="white" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round" opacity="0.25"
/>
<path
d="M 110,100 C 102,100 96,106 96,114 L 158,165 C 161,168 161,172 158,175 L 96,226 C 96,234 102,240 110,240 L 210,240 C 218,240 225,234 228,226 L 284,175 C 287,172 287,168 284,165 L 228,114 C 225,106 218,100 210,100 Z"
stroke="white" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round" opacity="0.85"
/>
</svg>
{/* Right Column: Quotes & Text Content */}
<div className="dm-workflow-right">
<svg width="32" height="24" viewBox="0 0 32 24" fill="none" xmlns="http://www.w3.org/2000/svg" className="dm-workflow-quote">
<rect x="2" y="2" width="9" height="20" rx="1.5" transform="skewX(-12)" fill="#C01227" />
<rect x="16" y="2" width="9" height="20" rx="1.5" transform="skewX(-12)" fill="#C01227" />
</svg>
<h3 className="dm-workflow-title">{slides[activeSlide].title}</h3>
<div className="dm-workflow-text-container">
<AnimatePresence mode="wait">
<motion.p
key={activeSlide}
initial={{ opacity: 0, y: 12 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: -12 }}
transition={{ duration: 0.28, ease: "easeInOut" }}
className="dm-workflow-text"
>
{slides[activeSlide].text}
</motion.p>
</AnimatePresence>
</div>
{/* Right Column: Quotes & Text Content */}
<div className="dm-workflow-right">
<svg width="32" height="24" viewBox="0 0 32 24" fill="none" xmlns="http://www.w3.org/2000/svg" className="dm-workflow-quote">
<rect x="2" y="2" width="9" height="20" rx="1.5" transform="skewX(-12)" fill="#C01227" />
<rect x="16" y="2" width="9" height="20" rx="1.5" transform="skewX(-12)" fill="#C01227" />
</svg>
<h3 className="dm-workflow-title">{slides[activeSlide].title}</h3>
<div className="dm-workflow-text-container">
<AnimatePresence mode="wait">
<motion.p
key={activeSlide}
initial={{ opacity: 0, y: 12 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: -12 }}
transition={{ duration: 0.28, ease: "easeInOut" }}
className="dm-workflow-text"
>
{slides[activeSlide].text}
</motion.p>
</AnimatePresence>
</div>
<div className="dm-workflow-nav">
<span className="dm-workflow-counter">0{activeSlide + 1}/03</span>
<div className="dm-workflow-bars">
{slides.map((_, index) => (
<button
key={index}
type="button"
aria-label={`Go to slide ${index + 1}`}
className={`dm-workflow-bar ${index === activeSlide ? "is-active" : ""}`}
onClick={() => setActiveSlide(index)}
/>
))}
</div>
<div className="dm-workflow-nav">
<span className="dm-workflow-counter">0{activeSlide + 1}/03</span>
<div className="dm-workflow-bars">
{slides.map((_, index) => (
<button
key={index}
type="button"
aria-label={`Go to slide ${index + 1}`}
className={`dm-workflow-bar ${index === activeSlide ? "is-active" : ""}`}
onClick={() => setActiveSlide(index)}
/>
))}
</div>
</div>
</div>
</div>
<style dangerouslySetInnerHTML={{ __html: styles }} />
@@ -108,73 +93,37 @@ export default function Workflow2() {
const styles = `
/* ============================================================
Workflow = ONE container: image-title banner (top) flush with
the dark content card (bottom). Single overflow:hidden wrapper
rounds the whole stack — no gap, no separate backgrounds.
Workflow 2 = ONE container:
├─ How Our Logistics Brain Works (full LogisticsBrainSection)
└─ Innovation (content card, flush + colour-matched)
The Innovation card is pulled up to butt against the logistics-brain
card's flat bottom and shares its dark red/black surface, so the two
read as a single continuous container with no gap / no break — the
same connected storytelling structure used in Workflow 1
(Impact of Optimisation → Performance).
============================================================ */
.dm-workflow {
max-width: 100%;
margin: 24px auto;
padding: 0 40px;
box-sizing: border-box;
.dm-wf2 {
position: relative;
margin: 0 auto 24px;
}
.dm-workflow__container {
/* Innovation card — aligned to the logistics-brain card (16px side insets),
red/black-matched, flat top, rounded bottom, pulled up to close the seam. */
.dm-wf2-card {
position: relative;
border-radius: 40px;
overflow: hidden;
background: #181818;
border: 1px solid rgba(255, 255, 255, 0.06);
box-shadow: 0 14px 50px -16px rgba(0, 0, 0, 0.55);
}
/* ── Banner (top) ── */
.dm-workflow-banner {
position: relative;
display: block;
width: 100%;
font-size: 0;
line-height: 0;
}
.dm-workflow-banner__img {
display: block;
width: 100%;
height: auto;
max-height: 380px;
object-fit: cover;
object-position: center;
}
.dm-workflow-banner__caption {
position: absolute;
left: 40px;
bottom: 32px;
background: rgba(255, 255, 255, 0.92);
padding: 16px 26px;
border-radius: 12px;
box-shadow: 0 10px 28px -10px rgba(0, 0, 0, 0.45);
line-height: normal;
}
.dm-workflow-banner__title-text {
display: block;
color: #C01227 !important;
font-family: var(--font-space-grotesk), var(--font-manrope), system-ui, sans-serif !important;
font-size: clamp(20px, 2.4vw, 34px) !important;
font-weight: 700 !important;
line-height: 1.1 !important;
letter-spacing: -0.01em;
text-transform: none !important;
}
/* ── Content card (bottom), flush under the banner ── */
.dm-workflow-card {
position: relative;
background: #181818;
border-top: 1px solid rgba(255, 255, 255, 0.06);
z-index: 2;
margin: 0 16px 0;
background: radial-gradient(120% 100% at 50% 0%, #12090c 0%, #0a070a 55%, #060507 100%);
border: 1px solid rgba(192, 18, 39, 0.16);
border-top: none;
border-radius: 0 0 28px 28px;
box-shadow: 0 10px 40px -10px rgba(0, 0, 0, 0.5);
padding: 48px 60px;
display: flex;
align-items: center;
justify-content: space-between;
gap: 40px;
overflow: hidden;
box-sizing: border-box;
}
@@ -251,24 +200,21 @@ const styles = `
.dm-workflow-bar:hover { background: rgba(255, 255, 255, 0.35); }
.dm-workflow-bar.is-active:hover { background: #C01227; }
/* ── Responsive ── */
/* ── Responsive — keep insets/radius aligned to the logistics-brain card ── */
@media (max-width: 1024px) {
.dm-workflow__container { border-radius: 32px; }
.dm-workflow-banner__img { max-height: 300px; }
.dm-workflow-banner__caption { left: 28px; bottom: 24px; padding: 13px 20px; }
.dm-workflow-card { padding: 44px 44px; gap: 44px; }
.dm-wf2-card {
padding: 44px 44px;
gap: 44px;
}
.dm-workflow-title { font-size: 32px; }
}
@media (max-width: 768px) {
.dm-workflow { padding: 0 16px; }
.dm-workflow__container { border-radius: 24px; }
.dm-workflow-banner__img { max-height: 220px; }
.dm-workflow-banner__caption { left: 16px; bottom: 16px; padding: 11px 16px; }
.dm-workflow-card {
flex-direction: column;
@media (max-width: 767px) {
.dm-wf2-card {
margin: 0 10px 0;
border-radius: 0 0 20px 20px;
padding: 36px 28px;
gap: 36px;
flex-direction: column;
}
.dm-workflow-left { max-width: 280px; }
.dm-workflow-right { width: 100%; }

View File

@@ -2,6 +2,7 @@
import React, { useState } from "react";
import { motion, AnimatePresence } from "framer-motion";
import StrategySection from "../strategy/StrategySection";
export default function Workflow3() {
const [activeSlide, setActiveSlide] = useState(0);
@@ -22,83 +23,69 @@ export default function Workflow3() {
];
return (
<section className="dm-workflow" aria-label="Workflow 3 — Happier Riders & Strategy">
<div className="dm-workflow__container">
<section className="dm-wf3" aria-label="Workflow 3 — Happier Riders. Higher Fulfillment. & Strategy">
{/* ── Top sub-section: Happier Riders banner ── */}
<div className="dm-workflow-banner">
{/* eslint-disable-next-line @next/next/no-img-element */}
<img
className="dm-workflow-banner__img"
src="/images/miletruth-3.png"
alt="Happier Riders. Higher Fulfillment"
width={1733}
height={773}
loading="lazy"
decoding="async"
/>
<div className="dm-workflow-banner__caption">
<span className="dm-workflow-banner__title-text">Happier Riders. Higher Fulfillment</span>
</div>
{/* ── Top sub-section: the full "Happier Riders. Higher Fulfillment."
3D scroll-storytelling experience ── */}
<StrategySection connected />
{/* ── Bottom sub-section: Strategy content, flush + pulled up to butt against
the 3D card's flat bottom so the whole workflow reads as one container —
the same connected structure used in Workflow 1 & 2 ── */}
<div className="dm-wf3-card">
{/* Left Column: Overlapping Chevron Graphic */}
<div className="dm-workflow-left">
<svg viewBox="0 0 320 280" fill="none" xmlns="http://www.w3.org/2000/svg" className="dm-workflow-svg">
<path
d="M 30,20 C 22,20 16,26 16,34 L 78,85 C 81,88 81,92 78,95 L 16,146 C 16,154 22,160 30,160 L 130,160 C 138,160 145,154 148,146 L 204,95 C 207,92 207,88 204,85 L 148,34 C 145,26 138,20 130,20 Z"
stroke="white" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round" opacity="0.25"
/>
<path
d="M 110,100 C 102,100 96,106 96,114 L 158,165 C 161,168 161,172 158,175 L 96,226 C 96,234 102,240 110,240 L 210,240 C 218,240 225,234 228,226 L 284,175 C 287,172 287,168 284,165 L 228,114 C 225,106 218,100 210,100 Z"
stroke="white" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round" opacity="0.85"
/>
</svg>
</div>
{/* ── Bottom sub-section: Strategy content ── */}
<div className="dm-workflow-card">
{/* Left Column: Overlapping Chevron Graphic */}
<div className="dm-workflow-left">
<svg viewBox="0 0 320 280" fill="none" xmlns="http://www.w3.org/2000/svg" className="dm-workflow-svg">
<path
d="M 30,20 C 22,20 16,26 16,34 L 78,85 C 81,88 81,92 78,95 L 16,146 C 16,154 22,160 30,160 L 130,160 C 138,160 145,154 148,146 L 204,95 C 207,92 207,88 204,85 L 148,34 C 145,26 138,20 130,20 Z"
stroke="white" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round" opacity="0.25"
/>
<path
d="M 110,100 C 102,100 96,106 96,114 L 158,165 C 161,168 161,172 158,175 L 96,226 C 96,234 102,240 110,240 L 210,240 C 218,240 225,234 228,226 L 284,175 C 287,172 287,168 284,165 L 228,114 C 225,106 218,100 210,100 Z"
stroke="white" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round" opacity="0.85"
/>
</svg>
{/* Right Column: Quotes & Text Content */}
<div className="dm-workflow-right">
<svg width="32" height="24" viewBox="0 0 32 24" fill="none" xmlns="http://www.w3.org/2000/svg" className="dm-workflow-quote">
<rect x="2" y="2" width="9" height="20" rx="1.5" transform="skewX(-12)" fill="#C01227" />
<rect x="16" y="2" width="9" height="20" rx="1.5" transform="skewX(-12)" fill="#C01227" />
</svg>
<h3 className="dm-workflow-title">{slides[activeSlide].title}</h3>
<div className="dm-workflow-text-container">
<AnimatePresence mode="wait">
<motion.p
key={activeSlide}
initial={{ opacity: 0, y: 12 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: -12 }}
transition={{ duration: 0.28, ease: "easeInOut" }}
className="dm-workflow-text"
>
{slides[activeSlide].text}
</motion.p>
</AnimatePresence>
</div>
{/* Right Column: Quotes & Text Content */}
<div className="dm-workflow-right">
<svg width="32" height="24" viewBox="0 0 32 24" fill="none" xmlns="http://www.w3.org/2000/svg" className="dm-workflow-quote">
<rect x="2" y="2" width="9" height="20" rx="1.5" transform="skewX(-12)" fill="#C01227" />
<rect x="16" y="2" width="9" height="20" rx="1.5" transform="skewX(-12)" fill="#C01227" />
</svg>
<h3 className="dm-workflow-title">{slides[activeSlide].title}</h3>
<div className="dm-workflow-text-container">
<AnimatePresence mode="wait">
<motion.p
key={activeSlide}
initial={{ opacity: 0, y: 12 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: -12 }}
transition={{ duration: 0.28, ease: "easeInOut" }}
className="dm-workflow-text"
>
{slides[activeSlide].text}
</motion.p>
</AnimatePresence>
</div>
<div className="dm-workflow-nav">
<span className="dm-workflow-counter">0{activeSlide + 1}/03</span>
<div className="dm-workflow-bars">
{slides.map((_, index) => (
<button
key={index}
type="button"
aria-label={`Go to slide ${index + 1}`}
className={`dm-workflow-bar ${index === activeSlide ? "is-active" : ""}`}
onClick={() => setActiveSlide(index)}
/>
))}
</div>
<div className="dm-workflow-nav">
<span className="dm-workflow-counter">0{activeSlide + 1}/03</span>
<div className="dm-workflow-bars">
{slides.map((_, index) => (
<button
key={index}
type="button"
aria-label={`Go to slide ${index + 1}`}
className={`dm-workflow-bar ${index === activeSlide ? "is-active" : ""}`}
onClick={() => setActiveSlide(index)}
/>
))}
</div>
</div>
</div>
</div>
<style dangerouslySetInnerHTML={{ __html: styles }} />
@@ -108,73 +95,33 @@ export default function Workflow3() {
const styles = `
/* ============================================================
Workflow = ONE container: image-title banner (top) flush with
the dark content card (bottom). Single overflow:hidden wrapper
rounds the whole stack — no gap, no separate backgrounds.
Workflow 3 = ONE container:
├─ Happier Riders. Higher Fulfillment. (full StrategySection — 3D)
└─ Strategy (content card, flush, pulled up)
The Strategy card aligns to the 3D card's 16px side insets, butts against
its flat bottom and rounds the bottom corners, so the two read as a single
continuous container — same technique as Workflow 1 & 2.
============================================================ */
.dm-workflow {
max-width: 100%;
margin: 24px auto;
padding: 0 40px;
box-sizing: border-box;
.dm-wf3 {
position: relative;
margin: 0 auto 24px;
}
.dm-workflow__container {
.dm-wf3-card {
position: relative;
border-radius: 40px;
overflow: hidden;
z-index: 2;
margin: 0 16px 0;
background: #181818;
border: 1px solid rgba(255, 255, 255, 0.06);
box-shadow: 0 14px 50px -16px rgba(0, 0, 0, 0.55);
}
/* ── Banner (top) ── */
.dm-workflow-banner {
position: relative;
display: block;
width: 100%;
font-size: 0;
line-height: 0;
}
.dm-workflow-banner__img {
display: block;
width: 100%;
height: auto;
max-height: 380px;
object-fit: cover;
object-position: center;
}
.dm-workflow-banner__caption {
position: absolute;
left: 40px;
bottom: 32px;
background: rgba(255, 255, 255, 0.92);
padding: 16px 26px;
border-radius: 12px;
box-shadow: 0 10px 28px -10px rgba(0, 0, 0, 0.45);
line-height: normal;
}
.dm-workflow-banner__title-text {
display: block;
color: #C01227 !important;
font-family: var(--font-space-grotesk), var(--font-manrope), system-ui, sans-serif !important;
font-size: clamp(20px, 2.4vw, 34px) !important;
font-weight: 700 !important;
line-height: 1.1 !important;
letter-spacing: -0.01em;
text-transform: none !important;
}
/* ── Content card (bottom), flush under the banner ── */
.dm-workflow-card {
position: relative;
background: #181818;
border-top: 1px solid rgba(255, 255, 255, 0.06);
border-top: none;
border-radius: 0 0 28px 28px;
box-shadow: 0 10px 40px -10px rgba(0, 0, 0, 0.5);
padding: 48px 60px;
display: flex;
align-items: center;
justify-content: space-between;
gap: 40px;
overflow: hidden;
box-sizing: border-box;
}
@@ -251,24 +198,18 @@ const styles = `
.dm-workflow-bar:hover { background: rgba(255, 255, 255, 0.35); }
.dm-workflow-bar.is-active:hover { background: #C01227; }
/* ── Responsive ── */
/* ── Responsive — keep insets/radius aligned to the 3D card ── */
@media (max-width: 1024px) {
.dm-workflow__container { border-radius: 32px; }
.dm-workflow-banner__img { max-height: 300px; }
.dm-workflow-banner__caption { left: 28px; bottom: 24px; padding: 13px 20px; }
.dm-workflow-card { padding: 44px 44px; gap: 44px; }
.dm-wf3-card { padding: 44px 44px; gap: 44px; }
.dm-workflow-title { font-size: 32px; }
}
@media (max-width: 768px) {
.dm-workflow { padding: 0 16px; }
.dm-workflow__container { border-radius: 24px; }
.dm-workflow-banner__img { max-height: 220px; }
.dm-workflow-banner__caption { left: 16px; bottom: 16px; padding: 11px 16px; }
.dm-workflow-card {
flex-direction: column;
@media (max-width: 767px) {
.dm-wf3-card {
margin: 0 10px 0;
border-radius: 0 0 20px 20px;
padding: 36px 28px;
gap: 36px;
flex-direction: column;
}
.dm-workflow-left { max-width: 280px; }
.dm-workflow-right { width: 100%; }