fix padding gap
This commit is contained in:
121
src/app/cookie-policy/page.tsx
Normal file
121
src/app/cookie-policy/page.tsx
Normal file
@@ -0,0 +1,121 @@
|
||||
import React from "react";
|
||||
import type { Metadata } from "next";
|
||||
import LegalDocument, { ContactLink, type LegalSection } from "@/components/sections/LegalDocument";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Cookie Policy – Doormile",
|
||||
description:
|
||||
"How Doormile uses cookies and similar technologies when you visit our website, and how you can manage them.",
|
||||
};
|
||||
|
||||
const sections: LegalSection[] = [
|
||||
{
|
||||
heading: "What Are Cookies?",
|
||||
blocks: [
|
||||
{
|
||||
type: "p",
|
||||
text: "Cookies are small text files stored on your device that help websites remember information about your visit and improve the browsing experience.",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
heading: "Why We Use Cookies",
|
||||
blocks: [
|
||||
{ type: "p", text: "We use cookies to:" },
|
||||
{
|
||||
type: "ul",
|
||||
items: [
|
||||
"Enable essential website functionality",
|
||||
"Improve website performance",
|
||||
"Analyze visitor behavior and traffic patterns",
|
||||
"Remember user preferences",
|
||||
"Enhance overall user experience",
|
||||
"Support website security",
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
heading: "Types of Cookies We Use",
|
||||
blocks: [
|
||||
{ type: "h3", text: "Essential Cookies" },
|
||||
{
|
||||
type: "p",
|
||||
text: "These cookies are required for core website functionality and security features. The website may not function correctly without them.",
|
||||
},
|
||||
{ type: "h3", text: "Performance Cookies" },
|
||||
{
|
||||
type: "p",
|
||||
text: "These cookies collect information about how visitors interact with the website and help us improve performance and usability.",
|
||||
},
|
||||
{ type: "h3", text: "Analytics Cookies" },
|
||||
{
|
||||
type: "p",
|
||||
text: "Analytics cookies help us understand website traffic, visitor engagement, popular content, and user journeys.",
|
||||
},
|
||||
{ type: "h3", text: "Functional Cookies" },
|
||||
{
|
||||
type: "p",
|
||||
text: "These cookies remember user preferences such as language, region, and other customization settings.",
|
||||
},
|
||||
{ type: "h3", text: "Third-Party Cookies" },
|
||||
{
|
||||
type: "p",
|
||||
text: "Some third-party services integrated into our website, including analytics and performance monitoring tools, may place cookies on your device.",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
heading: "Managing Cookies",
|
||||
blocks: [
|
||||
{
|
||||
type: "p",
|
||||
text: "Most web browsers allow users to control, block, or delete cookies through browser settings. Please note that disabling cookies may impact certain website features and functionality.",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
heading: "Cookie Consent",
|
||||
blocks: [
|
||||
{
|
||||
type: "p",
|
||||
text: "Where required by applicable law, visitors may be presented with cookie consent options when accessing the website.",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
heading: "Policy Updates",
|
||||
blocks: [
|
||||
{
|
||||
type: "p",
|
||||
text: "We may revise this Cookie Policy periodically to reflect changes in technology, regulations, or business practices. Updated versions will be published on this page.",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
heading: "Contact Us",
|
||||
blocks: [
|
||||
{
|
||||
type: "p",
|
||||
text: <>If you have questions regarding this Cookie Policy or our use of cookies, please contact us through our <ContactLink />.</>,
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
export default function CookiePolicyPage() {
|
||||
return (
|
||||
<div className="content-wrapper content-wrapper-may-contain-elementor-code content-wrapper-sidebar-position-none">
|
||||
<div className="content">
|
||||
<div className="content-inner">
|
||||
<LegalDocument
|
||||
title="Cookie Policy"
|
||||
lastUpdated="June 2026"
|
||||
intro="This Cookie Policy explains how Doormile uses cookies and similar technologies when you visit our website."
|
||||
sections={sections}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -10,6 +10,76 @@ html {
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
GLOBAL SPACING SYSTEM
|
||||
A single shared vertical-rhythm scale so every section uses
|
||||
consistent top/bottom spacing instead of ad-hoc values.
|
||||
Fluid (clamp) so it scales down gracefully on small screens.
|
||||
--space-section → standard section (≈80px)
|
||||
--space-section-lg → large/feature section (≈100px)
|
||||
--space-hero-gap → gap from hero to the first section below
|
||||
Apply via .dm-section / .dm-section-lg, or reference the vars
|
||||
directly in component styles.
|
||||
============================================================ */
|
||||
:root {
|
||||
--space-section: clamp(40px, 5vw, 64px);
|
||||
--space-section-lg: clamp(52px, 6vw, 80px);
|
||||
--space-hero-gap: clamp(36px, 4.5vw, 64px);
|
||||
}
|
||||
|
||||
.dm-section {
|
||||
padding-top: var(--space-section) !important;
|
||||
padding-bottom: var(--space-section) !important;
|
||||
}
|
||||
|
||||
.dm-section-lg {
|
||||
padding-top: var(--space-section-lg) !important;
|
||||
padding-bottom: var(--space-section-lg) !important;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------
|
||||
Hero → first-section gap fixes
|
||||
The "Doormile Way" container (.elementor-element-88745f4) carries a
|
||||
150px top margin from the shared Elementor kit (intended as mid-page
|
||||
spacing on Home, where it sits deep in the stack). On the About page
|
||||
it is the FIRST section under the hero, so that 150px reads as an
|
||||
oversized empty gap. Scope the reduction to the About page only
|
||||
(.elementor-86) so Home's mid-page rhythm is untouched.
|
||||
------------------------------------------------------------ */
|
||||
.elementor-86 .elementor-element.elementor-element-88745f4 {
|
||||
margin-top: var(--space-hero-gap) !important;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------
|
||||
HOME PAGE — unified section rhythm
|
||||
The shared Elementor kit stamps several stacked sections with a
|
||||
150px top margin. On Home that makes "The Problem", the marquee,
|
||||
"Connected Logistics" and "The Doormile Way" float far below the
|
||||
section above them, while Stats and the EV card sit tight — an
|
||||
uneven, broken rhythm. Normalize EVERY post-hero section to one
|
||||
consistent gap so the page reads Hero ↓ Section ↓ Section evenly.
|
||||
|
||||
Scoped to `.elementor.elementor-61` — the Home page root uniquely
|
||||
carries BOTH classes, so this never leaks onto other pages that
|
||||
reuse these components (e.g. The Doormile Way on About-us, whose
|
||||
root is `.elementor.elementor-86`).
|
||||
|
||||
Hero (741f56c) and the Stats band (9b26234) directly beneath it are
|
||||
intentionally left tight and untouched.
|
||||
------------------------------------------------------------ */
|
||||
/* Sections, in render order: 30fd9d1 The Problem · b62c0b3 Marquee ·
|
||||
89a0ca1 Connected Logistics · 88745f4 The Doormile Way · bbc6760 EV ·
|
||||
3b4a7cc Industry Solutions. */
|
||||
.elementor.elementor-61 .elementor-element.elementor-element-30fd9d1,
|
||||
.elementor.elementor-61 .elementor-element.elementor-element-b62c0b3,
|
||||
.elementor.elementor-61 .elementor-element.elementor-element-89a0ca1,
|
||||
.elementor.elementor-61 .elementor-element.elementor-element-88745f4,
|
||||
.elementor.elementor-61 .elementor-element.elementor-element-bbc6760,
|
||||
.elementor.elementor-61 .elementor-element.elementor-element-3b4a7cc {
|
||||
margin-top: var(--space-section) !important;
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
|
||||
/* Lenis global smooth scroll (src/animations/SmoothScroll.tsx). These classes are
|
||||
only present on routes/devices where Lenis is active; on touch devices and with
|
||||
prefers-reduced-motion Lenis is off and native scroll-behavior:smooth (above) applies. */
|
||||
@@ -87,12 +157,15 @@ body {
|
||||
#masthead .elementor-element.elementor-element-0b7bf6f .header-menu-container .main-menu > li > a {
|
||||
padding-top: 15px !important;
|
||||
padding-bottom: 16px !important;
|
||||
padding-left: 14px !important;
|
||||
padding-right: 14px !important;
|
||||
font-size: 15px !important;
|
||||
line-height: 1.2 !important;
|
||||
white-space: nowrap !important;
|
||||
}
|
||||
|
||||
#masthead .header-menu-container .main-menu {
|
||||
gap: 18px !important;
|
||||
gap: 8px !important;
|
||||
}
|
||||
|
||||
#masthead .elementor-element.elementor-element-cabdb09 a.header-button {
|
||||
@@ -450,8 +523,8 @@ body {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 30px;
|
||||
width: 90%;
|
||||
margin: 30px auto;
|
||||
width: 100%;
|
||||
margin: 30px 0 0;
|
||||
}
|
||||
|
||||
@media (max-width: 1024px) {
|
||||
@@ -579,12 +652,17 @@ body {
|
||||
transform: translateY(10px);
|
||||
}
|
||||
|
||||
/* Default card title — single typography token shared by every card (FMCG,
|
||||
Pharmaceutical, Enterprise & B2B). FMCG is the reference: small, clean,
|
||||
bottom-left, consistent weight. Kept compact so longer labels read at the
|
||||
same size/weight as FMCG instead of looking heavier. */
|
||||
.industry-card-default-title {
|
||||
color: #ffffff !important;
|
||||
font-size: 28px !important;
|
||||
font-size: 22px !important;
|
||||
font-weight: 700 !important;
|
||||
line-height: 1.2 !important;
|
||||
margin: 0 !important;
|
||||
letter-spacing: -0.5px !important;
|
||||
letter-spacing: -0.3px !important;
|
||||
text-transform: none !important;
|
||||
font-family: var(--font-manrope), 'Manrope', system-ui, -apple-system, sans-serif !important;
|
||||
}
|
||||
@@ -730,9 +808,27 @@ body {
|
||||
letter-spacing: -0.5px !important;
|
||||
}
|
||||
|
||||
.elementor-element-3b4a7cc > .e-con-inner {
|
||||
/* Industry Solutions: match the Meet Crew (OurTeam) container EXACTLY. The
|
||||
e-con-boxed inner otherwise spans edge-to-edge because the vendor
|
||||
"display: var(--display)" resolves to the invalid `inline` fallback, so its
|
||||
max-width is ignored. The previous rule here only set padding (never
|
||||
max-width / margin / display), which is why the divider line stretched almost
|
||||
full-viewport and the heading hugged the left edge. Force flex and pin the
|
||||
inner to the shared 1480px inset so the label divider, heading and card grid
|
||||
all share the same left/right edges as the rest of the page. */
|
||||
.elementor.elementor-61 .elementor-element.elementor-element-3b4a7cc {
|
||||
display: flex;
|
||||
}
|
||||
.elementor.elementor-61 .elementor-element.elementor-element-3b4a7cc > .e-con-inner {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
max-width: 1480px;
|
||||
width: 100%;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
padding-left: clamp(20px, 4vw, 50px) !important;
|
||||
padding-right: clamp(20px, 4vw, 50px) !important;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/* Custom premium animations keyframes */
|
||||
|
||||
@@ -45,7 +45,7 @@ const inter = Inter({
|
||||
});
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Doormile — Last-Mile Logistics Intelligence",
|
||||
title: "Doormile — Delivering Trust. Beyond Boundaries",
|
||||
description: "Doormile powers last-mile logistics with MileTruth™ AI, providing connected miles, SLA protection, and carrier management.",
|
||||
icons: {
|
||||
icon: "/images/cropped-image-2.png",
|
||||
@@ -71,19 +71,13 @@ export default function RootLayout({
|
||||
rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.2/css/all.min.css"
|
||||
/>
|
||||
{/* Load WordPress & Elementor compiled styles from public folder */}
|
||||
<link rel="stylesheet" href="/css/vendor/vendor-elementor-generated-globals.css" />
|
||||
<link rel="stylesheet" href="/css/vendor/vendor-elementor-base.css" />
|
||||
<link rel="stylesheet" href="/css/vendor/vendor-elementor-custom.min.css" />
|
||||
<link rel="stylesheet" href="/css/vendor/vendor-theme-core.css" />
|
||||
<link rel="stylesheet" href="/css/vendor/vendor-global-overrides.css" />
|
||||
<link rel="stylesheet" href="/css/vendor/vendor-layout-main.css" />
|
||||
<link rel="stylesheet" href="/css/vendor/vendor-responsive-laptops.css" />
|
||||
<link rel="stylesheet" href="/css/vendor/vendor-elementor-hfe.css" />
|
||||
<link rel="stylesheet" href="/css/vendor/vendor-icons-fontello-load.css" />
|
||||
<link rel="stylesheet" href="/css/vendor/vendor-icons-fontello.css" />
|
||||
<link rel="stylesheet" href="/css/custom-frontend.min.css" />
|
||||
<link rel="stylesheet" href="/css/all-inlined-head-styles.css" />
|
||||
{/*
|
||||
Consolidated site styles. Generated by `npm run build:css`
|
||||
(scripts/build-css.sh): the legacy WordPress/Elementor vendor CSS is
|
||||
concatenated in cascade order and purged of unused selectors via
|
||||
purgecss.config.cjs. ~2.86 MB of vendor CSS -> ~560 KB, one request.
|
||||
*/}
|
||||
<link rel="stylesheet" href="/css/site.css" />
|
||||
</head>
|
||||
{/*
|
||||
Production DOM (index.php + header.php):
|
||||
|
||||
@@ -10,7 +10,7 @@ import EVSection from "@/components/sections/EVSection";
|
||||
import IndustrySolutions from "@/components/sections/IndustrySolutions";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Doormile — Last-Mile Logistics Intelligence",
|
||||
title: "Doormile — Delivering Trust. Beyond Boundaries",
|
||||
description:
|
||||
"Doormile helps logistics companies track every mile with MileTruth™ AI. Real-time SLA protection and connected miles visibility.",
|
||||
};
|
||||
|
||||
146
src/app/privacy-policy/page.tsx
Normal file
146
src/app/privacy-policy/page.tsx
Normal file
@@ -0,0 +1,146 @@
|
||||
import React from "react";
|
||||
import type { Metadata } from "next";
|
||||
import LegalDocument, { ContactLink, type LegalSection } from "@/components/sections/LegalDocument";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Privacy Policy – Doormile",
|
||||
description:
|
||||
"How Doormile collects, uses, stores, and protects your information when you visit our website, interact with our services, or communicate with us.",
|
||||
};
|
||||
|
||||
const sections: LegalSection[] = [
|
||||
{
|
||||
heading: "Information We Collect",
|
||||
blocks: [
|
||||
{ type: "p", text: "We may collect the following information:" },
|
||||
{
|
||||
type: "ul",
|
||||
items: [
|
||||
"Full name",
|
||||
"Email address",
|
||||
"Phone number",
|
||||
"Company name",
|
||||
"Job title",
|
||||
"Information submitted through contact forms",
|
||||
"Service inquiry details",
|
||||
"Website usage data and analytics",
|
||||
"Browser, device, and IP information",
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
heading: "How We Use Your Information",
|
||||
blocks: [
|
||||
{ type: "p", text: "We use your information to:" },
|
||||
{
|
||||
type: "ul",
|
||||
items: [
|
||||
"Respond to inquiries and support requests",
|
||||
"Provide information about our services",
|
||||
"Improve website performance and user experience",
|
||||
"Analyze usage trends and platform effectiveness",
|
||||
"Maintain security and prevent unauthorized access",
|
||||
"Communicate service updates and business information",
|
||||
"Comply with legal and regulatory requirements",
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
heading: "Information Sharing",
|
||||
blocks: [
|
||||
{
|
||||
type: "p",
|
||||
text: "Doormile does not sell, rent, or trade personal information. Information may be shared with trusted service providers that assist with website hosting, analytics, communications, and operational support, subject to appropriate confidentiality and security obligations.",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
heading: "Data Security",
|
||||
blocks: [
|
||||
{
|
||||
type: "p",
|
||||
text: "We implement industry-standard administrative, technical, and organizational safeguards designed to protect personal information from unauthorized access, disclosure, alteration, or destruction.",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
heading: "Data Retention",
|
||||
blocks: [
|
||||
{
|
||||
type: "p",
|
||||
text: "We retain information only for as long as necessary to fulfill the purposes described in this policy, comply with legal obligations, resolve disputes, and enforce agreements.",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
heading: "Cookies and Tracking Technologies",
|
||||
blocks: [
|
||||
{
|
||||
type: "p",
|
||||
text: "We use cookies and similar technologies to improve website functionality, measure performance, understand user behavior, and enhance user experience.",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
heading: "Your Rights",
|
||||
blocks: [
|
||||
{ type: "p", text: "Depending on applicable laws, you may have the right to:" },
|
||||
{
|
||||
type: "ul",
|
||||
items: [
|
||||
"Access your personal information",
|
||||
"Request correction of inaccurate data",
|
||||
"Request deletion of personal information",
|
||||
"Restrict or object to certain processing activities",
|
||||
"Withdraw consent where applicable",
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
heading: "Third-Party Links",
|
||||
blocks: [
|
||||
{
|
||||
type: "p",
|
||||
text: "Our website may contain links to third-party websites. We are not responsible for the privacy practices or content of external websites.",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
heading: "Policy Updates",
|
||||
blocks: [
|
||||
{
|
||||
type: "p",
|
||||
text: "We may update this Privacy Policy periodically. Any changes will be posted on this page with a revised effective date.",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
heading: "Contact Us",
|
||||
blocks: [
|
||||
{
|
||||
type: "p",
|
||||
text: <>For privacy-related questions or requests, please contact us through our <ContactLink />.</>,
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
export default function PrivacyPolicyPage() {
|
||||
return (
|
||||
<div className="content-wrapper content-wrapper-may-contain-elementor-code content-wrapper-sidebar-position-none">
|
||||
<div className="content">
|
||||
<div className="content-inner">
|
||||
<LegalDocument
|
||||
title="Privacy Policy"
|
||||
lastUpdated="June 2026"
|
||||
intro="At Doormile, we are committed to protecting your privacy and maintaining the security of the information you share with us. This Privacy Policy outlines how we collect, use, store, and protect your information when you visit our website, interact with our services, or communicate with us."
|
||||
sections={sections}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
140
src/app/terms-of-service/page.tsx
Normal file
140
src/app/terms-of-service/page.tsx
Normal file
@@ -0,0 +1,140 @@
|
||||
import React from "react";
|
||||
import type { Metadata } from "next";
|
||||
import LegalDocument, { ContactLink, type LegalSection } from "@/components/sections/LegalDocument";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Terms of Service – Doormile",
|
||||
description:
|
||||
"The Terms of Service governing your access to and use of the Doormile website and related services.",
|
||||
};
|
||||
|
||||
const sections: LegalSection[] = [
|
||||
{
|
||||
heading: "Acceptance of Terms",
|
||||
blocks: [
|
||||
{
|
||||
type: "p",
|
||||
text: "By accessing this website, you acknowledge that you have read, understood, and agreed to these Terms of Service and all applicable laws and regulations.",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
heading: "Permitted Use",
|
||||
blocks: [
|
||||
{
|
||||
type: "p",
|
||||
text: "You agree to use the website and services only for lawful purposes and in accordance with these terms.",
|
||||
},
|
||||
{ type: "p", text: "You agree not to:" },
|
||||
{
|
||||
type: "ul",
|
||||
items: [
|
||||
"Violate applicable laws or regulations",
|
||||
"Attempt unauthorized access to systems or networks",
|
||||
"Interfere with website functionality or security",
|
||||
"Distribute malicious software or harmful code",
|
||||
"Misrepresent your identity or organization",
|
||||
"Use website content without authorization",
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
heading: "Intellectual Property Rights",
|
||||
blocks: [
|
||||
{
|
||||
type: "p",
|
||||
text: "All content, technology, software, graphics, trademarks, logos, text, designs, and other materials available on this website are the property of Doormile or its licensors and are protected by applicable intellectual property laws.",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
heading: "User Submissions",
|
||||
blocks: [
|
||||
{
|
||||
type: "p",
|
||||
text: "Any information submitted through forms, inquiries, or communications must be accurate and lawful. Users are responsible for the content they submit.",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
heading: "Service Availability",
|
||||
blocks: [
|
||||
{
|
||||
type: "p",
|
||||
text: "While we strive to maintain uninterrupted access, we do not guarantee that the website or services will always be available, secure, or error-free.",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
heading: "Disclaimer of Warranties",
|
||||
blocks: [
|
||||
{
|
||||
type: "p",
|
||||
text: 'The website and services are provided on an "as is" and "as available" basis without warranties of any kind, whether express or implied.',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
heading: "Limitation of Liability",
|
||||
blocks: [
|
||||
{
|
||||
type: "p",
|
||||
text: "To the maximum extent permitted by law, Doormile shall not be liable for any indirect, incidental, special, consequential, or punitive damages arising from or related to the use of the website or services.",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
heading: "Indemnification",
|
||||
blocks: [
|
||||
{
|
||||
type: "p",
|
||||
text: "Users agree to indemnify and hold harmless Doormile, its employees, partners, and affiliates from claims arising from misuse of the website or violation of these terms.",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
heading: "Modifications",
|
||||
blocks: [
|
||||
{
|
||||
type: "p",
|
||||
text: "We reserve the right to update or modify these Terms of Service at any time. Continued use of the website following updates constitutes acceptance of the revised terms.",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
heading: "Governing Law",
|
||||
blocks: [
|
||||
{
|
||||
type: "p",
|
||||
text: "These Terms shall be governed by and interpreted in accordance with applicable laws and regulations in the jurisdictions where Doormile conducts business.",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
heading: "Contact Us",
|
||||
blocks: [
|
||||
{
|
||||
type: "p",
|
||||
text: <>Questions regarding these Terms of Service may be submitted through our <ContactLink />.</>,
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
export default function TermsOfServicePage() {
|
||||
return (
|
||||
<div className="content-wrapper content-wrapper-may-contain-elementor-code content-wrapper-sidebar-position-none">
|
||||
<div className="content">
|
||||
<div className="content-inner">
|
||||
<LegalDocument
|
||||
title="Terms of Service"
|
||||
lastUpdated="June 2026"
|
||||
intro="These Terms of Service govern your access to and use of the Doormile website and related services. By accessing or using our website, you agree to comply with these terms."
|
||||
sections={sections}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -5,7 +5,7 @@ import { useHeaderUI } from "./HeaderUIProvider";
|
||||
/**
|
||||
* Production: `<div class="body-overlay"></div>` is a direct child of body
|
||||
* (rendered by both index.php line 6 and header.php line 5 — production has two; we render one).
|
||||
* CSS (in vendor-theme-core.css and elementor-frontend-inline-css.css) styles it as fixed-position fullscreen overlay.
|
||||
* CSS (consolidated into /public/css/site.css) styles it as fixed-position fullscreen overlay.
|
||||
*/
|
||||
export default function BodyOverlay() {
|
||||
const { isMenuOpen, isSidebarOpen, closeAll } = useHeaderUI();
|
||||
|
||||
@@ -527,6 +527,16 @@ export default function Header() {
|
||||
opacity: 1 !important;
|
||||
}
|
||||
|
||||
#masthead .header-menu-container .main-menu > li.active > a {
|
||||
color: #ffffff !important;
|
||||
}
|
||||
|
||||
#masthead .header-menu-container .main-menu > li > a:focus,
|
||||
#masthead .header-menu-container .main-menu > li > a:focus-visible {
|
||||
outline: none !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
/* Responsive logo adjustment on mobile/tablet */
|
||||
@media (max-width: 1024px) {
|
||||
#masthead .elementor-element.elementor-element-846e53d .hfe-site-logo .hfe-site-logo-container img {
|
||||
|
||||
@@ -5,7 +5,7 @@ import dynamic from "next/dynamic";
|
||||
import { motion, useMotionValue, useTransform, type MotionValue } from "framer-motion";
|
||||
import gsap from "gsap";
|
||||
import { ScrollTrigger } from "gsap/ScrollTrigger";
|
||||
import { P, STRATEGIES, ENGINE_STEPS, CONSTRAINT_LIST, STRATEGY_SCORES } from "./theme";
|
||||
import { P, STRATEGIES, WINNER_INDEX, ENGINE_STEPS, CONSTRAINT_LIST, STRATEGY_SCORES } from "./theme";
|
||||
|
||||
const LogisticsBrainCanvas = dynamic(() => import("./LogisticsBrainCanvas"), { ssr: false });
|
||||
|
||||
@@ -53,12 +53,21 @@ function StepRail({ active }: { active: number }) {
|
||||
);
|
||||
}
|
||||
|
||||
/** One cross-fading workflow card pinned to the lower-left. */
|
||||
/**
|
||||
* One workflow card that travels through the story. The outer anchor pins it to
|
||||
* its stage position (Left / Center / Right / Center-Hero); the inner motion card
|
||||
* slides + scales into that anchor in lockstep with scroll, so as the camera moves
|
||||
* through the stages the card visibly moves with the narrative instead of sitting
|
||||
* fixed in one corner.
|
||||
*/
|
||||
function StoryCard({
|
||||
step,
|
||||
index,
|
||||
pos,
|
||||
opacity,
|
||||
y,
|
||||
x,
|
||||
scale,
|
||||
num,
|
||||
kicker,
|
||||
title,
|
||||
@@ -66,8 +75,11 @@ function StoryCard({
|
||||
}: {
|
||||
step: number;
|
||||
index: number;
|
||||
pos: "left" | "center" | "right" | "hero";
|
||||
opacity: MotionValue<number>;
|
||||
y: MotionValue<number>;
|
||||
x: MotionValue<number>;
|
||||
scale: MotionValue<number>;
|
||||
num: string;
|
||||
kicker: string;
|
||||
title: string;
|
||||
@@ -76,14 +88,16 @@ function StoryCard({
|
||||
// Don't mount this beat's card until its step is active.
|
||||
if (step !== index) return null;
|
||||
return (
|
||||
<motion.div className="dm-lb-card-story" style={{ opacity, y }}>
|
||||
<div className="dm-lb-card-story__head">
|
||||
<span className="dm-lb-pillar__num">{num}</span>
|
||||
<span className="dm-lb-pillar__kicker">{kicker}</span>
|
||||
</div>
|
||||
<h3 className="dm-lb-pillar__title">{title}</h3>
|
||||
{children}
|
||||
</motion.div>
|
||||
<div className={`dm-lb-card-anchor is-${pos}`}>
|
||||
<motion.div className="dm-lb-card-story" style={{ opacity, y, x, scale }}>
|
||||
<div className="dm-lb-card-story__head">
|
||||
<span className="dm-lb-pillar__num">{num}</span>
|
||||
<span className="dm-lb-pillar__kicker">{kicker}</span>
|
||||
</div>
|
||||
<h3 className="dm-lb-pillar__title">{title}</h3>
|
||||
{children}
|
||||
</motion.div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -182,6 +196,22 @@ export default function LogisticsBrainSection({ connected = false }: { connected
|
||||
const p5o = useTransform(scroll, [0.75, 0.78, 0.855, 0.875], [0, 1, 1, 0]);
|
||||
const p5y = useTransform(scroll, [0.75, 0.79], [26, 0]);
|
||||
|
||||
// Horizontal slide + scale per beat — same windows as the opacity above, so the
|
||||
// card glides between its stage anchors (Left → Center → Right → Left → Center-Hero)
|
||||
// in lockstep with the camera. Each card enters from the direction of the previous
|
||||
// stage and drifts toward the next as it leaves, reading as one continuous travel.
|
||||
const p1x = useTransform(scroll, [0.135, 0.165, 0.255, 0.275], [-52, 0, 0, 52]);
|
||||
const p1s = useTransform(scroll, [0.135, 0.165, 0.255, 0.275], [0.965, 1, 1, 0.965]);
|
||||
const p2x = useTransform(scroll, [0.29, 0.32, 0.415, 0.435], [-52, 0, 0, 52]);
|
||||
const p2s = useTransform(scroll, [0.29, 0.32, 0.415, 0.435], [0.965, 1, 1, 0.965]);
|
||||
const p3x = useTransform(scroll, [0.45, 0.48, 0.575, 0.595], [-52, 0, 0, -52]);
|
||||
const p3s = useTransform(scroll, [0.45, 0.48, 0.575, 0.595], [0.965, 1, 1, 0.965]);
|
||||
const p4x = useTransform(scroll, [0.61, 0.64, 0.715, 0.735], [52, 0, 0, 52]);
|
||||
const p4s = useTransform(scroll, [0.61, 0.64, 0.715, 0.735], [0.965, 1, 1, 0.965]);
|
||||
// Hero (final selection): scales up a touch and holds center as it settles.
|
||||
const p5x = useTransform(scroll, [0.75, 0.78, 0.855, 0.875], [-52, 0, 0, 0]);
|
||||
const p5s = useTransform(scroll, [0.75, 0.78, 0.855, 0.875], [0.97, 1.05, 1.05, 1.0]);
|
||||
|
||||
const finaleOpacity = useTransform(scroll, [P.finale - 0.02, P.finale + 0.04], [0, 1]);
|
||||
const finaleY = useTransform(scroll, [P.finale - 0.02, P.finale + 0.06], [40, 0]);
|
||||
const taglineOpacity = useTransform(scroll, [P.finale + 0.04, P.finale + 0.1], [0, 1]);
|
||||
@@ -217,18 +247,18 @@ export default function LogisticsBrainSection({ connected = false }: { connected
|
||||
<span className="dm-lb-arrow">↓</span>
|
||||
</motion.div>
|
||||
|
||||
{/* STEP 01 — Generate Routes */}
|
||||
<StoryCard step={step} index={0} opacity={p1o} y={p1y} num="01" kicker="Generate Routes" title="We create many delivery plans at once">
|
||||
{/* STEP 01 — Generate Routes (card anchored LEFT) */}
|
||||
<StoryCard step={step} index={0} pos="left" opacity={p1o} y={p1y} x={p1x} scale={p1s} num="01" kicker="Generate Routes" title="We create many delivery plans at once">
|
||||
<div className="dm-lb-chips">
|
||||
{STRATEGIES.map((s) => (
|
||||
<span key={s} className="dm-lb-chip">{s}</span>
|
||||
{STRATEGIES.map((s, i) => (
|
||||
<span key={s} className={`dm-lb-chip${i === WINNER_INDEX ? " dm-lb-chip--active" : ""}`}>{s}</span>
|
||||
))}
|
||||
</div>
|
||||
<p className="dm-lb-pillar__foot">6 different ways to deliver all 59 orders — generated in milliseconds.</p>
|
||||
</StoryCard>
|
||||
|
||||
{/* STEP 02 — Check Constraints (the EV paradox) */}
|
||||
<StoryCard step={step} index={1} opacity={p2o} y={p2y} num="02" kicker="Check Constraints" title="Every plan must respect real-world limits">
|
||||
{/* STEP 02 — Check Constraints (card anchored CENTER) */}
|
||||
<StoryCard step={step} index={1} pos="center" opacity={p2o} y={p2y} x={p2x} scale={p2s} num="02" kicker="Check Constraints" title="Every plan must respect real-world limits">
|
||||
<ul className="dm-lb-constraints">
|
||||
{CONSTRAINT_LIST.map((c) => (
|
||||
<li key={c.label}>
|
||||
@@ -241,8 +271,8 @@ export default function LogisticsBrainSection({ connected = false }: { connected
|
||||
<p className="dm-lb-pillar__stat"><strong>59/59</strong> delivered <em>vs 34/59 when battery limits are ignored</em></p>
|
||||
</StoryCard>
|
||||
|
||||
{/* STEP 03 — Score & Compare (the leaderboard) */}
|
||||
<StoryCard step={step} index={2} opacity={p3o} y={p3y} num="03" kicker="Score & Compare" title="Each plan is scored by total delivery cost">
|
||||
{/* STEP 03 — Score & Compare (card anchored RIGHT) */}
|
||||
<StoryCard step={step} index={2} pos="right" opacity={p3o} y={p3y} x={p3x} scale={p3s} num="03" kicker="Score & Compare" title="Each plan is scored by total delivery cost">
|
||||
<ul className="dm-lb-board">
|
||||
{STRATEGY_SCORES.map((s) => (
|
||||
<li key={s.name} className={s.win ? "is-win" : ""}>
|
||||
@@ -254,8 +284,8 @@ export default function LogisticsBrainSection({ connected = false }: { connected
|
||||
</ul>
|
||||
</StoryCard>
|
||||
|
||||
{/* STEP 04 — Guarantee On-Time */}
|
||||
<StoryCard step={step} index={3} opacity={p4o} y={p4y} num="04" kicker="Guarantee On-Time" title="Any plan even 1 minute late is rejected">
|
||||
{/* STEP 04 — Guarantee On-Time (card anchored LEFT) */}
|
||||
<StoryCard step={step} index={3} pos="left" opacity={p4o} y={p4y} x={p4x} scale={p4s} num="04" kicker="Guarantee On-Time" title="Any plan even 1 minute late is rejected">
|
||||
<div className="dm-lb-sla">
|
||||
<span className="dm-lb-sla__badge">⏱️ On-time only</span>
|
||||
<span className="dm-lb-sla__x">✕ Late plan → dropped</span>
|
||||
@@ -263,8 +293,8 @@ export default function LogisticsBrainSection({ connected = false }: { connected
|
||||
<p className="dm-lb-pillar__foot">We only keep plans that hit every promised delivery window.</p>
|
||||
</StoryCard>
|
||||
|
||||
{/* STEP 05 — Pick & Dispatch */}
|
||||
<StoryCard step={step} index={4} opacity={p5o} y={p5y} num="05" kicker="Pick & Dispatch" title="The winning plan is sent to the fleet">
|
||||
{/* STEP 05 — Pick & Dispatch (card anchored CENTER, hero) */}
|
||||
<StoryCard step={step} index={4} pos="hero" opacity={p5o} y={p5y} x={p5x} scale={p5s} num="05" kicker="Pick & Dispatch" title="The winning plan is sent to the fleet">
|
||||
<div className="dm-lb-winner">✓ Multi-Trip selected — lowest cost, zero delays</div>
|
||||
<div className="dm-lb-chips">
|
||||
<span className="dm-lb-chip">EV Bikes</span>
|
||||
@@ -381,62 +411,76 @@ const styles = `
|
||||
.dm-lb-arrow { font-size: 18px; animation: dmLbBob 1.8s ease-in-out infinite; }
|
||||
@keyframes dmLbBob { 0%,100% { transform: translateY(0); opacity: 0.5; } 50% { transform: translateY(6px); opacity: 1; } }
|
||||
|
||||
/* ---- Lower-left workflow card (glass panel, cross-fades per step) ---- */
|
||||
.dm-lb-card-story { position: absolute; left: clamp(18px, 4vw, 56px); bottom: clamp(26px, 7vh, 64px);
|
||||
width: min(440px, 84vw); pointer-events: auto; will-change: opacity, transform;
|
||||
/* ---- Story card: a premium light-glass panel that TRAVELS between stage
|
||||
anchors. The anchor pins the stage position; the inner card slides/scales into
|
||||
it (Left → Center → Right → Left → Center-Hero) in lockstep with scroll. ---- */
|
||||
.dm-lb-card-anchor { position: absolute; bottom: clamp(26px, 7vh, 64px); z-index: 6; pointer-events: none; }
|
||||
.dm-lb-card-anchor.is-left { left: clamp(18px, 4vw, 56px); }
|
||||
.dm-lb-card-anchor.is-right { right: clamp(18px, 4vw, 56px); }
|
||||
.dm-lb-card-anchor.is-center,
|
||||
.dm-lb-card-anchor.is-hero { left: 50%; transform: translateX(-50%); }
|
||||
/* Hero (final selection) sits a little higher + centred so it reads as the payoff. */
|
||||
.dm-lb-card-anchor.is-hero { bottom: clamp(40px, 9vh, 92px); }
|
||||
|
||||
.dm-lb-card-story { position: relative; width: min(440px, 84vw); pointer-events: auto;
|
||||
will-change: opacity, transform; transform-origin: bottom center;
|
||||
padding: 18px 20px; border-radius: 18px;
|
||||
background: rgba(14,8,10,0.9); border: 1px solid rgba(226,53,66,0.22);
|
||||
/* backdrop blur removed — this card cross-fades/translates on scroll, so the blur
|
||||
was recomputed every frame; a near-opaque fill keeps the look at no per-frame cost. */
|
||||
box-shadow: 0 24px 64px -30px rgba(0,0,0,0.92); }
|
||||
/* Premium light glass — clean SaaS surface, brand red used only as a top accent. */
|
||||
background: rgba(255,255,255,0.94);
|
||||
border: 1px solid rgba(15,23,42,0.08); border-top: 3px solid #C01227;
|
||||
box-shadow: 0 28px 70px -34px rgba(15,23,42,0.45); }
|
||||
.dm-lb-card-anchor.is-hero .dm-lb-card-story { width: min(480px, 88vw);
|
||||
box-shadow: 0 38px 92px -34px rgba(192,18,39,0.4); }
|
||||
.dm-lb-card-story__head { display: flex; align-items: center; gap: 10px; margin-bottom: 10px; }
|
||||
.dm-lb-pillar__num { font-size: 12px; font-weight: 700; letter-spacing: 0.1em; color: #ffffff;
|
||||
background: linear-gradient(135deg, #E2354A, #C01227); border-radius: 7px; padding: 3px 8px; }
|
||||
.dm-lb-pillar__kicker { font-size: clamp(11px, 1.1vw, 13px); font-weight: 700; letter-spacing: 0.18em;
|
||||
text-transform: uppercase; color: #F2667A; }
|
||||
.dm-lb .dm-lb-pillar__title { margin: 0 0 12px !important; padding: 0 !important; color: #fbf5f6 !important;
|
||||
text-transform: uppercase; color: #C01227; }
|
||||
.dm-lb .dm-lb-pillar__title { margin: 0 0 12px !important; padding: 0 !important; color: #0f172a !important;
|
||||
font-weight: 700 !important; text-transform: none !important; letter-spacing: -0.015em !important;
|
||||
font-size: clamp(17px, 1.9vw, 24px) !important; line-height: 1.18 !important;
|
||||
text-shadow: 0 0 30px rgba(192,18,39,0.3) !important; }
|
||||
.dm-lb-chips { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 10px; }
|
||||
.dm-lb-chip { font-size: 11.5px; font-weight: 600; letter-spacing: 0.02em; color: #f1dadd;
|
||||
padding: 4px 11px; border-radius: 999px; background: rgba(192,18,39,0.12);
|
||||
border: 1px solid rgba(226,53,66,0.30); white-space: nowrap; }
|
||||
.dm-lb-pillar__foot { margin: 0; font-size: clamp(12px, 1.1vw, 13.5px); line-height: 1.45; color: rgba(236,224,226,0.72); }
|
||||
.dm-lb-pillar__stat { margin: 6px 0 0; font-size: clamp(12.5px, 1.2vw, 15px); color: rgba(236,224,226,0.78); }
|
||||
.dm-lb-pillar__stat strong { color: #4ade80; font-weight: 800; font-size: 1.25em; text-shadow: 0 0 20px rgba(34,197,94,0.5); }
|
||||
.dm-lb-pillar__stat em { font-style: normal; color: rgba(230,218,220,0.55); }
|
||||
font-size: clamp(17px, 1.9vw, 24px) !important; line-height: 1.18 !important; }
|
||||
.dm-lb-chips { display: flex; flex-wrap: wrap; gap: 7px; margin-bottom: 10px; }
|
||||
/* Strategy pills — white pills, soft border + light shadow, brand-red active state. */
|
||||
.dm-lb-chip { font-size: 11.5px; font-weight: 600; letter-spacing: 0.02em; color: #334155;
|
||||
padding: 5px 12px; border-radius: 999px; background: #ffffff;
|
||||
border: 1px solid rgba(15,23,42,0.1); box-shadow: 0 1px 2px rgba(15,23,42,0.06); white-space: nowrap; }
|
||||
.dm-lb-chip--active { color: #ffffff; background: linear-gradient(135deg, #E2354A, #C01227);
|
||||
border-color: transparent; box-shadow: 0 6px 16px -6px rgba(192,18,39,0.5); }
|
||||
.dm-lb-pillar__foot { margin: 0; font-size: clamp(12px, 1.1vw, 13.5px); line-height: 1.45; color: #475569; }
|
||||
.dm-lb-pillar__stat { margin: 6px 0 0; font-size: clamp(12.5px, 1.2vw, 15px); color: #475569; }
|
||||
.dm-lb-pillar__stat strong { color: #16a34a; font-weight: 800; font-size: 1.25em; }
|
||||
.dm-lb-pillar__stat em { font-style: normal; color: #94a3b8; }
|
||||
|
||||
/* Constraints checklist (step 02) */
|
||||
.dm-lb-constraints { list-style: none; margin: 0 0 10px; padding: 0; display: grid; gap: 7px; }
|
||||
.dm-lb-constraints li { display: flex; align-items: center; gap: 9px; }
|
||||
.dm-lb-constraints__icon { font-size: 14px; width: 20px; text-align: center; }
|
||||
.dm-lb-constraints__label { font-size: 13px; font-weight: 700; color: #fbeff0; min-width: 84px; }
|
||||
.dm-lb-constraints__note { font-size: 12px; color: rgba(232,222,224,0.6); }
|
||||
.dm-lb-constraints__label { font-size: 13px; font-weight: 700; color: #0f172a; min-width: 84px; }
|
||||
.dm-lb-constraints__note { font-size: 12px; color: #64748b; }
|
||||
|
||||
/* Scored leaderboard (step 03) */
|
||||
.dm-lb-board { list-style: none; margin: 0; padding: 0; display: grid; gap: 6px; }
|
||||
.dm-lb-board li { display: grid; grid-template-columns: 104px 1fr 26px; align-items: center; gap: 9px; }
|
||||
.dm-lb-board__name { font-size: 11.5px; font-weight: 600; color: rgba(234,226,228,0.68); display: flex; align-items: center; gap: 6px; white-space: nowrap; }
|
||||
.dm-lb-board li.is-win .dm-lb-board__name { color: #fff; font-weight: 800; }
|
||||
.dm-lb-board__name { font-size: 11.5px; font-weight: 600; color: #64748b; display: flex; align-items: center; gap: 6px; white-space: nowrap; }
|
||||
.dm-lb-board li.is-win .dm-lb-board__name { color: #0f172a; font-weight: 800; }
|
||||
.dm-lb-board__tag { font-size: 8px; font-weight: 800; letter-spacing: 0.08em; color: #fff;
|
||||
background: linear-gradient(135deg,#E2354A,#C01227); padding: 2px 5px; border-radius: 5px; }
|
||||
.dm-lb-board__track { height: 7px; border-radius: 999px; background: rgba(255,255,255,0.08); overflow: hidden; }
|
||||
.dm-lb-board__fill { display: block; height: 100%; border-radius: 999px; background: rgba(150,150,165,0.5); }
|
||||
.dm-lb-board li.is-win .dm-lb-board__fill { background: linear-gradient(90deg,#E2354A,#C01227); box-shadow: 0 0 12px rgba(226,53,66,0.6); }
|
||||
.dm-lb-board__score { font-size: 12px; font-weight: 700; color: rgba(234,226,228,0.68); text-align: right; }
|
||||
.dm-lb-board li.is-win .dm-lb-board__score { color: #fff; }
|
||||
.dm-lb-board__track { height: 7px; border-radius: 999px; background: rgba(15,23,42,0.08); overflow: hidden; }
|
||||
.dm-lb-board__fill { display: block; height: 100%; border-radius: 999px; background: rgba(100,116,139,0.45); }
|
||||
.dm-lb-board li.is-win .dm-lb-board__fill { background: linear-gradient(90deg,#E2354A,#C01227); box-shadow: 0 0 12px rgba(226,53,66,0.4); }
|
||||
.dm-lb-board__score { font-size: 12px; font-weight: 700; color: #64748b; text-align: right; }
|
||||
.dm-lb-board li.is-win .dm-lb-board__score { color: #0f172a; }
|
||||
|
||||
/* SLA badges (step 04) */
|
||||
.dm-lb-sla { display: flex; gap: 8px; margin-bottom: 10px; flex-wrap: wrap; }
|
||||
.dm-lb-sla__badge { font-size: 12px; font-weight: 700; color: #86efac; background: rgba(34,197,94,0.1);
|
||||
border: 1px solid rgba(34,197,94,0.32); padding: 6px 12px; border-radius: 999px; }
|
||||
.dm-lb-sla__x { font-size: 12px; font-weight: 700; color: #fca5a5; background: rgba(239,68,68,0.1);
|
||||
border: 1px solid rgba(239,68,68,0.32); padding: 6px 12px; border-radius: 999px; }
|
||||
.dm-lb-sla__badge { font-size: 12px; font-weight: 700; color: #15803d; background: rgba(34,197,94,0.1);
|
||||
border: 1px solid rgba(34,197,94,0.3); padding: 6px 12px; border-radius: 999px; }
|
||||
.dm-lb-sla__x { font-size: 12px; font-weight: 700; color: #b91c1c; background: rgba(239,68,68,0.08);
|
||||
border: 1px solid rgba(239,68,68,0.28); padding: 6px 12px; border-radius: 999px; }
|
||||
|
||||
/* Winner banner (step 05) */
|
||||
.dm-lb-winner { font-size: 13.5px; font-weight: 700; color: #fff; margin-bottom: 10px; padding: 9px 13px; border-radius: 12px;
|
||||
background: linear-gradient(135deg, rgba(192,18,39,0.24), rgba(34,197,94,0.16)); border: 1px solid rgba(226,53,66,0.4); }
|
||||
.dm-lb-winner { font-size: 13.5px; font-weight: 700; color: #0f172a; margin-bottom: 10px; padding: 9px 13px; border-radius: 12px;
|
||||
background: linear-gradient(135deg, rgba(192,18,39,0.08), rgba(34,197,94,0.08)); border: 1px solid rgba(226,53,66,0.32); }
|
||||
|
||||
/* ---- Finale: KPI cards ---- */
|
||||
.dm-lb-finale { position: absolute; inset: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center; padding: 0 20px; }
|
||||
@@ -466,7 +510,15 @@ const styles = `
|
||||
.dm-lb { height: 400vh; }
|
||||
.dm-lb-kpis { gap: 12px; }
|
||||
.dm-lb-kpi { min-width: 96px; padding: 14px 14px; }
|
||||
.dm-lb-card-story { left: 0; right: 0; margin: 0 auto; width: calc(100% - 28px); bottom: clamp(20px, 5vh, 44px); padding: 14px 16px; }
|
||||
/* On phones every stage collapses to one centred, full-width position — the
|
||||
horizontal travel only reads on wider screens. */
|
||||
.dm-lb-card-anchor,
|
||||
.dm-lb-card-anchor.is-left,
|
||||
.dm-lb-card-anchor.is-right,
|
||||
.dm-lb-card-anchor.is-center,
|
||||
.dm-lb-card-anchor.is-hero { left: 50%; right: auto; transform: translateX(-50%); bottom: clamp(20px, 5vh, 44px); }
|
||||
.dm-lb-card-story,
|
||||
.dm-lb-card-anchor.is-hero .dm-lb-card-story { width: calc(100vw - 28px); padding: 14px 16px; }
|
||||
.dm-lb-board li { grid-template-columns: 88px 1fr 24px; }
|
||||
.dm-lb-constraints__note { display: none; }
|
||||
}
|
||||
|
||||
@@ -5,63 +5,54 @@ import { ScrollReveal } from "@/animations/Reveal";
|
||||
export default function BlogGrid() {
|
||||
const blogs = [
|
||||
{
|
||||
date: "Apl.06/2025",
|
||||
title: "How AI Is Transforming Last-Mile EV Delivery",
|
||||
excerpt: "Machine learning and real-time data are reshaping how fleets plan, dispatch, and adapt — making every kilometre smarter than the last.",
|
||||
category: "Technology",
|
||||
image: "/images/blog-post-pic-17.png",
|
||||
},
|
||||
{
|
||||
date: "Apl.06/2025",
|
||||
title: "The EV Paradox: Solving Range Anxiety for Urban Fleets",
|
||||
excerpt: "Electric vehicles promise sustainability, but battery constraints introduce a new routing challenge. Here's how MileTruth™ AI solves it before dispatch.",
|
||||
category: "EV Fleet",
|
||||
image: "/images/blog-post-pic-18-840x840.jpg",
|
||||
image: "/images/ev-paradox.png",
|
||||
},
|
||||
{
|
||||
date: "Apl.06/2025",
|
||||
title: "42% Less Distance: Insights from Our Hyderabad Hub",
|
||||
excerpt: "A detailed look at how Doormile's MileTruth routing engine delivered measurable efficiency gains — fewer vehicles, less fuel, and zero SLA misses.",
|
||||
category: "Case Study",
|
||||
image: "/images/blog-post-pic-15.png",
|
||||
},
|
||||
{
|
||||
date: "Apl.06/2025",
|
||||
title: "MileTruth™ AI — 10 Stages to Smarter Dispatch",
|
||||
excerpt: "From order ingestion to final route output in under 45ms — a technical walkthrough of the ten-stage pipeline at the heart of our routing engine.",
|
||||
category: "MileTruth",
|
||||
image: "/images/blog-post-pic-31.png",
|
||||
},
|
||||
{
|
||||
date: "Apl.06/2025",
|
||||
title: "Why Mathematical Precision Beats Heuristics in Routing",
|
||||
excerpt: "Most routing tools guess. We calculate. Powered by Google OR-Tools, MileTruth evaluates six parallel strategy universes to select the optimal route every time.",
|
||||
category: "Technology",
|
||||
image: "/images/blog-post-pic-14.jpeg",
|
||||
},
|
||||
{
|
||||
date: "Apl.06/2025",
|
||||
title: "Fleet Reduction Without Compromising Delivery Volume",
|
||||
excerpt: "Deploying 37% fewer vehicles while handling the same order volumes isn't a trade-off — it's the result of smarter routing intelligence applied at every dispatch.",
|
||||
category: "Fleet Management",
|
||||
image: "/images/blog-post-pic-8.jpeg",
|
||||
},
|
||||
{
|
||||
date: "Apl.06/2025",
|
||||
title: "Building a Greener City: The Future of Urban Logistics",
|
||||
excerpt: "Cities are demanding cleaner delivery. We explore how AI-powered EV fleets and optimised routing create a path to zero-emission last-mile logistics at city scale.",
|
||||
category: "Sustainability",
|
||||
image: "/images/blog-post-pic-6.jpeg",
|
||||
},
|
||||
{
|
||||
date: "Apl.06/2025",
|
||||
title: "How Doormile Maintains 99.9% SLA Compliance at Scale",
|
||||
excerpt: "Hitting SLA targets 99.9% of the time isn't luck — it's the product of ETA pre-validation, real-time rebalancing, and a routing engine built with delivery reliability as its first constraint.",
|
||||
category: "Operations",
|
||||
image: "/images/blog-post-pic-4.jpeg",
|
||||
image: "/images/last-mile-approach.jpg",
|
||||
},
|
||||
{
|
||||
date: "Apl.06/2025",
|
||||
title: "Battery Simulation: The Secret to EV Route Pre-Validation",
|
||||
excerpt: "Before a single rider leaves the hub, MileTruth™ simulates every route against real charge capacity — eliminating mid-route failures and protecting your fulfillment rate.",
|
||||
category: "EV Fleet",
|
||||
@@ -114,24 +105,6 @@ export default function BlogGrid() {
|
||||
border-color: rgba(192, 18, 39, 0.2) !important;
|
||||
}
|
||||
|
||||
.custom-blog-date {
|
||||
font-size: 12px !important;
|
||||
font-weight: 700 !important;
|
||||
color: #94a3b8 !important;
|
||||
text-transform: uppercase !important;
|
||||
letter-spacing: 1px !important;
|
||||
margin-bottom: 8px !important;
|
||||
display: block !important;
|
||||
font-family: var(--font-manrope), sans-serif !important;
|
||||
}
|
||||
|
||||
.custom-blog-divider {
|
||||
width: 100% !important;
|
||||
height: 1px !important;
|
||||
background: rgba(0, 0, 0, 0.08) !important;
|
||||
margin-bottom: 20px !important;
|
||||
}
|
||||
|
||||
.custom-blog-title {
|
||||
font-size: 20px !important;
|
||||
font-weight: 800 !important;
|
||||
@@ -157,11 +130,32 @@ export default function BlogGrid() {
|
||||
font-weight: 500 !important;
|
||||
color: #64748b !important;
|
||||
line-height: 1.6 !important;
|
||||
margin: 0 0 24px 0 !important;
|
||||
margin: 0 0 18px 0 !important;
|
||||
text-transform: none !important;
|
||||
font-family: var(--font-manrope), sans-serif !important;
|
||||
}
|
||||
|
||||
.custom-blog-readmore {
|
||||
display: inline-flex !important;
|
||||
align-items: center !important;
|
||||
gap: 6px !important;
|
||||
font-size: 13px !important;
|
||||
font-weight: 800 !important;
|
||||
color: #c01227 !important;
|
||||
text-transform: uppercase !important;
|
||||
letter-spacing: 0.5px !important;
|
||||
margin: 0 0 24px 0 !important;
|
||||
font-family: var(--font-manrope), sans-serif !important;
|
||||
}
|
||||
|
||||
.custom-blog-readmore-arrow {
|
||||
transition: transform 0.3s cubic-bezier(0.2, 0.8, 0.2, 1) !important;
|
||||
}
|
||||
|
||||
.custom-blog-card:hover .custom-blog-readmore-arrow {
|
||||
transform: translateX(5px) !important;
|
||||
}
|
||||
|
||||
.custom-blog-img-container {
|
||||
position: relative !important;
|
||||
width: 100% !important;
|
||||
@@ -201,23 +195,21 @@ export default function BlogGrid() {
|
||||
<div className="custom-blog-card">
|
||||
{/* Text Block at Top */}
|
||||
<div className="flex flex-col">
|
||||
{/* Date */}
|
||||
<span className="custom-blog-date">
|
||||
{blog.date}
|
||||
</span>
|
||||
|
||||
{/* Thin divider line */}
|
||||
<div className="custom-blog-divider" />
|
||||
|
||||
{/* Bold Title */}
|
||||
<h3 className="custom-blog-title">
|
||||
{blog.title}
|
||||
</h3>
|
||||
|
||||
|
||||
{/* Description Excerpt */}
|
||||
<p className="custom-blog-excerpt">
|
||||
{blog.excerpt}
|
||||
</p>
|
||||
|
||||
{/* Read More */}
|
||||
<span className="custom-blog-readmore">
|
||||
Read More
|
||||
<span aria-hidden="true" className="custom-blog-readmore-arrow">→</span>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{/* Image at Bottom */}
|
||||
|
||||
@@ -10,6 +10,7 @@ export default function BlogsHero() {
|
||||
font-family: var(--font-manrope), sans-serif !important;
|
||||
font-size: clamp(34px, 5.5vw, 68px) !important;
|
||||
font-weight: 850 !important;
|
||||
line-height: 1.08 !important;
|
||||
text-transform: uppercase !important;
|
||||
letter-spacing: -1.5px !important;
|
||||
margin: 0 !important;
|
||||
@@ -30,22 +31,11 @@ export default function BlogsHero() {
|
||||
{/* Title / Heading for Blogs */}
|
||||
<div style={{ textAlign: "center", color: "#fff", zIndex: 5 }}>
|
||||
<h1 className="blogs-hero-title">
|
||||
Our <span style={{ color: "#C01227" }}>Blogs</span>
|
||||
Delivering Trust.<br />
|
||||
<span style={{ color: "#C01227" }}>Beyond Boundaries</span>
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
<div
|
||||
className="elementor-element elementor-element-91be79f elementor-widget__width-auto elementor-absolute elementor-widget elementor-widget-logico_breadcrumbs"
|
||||
style={{ position: "absolute", bottom: "40px", left: "50%", transform: "translateX(-50%)", zIndex: 10 }}
|
||||
>
|
||||
<div className="elementor-widget-container">
|
||||
<nav className="breadcrumbs" style={{ background: "rgba(255, 255, 255, 0.1)", backdropFilter: "blur(10px)", padding: "10px 24px", borderRadius: "30px", border: "1px solid rgba(255, 255, 255, 0.15)" }}>
|
||||
<Link href="/" style={{ color: "#fff", fontWeight: 600 }}>Home</Link>
|
||||
<span className="delimiter" style={{ color: "rgba(255, 255, 255, 0.6)", margin: "0 8px" }}>/</span>
|
||||
<span className="current" style={{ color: "#C01227", fontWeight: 700 }}>Blogs</span>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -77,7 +77,7 @@ export default function CompetitiveEdge() {
|
||||
<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>
|
||||
<h2 className="moat-heading" data-text="WHERE DOORMILE WINS">WHERE DOORMILE 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>
|
||||
|
||||
@@ -207,7 +207,7 @@ export default function EVLogisticSection() {
|
||||
|
||||
.ev-logistic-kicker {
|
||||
font-size: 14px !important;
|
||||
font-weight: 500 !important;
|
||||
font-weight: 400 !important;
|
||||
line-height: 2.1429em !important;
|
||||
letter-spacing: 0px !important; /* Expands to 3px on scroll */
|
||||
text-transform: lowercase !important;
|
||||
@@ -464,7 +464,7 @@ export default function EVLogisticSection() {
|
||||
>
|
||||
{/* Top Header Row with / features / kicker */}
|
||||
<div className="ev-logistic-header">
|
||||
<div className="ev-logistic-kicker">/ features /</div>
|
||||
<div className="ev-logistic-kicker">/ Build Electric Vehicles /</div>
|
||||
</div>
|
||||
|
||||
<div className="ev-logistic-body-grid">
|
||||
|
||||
@@ -5,11 +5,11 @@ import React, { useState, useEffect } from "react";
|
||||
export default function HowItWorksHero() {
|
||||
const [activeSlide, setActiveSlide] = useState(0);
|
||||
|
||||
// Auto-slide every 6 seconds
|
||||
// Auto-slide every 7 seconds — slower, more readable, professional pacing
|
||||
useEffect(() => {
|
||||
const interval = setInterval(() => {
|
||||
setActiveSlide((prev) => (prev === 0 ? 1 : 0));
|
||||
}, 6000);
|
||||
}, 7000);
|
||||
return () => clearInterval(interval);
|
||||
}, []);
|
||||
|
||||
@@ -77,11 +77,23 @@ export default function HowItWorksHero() {
|
||||
|
||||
.elementor-element.elementor-element-6c7cbcb .text-content {
|
||||
text-align: center !important;
|
||||
max-width: 800px !important;
|
||||
max-width: 820px !important;
|
||||
margin: 0 auto !important;
|
||||
}
|
||||
|
||||
/* Larger, more readable hero subtitle on large/4K screens */
|
||||
.elementor-element.elementor-element-6c7cbcb .content-slider-item-text p {
|
||||
font-size: clamp(16px, 1.35vw, 23px) !important;
|
||||
line-height: 1.65 !important;
|
||||
}
|
||||
|
||||
@media (min-width: 1025px) {
|
||||
/* Match Home's hero frame so the floating navbar sits with the same
|
||||
breathing space. Home (.elementor-61) frames the hero card at 20px;
|
||||
this page falls through to the shared kit's 32px base. */
|
||||
.elementor-element.elementor-element-741f56c {
|
||||
padding: 20px !important;
|
||||
}
|
||||
.elementor-element.elementor-element-6c7cbcb .owl-carousel.owl-theme .content-item {
|
||||
height: 800px !important;
|
||||
min-height: 800px !important;
|
||||
|
||||
@@ -8,11 +8,11 @@ export default function IndexHero() {
|
||||
const [activeSlide, setActiveSlide] = useState(0);
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
// Auto-slide every 6 seconds
|
||||
// Auto-slide every 7 seconds — slower, more readable, professional pacing
|
||||
useEffect(() => {
|
||||
const interval = setInterval(() => {
|
||||
setActiveSlide((prev) => (prev === 0 ? 1 : 0));
|
||||
}, 6000);
|
||||
}, 7000);
|
||||
return () => clearInterval(interval);
|
||||
}, []);
|
||||
|
||||
@@ -94,12 +94,18 @@ export default function IndexHero() {
|
||||
|
||||
.logico-content-slider-widget .text-content {
|
||||
width: 100% !important;
|
||||
max-width: min(680px, 100%) !important;
|
||||
max-width: min(780px, 100%) !important;
|
||||
box-sizing: border-box !important;
|
||||
padding-left: 15px !important;
|
||||
padding-right: 15px !important;
|
||||
}
|
||||
|
||||
/* Larger, more readable hero subtitle on large/4K screens */
|
||||
.logico-content-slider-widget .content-slider-item-text p {
|
||||
font-size: clamp(16px, 1.35vw, 23px) !important;
|
||||
line-height: 1.65 !important;
|
||||
}
|
||||
|
||||
/* Responsive slider heights */
|
||||
.logico-content-slider-widget .owl-stage-outer {
|
||||
height: 800px !important;
|
||||
|
||||
@@ -11,14 +11,14 @@ export default function IndustrySolutions() {
|
||||
|
||||
<div className="elementor-element elementor-element-f64bd88 e-con-full e-flex cut-corner-no sticky-container-off e-con e-child" data-id="f64bd88" data-element_type="container" data-e-type="container">
|
||||
<div className="elementor-element elementor-element-5ed2dbb e-con-full e-flex cut-corner-no sticky-container-off e-con e-child" data-id="5ed2dbb" data-element_type="container" data-e-type="container">
|
||||
<div className="elementor-element elementor-element-c8162c4 elementor-widget elementor-widget-logico_heading industry-section-label" data-id="c8162c4" data-element_type="widget" data-e-type="widget" data-widget_type="logico_heading.default" style={{paddingLeft: "50px"}}>
|
||||
<div className="elementor-element elementor-element-c8162c4 elementor-widget elementor-widget-logico_heading industry-section-label" data-id="c8162c4" data-element_type="widget" data-e-type="widget" data-widget_type="logico_heading.default">
|
||||
<style dangerouslySetInnerHTML={{ __html: `
|
||||
/* Minimal section label — matches the "/ Doormile Approach /" pattern */
|
||||
.industry-section-label {
|
||||
width: 100%;
|
||||
}
|
||||
.industry-section-label > .elementor-widget-container {
|
||||
max-width: 1740px;
|
||||
max-width: 100%;
|
||||
margin: 12px 0 50px 0;
|
||||
padding: 0 0 14px 0;
|
||||
border-style: solid;
|
||||
@@ -60,17 +60,9 @@ export default function IndustrySolutions() {
|
||||
data-element_type="widget"
|
||||
data-e-type="widget"
|
||||
data-widget_type="logico_heading.default"
|
||||
style={{marginLeft: "50px"}}
|
||||
>
|
||||
<div className="elementor-widget-container" style={{ margin: "30px 0 0 0"}}>
|
||||
<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" }}>
|
||||
<h3 className="logico-title" style={{ fontSize: "clamp(28px, 3.5vw, 48px)", lineHeight: "1.1", fontWeight: 800, textTransform: "uppercase", maxWidth: "900px" }}>
|
||||
<ScrollReveal delay={0.05} duration={0.8} yOffset={25}>
|
||||
Smart solutions built exclusively for your <span style={{ color: "#c01227" }}>industry</span>
|
||||
</ScrollReveal>
|
||||
|
||||
@@ -252,8 +252,16 @@ export default function IntelligenceGrid() {
|
||||
/* Buttery-Smooth Hardware-Accelerated 3D AI Logistics Timeline Styles */
|
||||
.roadmap-hero-section {
|
||||
position: relative;
|
||||
background: #09090b !important;
|
||||
width: 100%;
|
||||
background: #09090b !important;
|
||||
/* Stay WIDE and immersive — span nearly the full viewport, inset only
|
||||
by the site's standard left/right gutter (40px desktop, 32/24 on
|
||||
smaller screens) so the dark band never touches the viewport edge.
|
||||
No narrow max-width: the roadmap timeline + 4 milestone cards keep
|
||||
the large content area. Auto margins keep the gutters equal. */
|
||||
width: calc(100% - 80px);
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
border-radius: 24px;
|
||||
padding: 100px 40px;
|
||||
box-sizing: border-box;
|
||||
font-family: 'Manrope', sans-serif;
|
||||
@@ -299,7 +307,9 @@ export default function IntelligenceGrid() {
|
||||
}
|
||||
|
||||
.roadmap-hero-section .container {
|
||||
max-width: 1320px;
|
||||
/* Fill the wide section so the timeline + cards span most of the
|
||||
available width (no narrow content cap). */
|
||||
max-width: 100%;
|
||||
width: 100%;
|
||||
margin: 0 auto;
|
||||
position: relative;
|
||||
@@ -683,6 +693,7 @@ export default function IntelligenceGrid() {
|
||||
/* Responsive Constraints */
|
||||
@media (max-width: 1024px) {
|
||||
.roadmap-hero-section {
|
||||
width: calc(100% - 64px); /* 32px gutter */
|
||||
padding: 80px 24px;
|
||||
}
|
||||
|
||||
@@ -698,6 +709,7 @@ export default function IntelligenceGrid() {
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.roadmap-hero-section {
|
||||
width: calc(100% - 48px); /* 24px gutter */
|
||||
padding: 60px 16px;
|
||||
}
|
||||
|
||||
|
||||
284
src/components/sections/LegalDocument.tsx
Normal file
284
src/components/sections/LegalDocument.tsx
Normal file
@@ -0,0 +1,284 @@
|
||||
import React from "react";
|
||||
import Link from "next/link";
|
||||
|
||||
/**
|
||||
* Shared layout for the legal pages (Privacy Policy, Terms of Service, Cookie
|
||||
* Policy) so all three stay pixel-consistent. Content is passed in as structured
|
||||
* blocks; this component owns the hero, the desktop sticky table of contents and
|
||||
* the 800px reading column described in the design spec.
|
||||
*/
|
||||
|
||||
export type LegalBlock =
|
||||
| { type: "p"; text: React.ReactNode }
|
||||
| { type: "lead"; text: React.ReactNode }
|
||||
| { type: "h3"; text: string }
|
||||
| { type: "ul"; items: React.ReactNode[] };
|
||||
|
||||
export type LegalSection = {
|
||||
heading: string;
|
||||
blocks: LegalBlock[];
|
||||
};
|
||||
|
||||
export type LegalDocumentProps = {
|
||||
title: string;
|
||||
lastUpdated: string;
|
||||
intro: React.ReactNode;
|
||||
sections: LegalSection[];
|
||||
};
|
||||
|
||||
/** Stable, URL-safe id from a section heading (for TOC anchors). */
|
||||
function slug(heading: string): string {
|
||||
return heading
|
||||
.toLowerCase()
|
||||
.replace(/&/g, "and")
|
||||
.replace(/[^a-z0-9]+/g, "-")
|
||||
.replace(/(^-|-$)/g, "");
|
||||
}
|
||||
|
||||
function Block({ block }: { block: LegalBlock }) {
|
||||
switch (block.type) {
|
||||
case "lead":
|
||||
return <p className="dm-legal__lead">{block.text}</p>;
|
||||
case "p":
|
||||
return <p className="dm-legal__p">{block.text}</p>;
|
||||
case "h3":
|
||||
return <h3 className="dm-legal__h3">{block.text}</h3>;
|
||||
case "ul":
|
||||
return (
|
||||
<ul className="dm-legal__ul">
|
||||
{block.items.map((item, i) => (
|
||||
<li key={i}>{item}</li>
|
||||
))}
|
||||
</ul>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default function LegalDocument({ title, lastUpdated, intro, sections }: LegalDocumentProps) {
|
||||
return (
|
||||
<section className="dm-legal" aria-label={title}>
|
||||
<div className="dm-legal__wrap">
|
||||
{/* Desktop sticky table of contents */}
|
||||
<aside className="dm-legal__toc" aria-label="On this page">
|
||||
<div className="dm-legal__toc-inner">
|
||||
<p className="dm-legal__toc-label">On this page</p>
|
||||
<nav>
|
||||
<ul>
|
||||
{sections.map((s) => (
|
||||
<li key={s.heading}>
|
||||
<a href={`#${slug(s.heading)}`}>{s.heading}</a>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<div className="dm-legal__main">
|
||||
<header className="dm-legal__hero">
|
||||
<h1 className="dm-legal__title">{title}</h1>
|
||||
<p className="dm-legal__updated">Last Updated: {lastUpdated}</p>
|
||||
<p className="dm-legal__lead">{intro}</p>
|
||||
</header>
|
||||
|
||||
<article className="dm-legal__content">
|
||||
{sections.map((s) => (
|
||||
<section key={s.heading} id={slug(s.heading)} className="dm-legal__section">
|
||||
<h2 className="dm-legal__h2">{s.heading}</h2>
|
||||
{s.blocks.map((b, i) => (
|
||||
<Block key={i} block={b} />
|
||||
))}
|
||||
</section>
|
||||
))}
|
||||
</article>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>{styles}</style>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
/** Renders the recurring "contact us through our Contact page" link. */
|
||||
export function ContactLink() {
|
||||
return (
|
||||
<Link href="/contact" className="dm-legal__link">
|
||||
Contact page
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = `
|
||||
.dm-legal {
|
||||
background: #ffffff;
|
||||
color: #334155;
|
||||
/* Top padding clears the fixed/absolute floating navbar (~104px) + breathing room. */
|
||||
padding: clamp(132px, 16vh, 184px) 0 clamp(72px, 10vw, 96px);
|
||||
font-family: var(--font-manrope), system-ui, -apple-system, sans-serif;
|
||||
}
|
||||
|
||||
.dm-legal__wrap {
|
||||
max-width: 1180px;
|
||||
margin: 0 auto;
|
||||
padding: 0 clamp(20px, 5vw, 40px);
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr);
|
||||
gap: 0;
|
||||
}
|
||||
|
||||
/* ---- Sticky table of contents (desktop only) ---- */
|
||||
.dm-legal__toc { display: none; }
|
||||
|
||||
@media (min-width: 1080px) {
|
||||
.dm-legal__wrap {
|
||||
grid-template-columns: 248px minmax(0, 800px);
|
||||
justify-content: center;
|
||||
gap: 64px;
|
||||
}
|
||||
.dm-legal__toc { display: block; }
|
||||
}
|
||||
|
||||
.dm-legal__toc-inner { position: sticky; top: 128px; }
|
||||
.dm-legal__toc-label {
|
||||
margin: 0 0 14px;
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.14em;
|
||||
text-transform: uppercase;
|
||||
color: #94a3b8;
|
||||
}
|
||||
.dm-legal__toc nav ul { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 10px; }
|
||||
.dm-legal__toc nav a {
|
||||
display: block;
|
||||
font-size: 14px;
|
||||
line-height: 1.4;
|
||||
color: #64748b;
|
||||
text-decoration: none;
|
||||
border-left: 2px solid transparent;
|
||||
padding-left: 12px;
|
||||
transition: color 0.2s ease, border-color 0.2s ease;
|
||||
}
|
||||
.dm-legal__toc nav a:hover { color: #c01227; border-left-color: #c01227; }
|
||||
|
||||
/* ---- Reading column (max 800px) ---- */
|
||||
.dm-legal__main { min-width: 0; max-width: 800px; }
|
||||
|
||||
.dm-legal__hero { margin-bottom: clamp(40px, 6vw, 56px); }
|
||||
.dm-legal__title {
|
||||
margin: 0 !important;
|
||||
padding: 0 !important;
|
||||
/* !important / text-transform override the global ".elementor-kit-5 h1"
|
||||
(uppercase + kit font-size) so headings render in normal case at the spec sizes. */
|
||||
font-size: clamp(40px, 6vw, 60px) !important;
|
||||
font-weight: 800 !important;
|
||||
line-height: 1.08 !important;
|
||||
letter-spacing: -0.02em !important;
|
||||
text-transform: none !important;
|
||||
color: #0f172a !important;
|
||||
}
|
||||
.dm-legal__updated {
|
||||
margin: 16px 0 0;
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.08em;
|
||||
text-transform: uppercase;
|
||||
color: #94a3b8;
|
||||
}
|
||||
|
||||
.dm-legal__lead {
|
||||
margin: 24px 0 0;
|
||||
font-size: clamp(18px, 1.6vw, 20px);
|
||||
line-height: 1.7;
|
||||
color: #475569;
|
||||
}
|
||||
.dm-legal__hero .dm-legal__lead { margin-top: 24px; }
|
||||
|
||||
/* ---- Sections ---- */
|
||||
.dm-legal__content { display: flex; flex-direction: column; }
|
||||
.dm-legal__section { padding-top: 32px; }
|
||||
.dm-legal__section:first-child { padding-top: 0; }
|
||||
|
||||
.dm-legal__h2 {
|
||||
margin: 0 0 16px !important;
|
||||
padding: 0 !important;
|
||||
font-size: clamp(24px, 3vw, 32px) !important;
|
||||
font-weight: 700 !important;
|
||||
line-height: 1.2 !important;
|
||||
letter-spacing: -0.01em !important;
|
||||
text-transform: none !important;
|
||||
color: #0f172a !important;
|
||||
/* Offset anchor jumps so the heading isn't hidden under the fixed navbar. */
|
||||
scroll-margin-top: 120px;
|
||||
}
|
||||
.dm-legal__h3 {
|
||||
margin: 24px 0 8px !important;
|
||||
padding: 0 !important;
|
||||
font-size: 20px !important;
|
||||
font-weight: 700 !important;
|
||||
line-height: 1.35 !important;
|
||||
text-transform: none !important;
|
||||
color: #0f172a !important;
|
||||
}
|
||||
.dm-legal__p {
|
||||
margin: 0 0 16px;
|
||||
font-size: 18px;
|
||||
line-height: 1.7;
|
||||
color: #334155;
|
||||
}
|
||||
.dm-legal__p:last-child { margin-bottom: 0; }
|
||||
|
||||
.dm-legal__ul { margin: 4px 0 16px; padding: 0; list-style: none; display: flex; flex-direction: column; gap: 10px; }
|
||||
.dm-legal__ul li {
|
||||
position: relative;
|
||||
padding-left: 26px;
|
||||
font-size: 18px;
|
||||
line-height: 1.7;
|
||||
color: #334155;
|
||||
}
|
||||
/* Extra .dm-legal prefix raises specificity above the global theme rule
|
||||
".logico-front-end ul li:before" (a fontello glyph), so our clean red dot
|
||||
replaces the inherited checkmark marker. */
|
||||
.dm-legal .dm-legal__ul li::before {
|
||||
content: "" !important;
|
||||
position: absolute;
|
||||
left: 4px;
|
||||
top: 0.62em;
|
||||
width: 7px;
|
||||
height: 7px;
|
||||
border-radius: 50%;
|
||||
background: #c01227;
|
||||
font-size: 0;
|
||||
}
|
||||
/* TOC links are inside a <ul> too — suppress the same inherited glyph marker. */
|
||||
.dm-legal .dm-legal__toc nav li::before { content: none !important; }
|
||||
|
||||
.dm-legal__link { color: #c01227; font-weight: 600; text-decoration: none; border-bottom: 1px solid rgba(192,18,39,0.35); }
|
||||
.dm-legal__link:hover { border-bottom-color: #c01227; }
|
||||
|
||||
@media (max-width: 1079px) {
|
||||
.dm-legal__main { margin: 0 auto; }
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
Navbar visibility — LEGAL PAGES ONLY.
|
||||
This <style> block is rendered exclusively by LegalDocument, which only mounts
|
||||
on /privacy-policy, /terms-of-service and /cookie-policy. So although the rule
|
||||
targets the global #masthead, it is physically absent from every other page's
|
||||
HTML and cannot affect them — no global CSS file is touched.
|
||||
|
||||
Why it's needed: the desktop logo and nav links are white and the navbar bar is
|
||||
transparent at the top of the page. Over the dark heroes used elsewhere that's
|
||||
fine, but on these white pages the navbar vanishes. Give the bar the same dark
|
||||
glass fill the rest of the site already shows on scroll. Desktop only — the
|
||||
mobile logo is black-on-transparent and already legible here.
|
||||
============================================================ */
|
||||
@media (min-width: 1025px) {
|
||||
#masthead .elementor-element.elementor-element-466de1b {
|
||||
background: rgba(40, 40, 40, 0.75) !important;
|
||||
-webkit-backdrop-filter: blur(12px) !important;
|
||||
backdrop-filter: blur(12px) !important;
|
||||
border-bottom: 1px solid rgba(255, 255, 255, 0.08) !important;
|
||||
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.16) !important;
|
||||
}
|
||||
}
|
||||
`;
|
||||
@@ -99,11 +99,11 @@ export default function MileTruthHero() {
|
||||
.miletruth-hero .content-slider-item-text p {
|
||||
color: rgba(255, 255, 255, 0.72) !important;
|
||||
font-family: var(--font-manrope), "Manrope", sans-serif !important;
|
||||
font-size: clamp(16px, 1.8vw, 20px) !important;
|
||||
font-size: clamp(17px, 1.6vw, 23px) !important;
|
||||
font-weight: 500 !important;
|
||||
line-height: 1.6 !important;
|
||||
line-height: 1.65 !important;
|
||||
margin: 0 auto !important;
|
||||
max-width: 800px;
|
||||
max-width: 820px;
|
||||
}
|
||||
.miletruth-hero .slide-content {
|
||||
display: flex !important;
|
||||
|
||||
@@ -10,7 +10,7 @@ export default function Miles3() {
|
||||
/* =====================================================================
|
||||
How It Works · "Doormile connects first, mid, and last mile" section
|
||||
Self-contained recreation of the original Elementor design
|
||||
(source: public/css/sections/section-miles3.css + kit-5 typography).
|
||||
(originally Elementor section CSS, now inlined below + in /public/css/site.css).
|
||||
Explicit flex/grid values because the Elementor framework reads them
|
||||
from CSS custom properties that aren't set in this rebuild.
|
||||
===================================================================== */
|
||||
@@ -25,7 +25,7 @@ export default function Miles3() {
|
||||
margin: 20px 20px 0 20px;
|
||||
background-color: #1F1F1F;
|
||||
border-radius: 25px 25px 0 0;
|
||||
padding: 150px 0 0 0;
|
||||
padding: 90px 0 0 0;
|
||||
}
|
||||
/* Boxed inner — centered, original content width */
|
||||
.elementor-element-c36a604 > .e-con-inner {
|
||||
@@ -165,7 +165,7 @@ export default function Miles3() {
|
||||
.logico-front-end .elementor-element-63a9de5 .logico-title { font-size: clamp(40px, 5vw, 60px); }
|
||||
}
|
||||
@media (max-width: 1020px) {
|
||||
.elementor-element-c36a604 { margin: 15px 15px 0 15px; padding: 100px 0 0 0; }
|
||||
.elementor-element-c36a604 { margin: 15px 15px 0 15px; padding: 76px 0 0 0; }
|
||||
.elementor-element-77d1265 { padding: 0 30px; }
|
||||
.elementor-element-4add972 { grid-template-columns: repeat(2, 1fr); gap: 50px 40px; }
|
||||
.logico-front-end .elementor-element-63a9de5 .logico-title { font-size: clamp(34px, 6vw, 52px); }
|
||||
|
||||
@@ -8,11 +8,7 @@ export default function OurTeam() {
|
||||
position: "COO & Operational Specialist",
|
||||
image: "/images/Investor.png",
|
||||
},
|
||||
{
|
||||
name: "Fazul Ilahi",
|
||||
position: "CTO & Technology Specialist",
|
||||
image: "/images/Fazul.png",
|
||||
},
|
||||
|
||||
{
|
||||
name: "Parthiban",
|
||||
position: "CGO & Growth Specialist",
|
||||
@@ -22,6 +18,11 @@ export default function OurTeam() {
|
||||
name: "Aravinth",
|
||||
position: "CFO & Finance Specialist",
|
||||
image: "/images/Aravinth.png",
|
||||
},
|
||||
{
|
||||
name: "Fazul Ilahi",
|
||||
position: "CTO & Technology Specialist",
|
||||
image: "/images/Fazul.png",
|
||||
},
|
||||
{
|
||||
name: "Suriya Kumar",
|
||||
@@ -48,6 +49,9 @@ export default function OurTeam() {
|
||||
width: 100%;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
padding-left: clamp(20px, 4vw, 50px) !important;
|
||||
padding-right: clamp(20px, 4vw, 50px) !important;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/* Breathing room above and below the "Meet our the best crew" heading. */
|
||||
@@ -65,38 +69,40 @@ export default function OurTeam() {
|
||||
filter: grayscale(0%);
|
||||
}
|
||||
|
||||
/* Self-contained layout (does not rely on the cached vendor CSS). */
|
||||
/* Grid: three columns that wrap, with tightened row/column gaps. */
|
||||
/* Grid: five columns that wrap, with tightened row/column gaps. */
|
||||
.team-listing-wrapper.team-grid-listing {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
margin: 0 -16px -40px;
|
||||
}
|
||||
.team-listing-wrapper.team-grid-listing .team-item-wrapper {
|
||||
width: 33.3333%;
|
||||
width: 20%;
|
||||
padding: 0 16px;
|
||||
margin-bottom: 40px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
@media (max-width: 1020px) {
|
||||
@media (max-width: 1200px) {
|
||||
.team-listing-wrapper.team-grid-listing .team-item-wrapper { width: 33.3333%; }
|
||||
}
|
||||
@media (max-width: 800px) {
|
||||
.team-listing-wrapper.team-grid-listing .team-item-wrapper { width: 50%; }
|
||||
}
|
||||
@media (max-width: 660px) {
|
||||
@media (max-width: 480px) {
|
||||
.team-listing-wrapper.team-grid-listing .team-item-wrapper { width: 100%; }
|
||||
}
|
||||
|
||||
/* Card: photo on the LEFT, name/position on the RIGHT (side by side). */
|
||||
|
||||
/* Card: photo on top, name/position at the bottom (down to image). */
|
||||
.team-listing-wrapper.team-grid-listing .team-item {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: 22px;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 16px;
|
||||
width: 100%;
|
||||
}
|
||||
/* Compact portrait photo. Extra .team-item in the selector raises the
|
||||
specificity so it beats the cached vendor rule (width: 45.65%). */
|
||||
.team-listing-wrapper.team-grid-listing .team-item .team-item-media {
|
||||
flex-shrink: 0;
|
||||
width: 160px;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
}
|
||||
.team-listing-wrapper.team-grid-listing .team-item .post-media {
|
||||
@@ -113,7 +119,7 @@ export default function OurTeam() {
|
||||
object-fit: cover;
|
||||
}
|
||||
.team-listing-wrapper.team-grid-listing .team-item .team-item-content {
|
||||
flex: 1;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
}
|
||||
`}} />
|
||||
@@ -128,7 +134,7 @@ export default function OurTeam() {
|
||||
|
||||
<div style={{ alignSelf: "flex-start", width: "100%" }} className="elementor-element elementor-element-c46350e elementor-widget__width-initial elementor-widget elementor-widget-logico_heading" data-id="c46350e" data-element_type="widget" data-e-type="widget" data-widget_type="logico_heading.default">
|
||||
<div className="elementor-widget-container">
|
||||
<h3 className="logico-title" style={{ textAlign: "left" }}>Meet our the best crew</h3>
|
||||
<h3 className="logico-title" style={{ textAlign: "left" }}>Meet crew</h3>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -136,7 +142,7 @@ export default function OurTeam() {
|
||||
<div className="elementor-widget-container">
|
||||
<div className="logico-team-listing-widget">
|
||||
<div className="archive-listing">
|
||||
<div className="archive-listing-wrapper team-listing-wrapper team-grid-listing columns-3">
|
||||
<div className="archive-listing-wrapper team-listing-wrapper team-grid-listing columns-5">
|
||||
|
||||
{teamMembers.map((member, i) => (
|
||||
<div key={i} className="team-item-wrapper post-2866 team type-team status-publish has-post-thumbnail hentry">
|
||||
@@ -159,10 +165,7 @@ export default function OurTeam() {
|
||||
<div className="team-item-position" dangerouslySetInnerHTML={{ __html: member.position }}></div>
|
||||
<div className="team-item-socials">
|
||||
<ul className="team-socials wrapper-socials">
|
||||
<li><a href="https://www.facebook.com/" target="_blank" rel="noreferrer" className="fab fa-facebook-f"></a></li>
|
||||
<li><a href="https://x.com/" target="_blank" rel="noreferrer" className="fab fa-x-twitter"></a></li>
|
||||
<li><a href="https://www.linkedin.com/" target="_blank" rel="noreferrer" className="fab fa-linkedin-in"></a></li>
|
||||
<li><a href="https://www.youtube.com/" target="_blank" rel="noreferrer" className="fab fa-youtube"></a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -5,11 +5,11 @@ import React, { useState, useEffect } from "react";
|
||||
export default function SolutionsHero() {
|
||||
const [activeSlide, setActiveSlide] = useState(0);
|
||||
|
||||
// Auto-slide every 6 seconds
|
||||
// Auto-slide every 7 seconds — slower, more readable, professional pacing
|
||||
useEffect(() => {
|
||||
const interval = setInterval(() => {
|
||||
setActiveSlide((prev) => (prev === 0 ? 1 : 0));
|
||||
}, 6000);
|
||||
}, 7000);
|
||||
return () => clearInterval(interval);
|
||||
}, []);
|
||||
|
||||
@@ -77,11 +77,23 @@ export default function SolutionsHero() {
|
||||
|
||||
.elementor-element.elementor-element-6c7cbcb .text-content {
|
||||
text-align: center !important;
|
||||
max-width: 800px !important;
|
||||
max-width: 820px !important;
|
||||
margin: 0 auto !important;
|
||||
}
|
||||
|
||||
/* Larger, more readable hero subtitle on large/4K screens */
|
||||
.elementor-element.elementor-element-6c7cbcb .content-slider-item-text p {
|
||||
font-size: clamp(16px, 1.35vw, 23px) !important;
|
||||
line-height: 1.65 !important;
|
||||
}
|
||||
|
||||
@media (min-width: 1025px) {
|
||||
/* Match Home's hero frame so the floating navbar sits with the same
|
||||
breathing space. Home (.elementor-61) frames the hero card at 20px;
|
||||
this page falls through to the shared kit's 32px base. */
|
||||
.elementor-element.elementor-element-741f56c {
|
||||
padding: 20px !important;
|
||||
}
|
||||
.elementor-element.elementor-element-6c7cbcb .owl-carousel.owl-theme .content-item {
|
||||
height: 800px !important;
|
||||
min-height: 800px !important;
|
||||
|
||||
@@ -265,7 +265,7 @@ export default function WomenSection() {
|
||||
<div className="elementor-element elementor-element-90cc867 e-con-full e-flex cut-corner-no sticky-container-off e-con e-child" data-id="90cc867" data-element_type="container" data-e-type="container">
|
||||
<div className="elementor-element elementor-element-24c0280 elementor-widget__width-inherit elementor-widget elementor-widget-logico_heading" data-id="24c0280" data-element_type="widget" data-e-type="widget" data-widget_type="logico_heading.default">
|
||||
<div className="elementor-widget-container">
|
||||
<div className="logico-title">/ Success Stories /</div>
|
||||
<div className="logico-title">/ Women Empowerment /</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -116,7 +116,7 @@ const styles = `
|
||||
margin: 0 auto 0;
|
||||
}
|
||||
|
||||
/* Cancel the global "section { padding: 6rem 0 }" (custom-frontend.min.css): both
|
||||
/* Cancel the global "section { padding: 6rem 0 }" (consolidated into /public/css/site.css): both
|
||||
this wrapper and the nested .dm-opt are sections, so that 96px top+bottom stacked
|
||||
into large empty bands above / between the workflows. These are full-bleed pinned
|
||||
experiences whose cards butt together via their own insets — no section padding. */
|
||||
|
||||
@@ -118,7 +118,7 @@ const styles = `
|
||||
margin: 0 auto 0;
|
||||
}
|
||||
|
||||
/* Cancel the global "section { padding: 6rem 0 }" (custom-frontend.min.css): both
|
||||
/* Cancel the global "section { padding: 6rem 0 }" (consolidated into /public/css/site.css): both
|
||||
this wrapper and the nested .dm-lb are sections, so that 96px top+bottom stacked
|
||||
into large empty bands above / between the workflows. These are full-bleed pinned
|
||||
experiences whose cards butt together via their own insets — no section padding. */
|
||||
|
||||
@@ -118,7 +118,7 @@ const styles = `
|
||||
margin: 0 auto 0;
|
||||
}
|
||||
|
||||
/* Cancel the global "section { padding: 6rem 0 }" (custom-frontend.min.css): both
|
||||
/* Cancel the global "section { padding: 6rem 0 }" (consolidated into /public/css/site.css): both
|
||||
this wrapper and the nested .dm-st are sections, so that 96px top+bottom stacked
|
||||
into large empty bands above / between the workflows. These are full-bleed pinned
|
||||
experiences whose cards butt together via their own insets — no section padding. */
|
||||
|
||||
Reference in New Issue
Block a user