update how it works card update

This commit is contained in:
2026-06-09 17:42:42 +05:30
parent 0ef51540e9
commit 8c85a11698
22 changed files with 1631 additions and 1370 deletions

View File

@@ -7,7 +7,7 @@ import Navbar from './components/ui/Navbar'
import FirstMile from './components/sections/FirstMile'
import MidMile from './components/sections/MidMile'
import LastMile from './components/sections/LastMile'
import Analytics from './components/sections/Analytics'
import Promise from './components/sections/Promise'
import { useSceneStore } from './store/useSceneStore'
import './styles/experience.css'
@@ -145,8 +145,10 @@ export default function Experience3D() {
<div className="sections-overlay-container">
<FirstMile active={scrollProgress >= 0.02 && scrollProgress < 0.14} />
<MidMile active={scrollProgress >= 0.38 && scrollProgress < 0.50} />
<LastMile active={scrollProgress >= 0.80 && scrollProgress < 0.92} />
<Analytics active={scrollProgress >= 0.94} />
<LastMile active={scrollProgress >= 0.78 && scrollProgress < 0.875} />
{/* Final card: reveals as the journey closes (fills the slot the old
workflow timeline card used to occupy — no blank gap). */}
<Promise active={scrollProgress >= 0.90} />
</div>
</div>

View File

@@ -1,46 +0,0 @@
import React from 'react'
import RevealCard from '../ui/RevealCard'
export default function Analytics({ active }) {
return (
<RevealCard active={active} id="analytics-section">
<div className="section-badge">Workflow</div>
<h2 className="section-title">Doormile Insights</h2>
<h3 className="section-subtitle">3-Mile Logistics Ecosystem</h3>
<div className="workflow-steps">
<div className="workflow-step">
<div className="step-number-container">
<span className="step-number">01</span>
<div className="step-line"></div>
</div>
<div className="step-content">
<h4 className="step-title">First Mile</h4>
<p className="step-description">Incoming shipments are securely loaded, checked, and consolidated at initial fulfillment hubs.</p>
</div>
</div>
<div className="workflow-step">
<div className="step-number-container">
<span className="step-number">02</span>
<div className="step-line"></div>
</div>
<div className="step-content">
<h4 className="step-title">Mid Mile</h4>
<p className="step-description">Consolidated goods travel between primary distribution nodes via optimized express transit corridors.</p>
</div>
</div>
<div className="workflow-step">
<div className="step-number-container">
<span className="step-number">03</span>
</div>
<div className="step-content">
<h4 className="step-title">Last Mile</h4>
<p className="step-description">Local delivery units organize doorstep routes to transport packages to final customers.</p>
</div>
</div>
</div>
</RevealCard>
)
}

View File

@@ -9,9 +9,10 @@ export default function LastMile({ active }) {
const lenis = useSceneStore((state) => state.lenis)
const handleClose = () => {
// Smoothly scroll to 97% progress, which is inside the Analytics Dashboard section.
// Smoothly scroll to 92% progress, which lands on the analytics-dashboard
// view where the closing promise card is revealed.
// Relative to the experience spacer (the section sits below the page hero).
lenis?.scrollTo(progressToScrollY(0.97), { duration: 1.5 })
lenis?.scrollTo(progressToScrollY(0.92), { duration: 1.5 })
}
return (
@@ -22,12 +23,19 @@ export default function LastMile({ active }) {
<p className="section-description">{config.description}</p>
<div className="section-metrics">
<div className="metric-item">
<span className="metric-value">12.5 min</span>
<span className="metric-label">Avg. Delivery window</span>
<span className="metric-value">99.4%</span>
<span className="metric-label">On-Time Delivery</span>
</div>
<div className="metric-item">
<span className="metric-value">99.4%</span>
<span className="metric-label">On-Time Rate</span>
<span className="metric-value">12.5 min</span>
<span className="metric-label">Avg. Doorstep Time</span>
</div>
</div>
<div className="section-supporting">
<span className="supporting-dot"></span>
<div className="supporting-text">
<span className="supporting-value">Real-Time visibility</span>
<span className="supporting-label">Live GPS · Active now</span>
</div>
</div>
<button className="section-close-btn" onClick={handleClose}>

View File

@@ -20,14 +20,38 @@ export default function MidMile({ active }) {
<h2 className="section-title">{config.title}</h2>
<h3 className="section-subtitle">{config.subtitle}</h3>
<p className="section-description">{config.description}</p>
<div className="section-metrics">
<div className="metric-item">
<span className="metric-value">4.2 hr</span>
<span className="metric-label">Avg. Transit Time</span>
{/* Enterprise information strip — icon + title + description rows with
subtle hairline separators (no KPI cards / oversized statistics).
Keeps the `section-metrics` class so the RevealCard entrance stagger
still treats it as a single animated block. */}
<div className="section-metrics mm-info-strip">
<div className="mm-info-row">
<span className="mm-info-icon" aria-hidden="true">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<rect x="1" y="3" width="15" height="13"></rect>
<polygon points="16 8 20 8 23 11 23 16 16 16 16 8"></polygon>
<circle cx="5.5" cy="18.5" r="2.5"></circle>
<circle cx="18.5" cy="18.5" r="2.5"></circle>
</svg>
</span>
<div className="mm-info-content">
<h4 className="mm-info-title">Vehicles In Transit</h4>
<p className="mm-info-text">A live view of active vehicles moving shipments between regional distribution hubs.</p>
</div>
</div>
<div className="metric-item">
<span className="metric-value">220 kw</span>
<span className="metric-label">Solar Output (Self-powered)</span>
<div className="mm-info-row">
<span className="mm-info-icon" aria-hidden="true">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<line x1="16.5" y1="9.4" x2="7.5" y2="4.21"></line>
<path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z"></path>
<polyline points="3.27 6.96 12 12.01 20.73 6.96"></polyline>
<line x1="12" y1="22.08" x2="12" y2="12"></line>
</svg>
</span>
<div className="mm-info-content">
<h4 className="mm-info-title">Packages In Transit</h4>
<p className="mm-info-text">Real-time visibility into parcels currently moving through the mid-mile network.</p>
</div>
</div>
</div>
<button className="section-close-btn" onClick={handleClose}>

View File

@@ -0,0 +1,29 @@
import React from 'react'
import RevealCard from '../ui/RevealCard'
/**
* Promise — Final card
* ---------------------------------------------------------------------------
* Closing-statement card and the final beat of the experience, revealed as the
* journey closes (right after Stage 03 — Last Mile). It's a regular centred
* in-experience overlay card (same chrome as the others) — NOT a separate
* scroll section — so the camera, scene, and scroll timing are untouched.
*/
export default function Promise({ active }) {
return (
<RevealCard active={active} id="promise-section">
<div className="section-badge">The Doormile Promise</div>
<h2 className="section-title promise-title">
One Connected System.
<br />
One Promise Kept.
</h2>
<span className="promise-divider" aria-hidden></span>
<p className="section-description promise-desc">
Stop managing three separate logistics services. Doormile unifies first,
mid and last mile into a single intelligent delivery system powered by
MileTruth&trade; AI.
</p>
</RevealCard>
)
}

View File

@@ -7,8 +7,10 @@ export default function Navbar() {
const lenis = useSceneStore((state) => state.lenis)
const handleNavClick = (index) => {
// Map index (0, 1, 2, 3) to the stable parking progress percentages (0.0, 0.38, 0.76, 0.97).
const sectionFractions = [0, 0.38, 0.76, 0.97]
// Map index (0, 1, 2, 3) to the stable parking progress percentages.
// The last lands on the analytics-dashboard view, where the closing promise
// card is revealed as the user finishes the final stretch of scroll.
const sectionFractions = [0, 0.38, 0.76, 0.92]
const targetProgress = sectionFractions[index]
// Relative to the experience spacer (the section sits below the page hero).
lenis?.scrollTo(progressToScrollY(targetProgress), { duration: 1.5 })

View File

@@ -10,10 +10,12 @@ export default function RevealCard({ children, active, id, className = "" }) {
// Find all target children inside the card to create a staggered entrance
const animTargets = card.querySelectorAll(
'.section-badge, .section-title, .section-subtitle, .section-description, .section-metrics, .section-close-btn, .workflow-step'
'.section-badge, .section-title, .section-subtitle, .section-description, .section-metrics, .section-supporting, .section-close-btn'
)
const isAnalytics = id === 'analytics-section'
// The promise card (the final card) is centred, so its reveal/exit tweens
// must preserve the -50%/-50% centring offset.
const isCentered = id === 'promise-section'
if (active) {
// Clean up any ongoing animations first
@@ -21,8 +23,8 @@ export default function RevealCard({ children, active, id, className = "" }) {
// Animate card container in
gsap.to(card, {
xPercent: isAnalytics ? -50 : 0,
yPercent: isAnalytics ? -50 : 0,
xPercent: isCentered ? -50 : 0,
yPercent: isCentered ? -50 : 0,
y: 0,
scale: 1,
opacity: 1,
@@ -52,9 +54,9 @@ export default function RevealCard({ children, active, id, className = "" }) {
// Animate card container out
gsap.to(card, {
xPercent: isAnalytics ? -50 : 0,
yPercent: isAnalytics ? -50 : 0,
y: isAnalytics ? 18 : 20,
xPercent: isCentered ? -50 : 0,
yPercent: isCentered ? -50 : 0,
y: isCentered ? 18 : 20,
scale: 0.96,
opacity: 0,
duration: 0.5,
@@ -78,8 +80,8 @@ export default function RevealCard({ children, active, id, className = "" }) {
className={`section-panel ${active ? 'active' : ''} ${className}`}
style={{
opacity: 0,
transform: id === 'analytics-section'
? 'translate(-50%, -50%) translateY(18px) scale(0.96)'
transform: id === 'promise-section'
? 'translate(-50%, -50%) translateY(18px) scale(0.96)'
: 'translateY(20px) scale(0.96)',
}}
>

View File

@@ -19,7 +19,7 @@ export const sections = [
id: 'last-mile',
title: 'Last Mile Delivery',
subtitle: 'Doorstep Courier Services',
description: 'Local delivery units take over, planning optimal paths to transport packages directly to customer doorsteps.',
description: 'Local courier fleets take over for the final leg — MileTruth™ AI sequences the fastest doorstep routes and keeps every package tracked through to a confirmed delivery.',
progressStart: 0.5,
progressEnd: 0.75,
},

View File

@@ -30,6 +30,17 @@
--dm-card-shadow: 0 24px 60px -28px rgba(15, 23, 42, 0.45);
--dm-font-head: var(--font-space-grotesk), var(--font-manrope), system-ui, sans-serif;
--dm-font-body: var(--font-manrope), system-ui, -apple-system, sans-serif;
/* Container spacing — matches the site's full-width section frame
(.custom-standard-hero-container used by Contact/About/CTA: full width,
no max-width cap, 20px gutters, 25px radius). The stage spans ~98% of the
viewport with standard gutters rather than sitting in a narrow centred box.
Values scale down responsively. */
--hiw-max-width: none;
--hiw-gutter: 20px;
--hiw-gap-top: 20px;
--hiw-gap-bottom: 20px;
--hiw-radius: 25px;
}
/* ---- Section shell + self-managed fixed pin ---- */
@@ -44,26 +55,38 @@
-moz-osx-font-smoothing: grayscale;
}
/* The stage is inset to sit inside the site's content container: a centred
max-width box with left/right gutters and equal top/bottom spacing. The SAME
inset is applied in every pin state (absolute-top → fixed → absolute-bottom)
so the stage never jumps at the pin hand-offs. Scroll progress and stage
maths are driven by the separate 900vh spacer (#scroll-trigger-trigger), so
insetting the stage doesn't touch them. Horizontal centring uses
left/right:0 + margin:auto (not transform) so it composes with the existing
translateZ(0) GPU layer. The 3D scene is not scaled — the canvas simply fills
the smaller framed box and CameraRig already adapts FOV to the aspect. */
.dm-hiw-3d-stage {
position: absolute;
top: 0;
top: var(--hiw-gap-top);
left: 0;
width: 100%;
height: 100vh;
right: 0;
margin-left: auto;
margin-right: auto;
width: calc(100% - 2 * var(--hiw-gutter));
max-width: var(--hiw-max-width);
height: calc(100vh - var(--hiw-gap-top) - var(--hiw-gap-bottom));
overflow: hidden;
border-radius: var(--hiw-radius);
will-change: transform;
transform: translateZ(0);
backface-visibility: hidden;
}
.dm-hiw-3d.is-pinned .dm-hiw-3d-stage {
position: fixed;
top: 0;
left: 0;
}
.dm-hiw-3d.is-after .dm-hiw-3d-stage {
position: absolute;
top: auto;
bottom: 0;
bottom: var(--hiw-gap-bottom);
}
.dm-hiw-3d .canvas-wrapper {
@@ -194,27 +217,273 @@
.dm-hiw-3d #last-mile-section {
left: clamp(24px, 5vw, 72px);
}
/* ===========================================================================
Stage 02 — Mid Mile Hub: premium enterprise dashboard card.
Scoped entirely to #mid-mile-section so the other three stage cards keep the
unified chrome. UI only — no transform/animation/scene/scroll changes (the
GSAP reveal still targets the same .section-* classes, which are preserved).
Sizes use clamp() so they scale down gracefully without fighting the shared
responsive rules below.
=========================================================================== */
.dm-hiw-3d #mid-mile-section {
right: clamp(24px, 5vw, 72px);
/* Only marginally larger than the sibling side panels (Stage 01/03 are
min(404px, 37vw)) — ~13% wider to hold the extra info, not dominant. */
width: min(456px, 41vw);
max-height: calc(100vh - 120px);
padding: clamp(22px, 2.4vw, 30px) clamp(24px, 2.8vw, 34px) clamp(20px, 2.2vw, 26px);
/* Clean glassmorphism white surface with subtle transparency. */
background: rgba(255, 255, 255, 0.9);
border-top: 3px solid var(--dm-red); /* thin red accent along the top edge */
box-shadow: 0 32px 72px -30px rgba(15, 23, 42, 0.5);
}
/* Final ecosystem panel — same card system, centred, a touch wider for its
timeline, and reduced from the old 500px so it no longer blocks the scene. */
.dm-hiw-3d #analytics-section {
/* ---- Header: stronger hierarchy ---- */
.dm-hiw-3d #mid-mile-section .section-badge {
font-size: 12px !important;
letter-spacing: 0.22em !important;
margin: 0 0 10px !important;
}
.dm-hiw-3d #mid-mile-section .section-title {
font-size: clamp(28px, 2.5vw, 40px) !important;
font-weight: 700 !important;
line-height: 1.07 !important;
letter-spacing: -0.025em !important;
margin: 0 0 7px !important;
}
.dm-hiw-3d #mid-mile-section .section-subtitle {
font-size: clamp(14.5px, 1.2vw, 16px) !important;
font-weight: 600 !important;
color: var(--dm-body) !important;
margin: 0 0 13px !important;
}
/* ---- Description: larger, more readable, contained measure ---- */
.dm-hiw-3d #mid-mile-section .section-description {
font-size: clamp(14.5px, 1.15vw, 16px) !important;
line-height: 1.72 !important;
max-width: 44ch !important;
margin: 0 0 6px !important;
}
/* ---- Stage 02 information strip ----------------------------------------
Replaces the KPI/metric look with a clean enterprise info panel: a
full-width column of icon + title + description rows divided by subtle
hairlines. Scoped to #mid-mile-section so the shared .section-metrics /
.metric-* styling on the other cards is untouched. The ID specificity also
overrides the base `.section-metrics` flex-row + border styling that still
rides along on the retained class. */
.dm-hiw-3d #mid-mile-section .mm-info-strip {
display: flex;
flex-direction: column;
gap: 0;
width: 100%; /* full-width content row */
border-top: 1px solid rgba(15, 23, 42, 0.08);
padding-top: 4px;
}
.dm-hiw-3d #mid-mile-section .mm-info-row {
display: flex;
align-items: flex-start;
gap: 16px;
padding: 11px 0;
}
/* Subtle separator between rows only (not above the first / below the last). */
.dm-hiw-3d #mid-mile-section .mm-info-row + .mm-info-row {
border-top: 1px solid rgba(15, 23, 42, 0.07);
}
.dm-hiw-3d #mid-mile-section .mm-info-icon {
flex-shrink: 0;
width: 40px;
height: 40px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 10px;
background: var(--dm-red-soft);
color: var(--dm-red);
}
.dm-hiw-3d #mid-mile-section .mm-info-icon svg {
width: 21px;
height: 21px;
}
.dm-hiw-3d #mid-mile-section .mm-info-content {
flex: 1;
min-width: 0;
padding-top: 1px;
}
.dm-hiw-3d #mid-mile-section .mm-info-title {
font-family: var(--dm-font-head) !important;
font-size: 15px !important;
font-weight: 700 !important;
line-height: 1.3 !important;
letter-spacing: -0.01em !important;
color: var(--dm-ink) !important;
margin: 0 0 3px !important;
}
.dm-hiw-3d #mid-mile-section .mm-info-text {
font-family: var(--dm-font-body) !important;
font-size: 13.5px !important;
font-weight: 400 !important;
line-height: 1.58 !important;
color: var(--dm-body) !important;
margin: 0 !important;
}
/* ---- Metrics: a simple horizontal row sitting DIRECTLY on the card surface —
no nested tiles / boxed containers. A thin divider rule above separates it
from the description; within each metric the icon sits to the left of the
value, with the label directly beneath it. Compact + uncluttered. ---- */
.dm-hiw-3d #mid-mile-section .section-metrics {
/* The strip is a vertical column; rows space themselves via their own
padding, so no large flex gap (this was a major source of extra height). */
gap: 0;
border-top: 1px solid rgba(15, 23, 42, 0.1);
margin-top: 14px;
padding-top: 12px;
}
.dm-hiw-3d #mid-mile-section .metric-item {
display: grid;
grid-template-columns: auto 1fr;
grid-template-rows: auto auto;
column-gap: 12px;
row-gap: 3px;
align-items: center;
padding: 0;
background: none;
border: none;
border-radius: 0;
}
/* Compact icon chip, vertically centred against the value/label stack. */
.dm-hiw-3d #mid-mile-section .metric-icon {
grid-row: 1 / span 2;
display: inline-flex;
align-items: center;
justify-content: center;
width: clamp(36px, 3vw, 42px);
height: clamp(36px, 3vw, 42px);
margin: 0;
border-radius: 11px;
background: var(--dm-red-soft);
color: var(--dm-red);
}
.dm-hiw-3d #mid-mile-section .metric-icon svg {
width: 56%;
height: 56%;
}
.dm-hiw-3d #mid-mile-section .metric-value {
grid-column: 2;
align-self: end;
font-size: clamp(26px, 2.4vw, 34px) !important;
line-height: 1 !important;
letter-spacing: -0.02em !important;
margin: 0 !important;
}
.dm-hiw-3d #mid-mile-section .metric-label {
grid-column: 2;
align-self: start;
font-size: 10.5px !important;
letter-spacing: 0.1em !important;
margin: 0 !important;
}
/* ---- CTA: larger red pill with subtle shadow + hover lift ---- */
.dm-hiw-3d #mid-mile-section .section-close-btn {
margin-top: 16px;
font-size: clamp(14px, 1vw, 15px);
font-weight: 600;
padding: clamp(12px, 1vw, 15px) clamp(24px, 2vw, 30px);
box-shadow: 0 16px 30px -12px rgba(192, 18, 39, 0.6);
}
.dm-hiw-3d #mid-mile-section .section-close-btn svg {
width: 16px;
height: 16px;
}
/* Tablet/mobile: relax the contained measure and tighten the KPI tiles so the
larger desktop styling above never overflows the bottom-docked card. */
@media (max-width: 1024px) {
.dm-hiw-3d #mid-mile-section .section-description {
max-width: none !important;
}
.dm-hiw-3d #mid-mile-section .section-metrics {
margin-top: 12px;
padding-top: 10px;
gap: 0;
}
.dm-hiw-3d #mid-mile-section .section-close-btn {
margin-top: 14px;
}
}
/* Closing promise card — a centred card occupying the final slot. */
.dm-hiw-3d #promise-section {
left: 50%;
right: auto;
top: 50%;
transform: translate(-50%, -50%) translateY(18px) scale(0.97);
width: min(400px, 90vw);
max-height: calc(100vh - 140px);
width: min(1060px, 92vw);
max-height: calc(100vh - 110px);
}
/* Closing-statement card — the final key message of the journey, scaled to the
authority of the page hero. The card spans most of the viewport width (small
left/right margins) so the headline can run wide; padding is kept lean so the
headline — not whitespace — dominates. */
.dm-hiw-3d #promise-section {
width: min(1060px, 92vw) !important; /* wide: uses most of the viewport */
padding: 36px 56px !important;
text-align: center;
display: flex;
flex-direction: column;
justify-content: center; /* centre the group vertically */
align-items: center; /* centre the group horizontally */
}
/* Kicker/subtitle — bumped ~+25% to sit in proportion with the larger headline. */
.dm-hiw-3d #promise-section .section-badge {
display: block !important;
font-size: 15px !important;
letter-spacing: 0.2em !important;
margin: 0 0 18px !important;
}
/* Dominant headline — matches the hero scale: up to 80px, uppercase, heavy
weight, tight hero leading + word-spacing. This is the visual anchor of the
card and the strongest type on the screen. */
/* Scoped under #promise-section (ID specificity) so it reliably overrides the
shared `.section-title` base rule, which is declared later in the file. */
.dm-hiw-3d #promise-section .promise-title {
font-size: clamp(40px, 6vw, 80px) !important;
font-weight: 800 !important;
line-height: 1.1 !important;
letter-spacing: -0.03em !important;
word-spacing: -0.03em !important;
text-transform: uppercase !important;
margin: 0 !important;
}
/* Real, flex-centred divider element — exactly under the headline centre. */
.dm-hiw-3d .promise-divider {
display: block;
width: 76px;
height: 3px;
border-radius: 999px;
background: var(--dm-red);
margin: 24px auto;
}
/* Supporting paragraph — hero body scale (20px) on a wide measure so it reads
as a balanced two-to-three line statement instead of wrapping too early.
Scoped under #promise-section so it overrides the later `.section-description`
base rule. */
.dm-hiw-3d #promise-section .promise-desc {
margin: 0 auto !important;
max-width: 760px !important;
font-size: 20px !important;
line-height: 1.7 !important;
}
/* ---- Unified card — all four stages share this exact chrome ---- */
.dm-hiw-3d .section-panel {
position: absolute;
width: min(340px, 31vw);
max-height: calc(100vh - 168px); /* never taller than the viewport */
width: min(404px, 37vw);
max-height: calc(100vh - 140px); /* never taller than the viewport */
overflow-y: auto;
padding: 24px 26px 26px;
padding: 34px 36px 34px;
background: var(--dm-card-bg);
backdrop-filter: blur(0px);
-webkit-backdrop-filter: blur(0px);
@@ -247,53 +516,53 @@
font-size: 10.5px !important;
text-transform: uppercase !important;
font-weight: 700 !important;
letter-spacing: 0.14em !important;
letter-spacing: 0.16em !important;
color: var(--dm-red) !important;
margin: 0 0 10px !important;
margin: 0 0 12px !important;
}
.dm-hiw-3d .section-title {
font-family: var(--dm-font-head) !important;
font-size: clamp(18px, 1.45vw, 22px) !important;
font-size: clamp(19px, 1.55vw, 24px) !important;
font-weight: 700 !important;
line-height: 1.15 !important;
letter-spacing: -0.015em !important;
line-height: 1.18 !important;
letter-spacing: -0.018em !important;
text-transform: none !important;
color: var(--dm-ink) !important;
margin: 0 0 4px !important;
margin: 0 0 6px !important;
}
.dm-hiw-3d .section-subtitle {
font-family: var(--dm-font-body) !important;
font-size: 13px !important;
font-weight: 500 !important;
line-height: 1.35 !important;
letter-spacing: 0 !important;
line-height: 1.4 !important;
letter-spacing: 0.005em !important;
text-transform: none !important;
color: var(--dm-muted) !important;
margin: 0 0 14px !important;
margin: 0 0 16px !important;
}
.dm-hiw-3d .section-description {
font-family: var(--dm-font-body) !important;
font-size: 13px !important;
font-size: 13.5px !important;
font-weight: 400 !important;
line-height: 1.55 !important;
line-height: 1.62 !important;
color: var(--dm-body) !important;
margin: 0 0 18px !important;
margin: 0 0 20px !important;
}
.dm-hiw-3d .section-metrics {
display: flex;
gap: 18px;
gap: 20px;
border-top: 1px solid rgba(15, 23, 42, 0.08);
padding-top: 16px;
padding-top: 18px;
}
.dm-hiw-3d .metric-item {
display: flex;
flex-direction: column;
gap: 3px;
gap: 4px;
flex: 1;
}
.dm-hiw-3d .metric-value {
font-family: var(--dm-font-head) !important;
font-size: 18px !important;
font-size: 19px !important;
font-weight: 700 !important;
line-height: 1.1 !important;
letter-spacing: -0.01em !important;
@@ -304,11 +573,58 @@
font-size: 9.5px !important;
font-weight: 600 !important;
text-transform: uppercase !important;
letter-spacing: 0.07em !important;
letter-spacing: 0.08em !important;
color: var(--dm-muted) !important;
}
.dm-hiw-3d .font-green .metric-value { color: #1f9d57 !important; }
/* Supporting metric (e.g. Last Mile real-time driver tracking) — a full-width
live-status row that sits beneath the two headline metrics. */
.dm-hiw-3d .section-supporting {
display: flex;
align-items: center;
gap: 11px;
margin-top: 14px;
padding: 11px 14px;
background: rgba(31, 157, 87, 0.07);
border: 1px solid rgba(31, 157, 87, 0.18);
border-radius: 12px;
}
.dm-hiw-3d .supporting-dot {
width: 9px;
height: 9px;
border-radius: 50%;
background-color: #1f9d57;
flex-shrink: 0;
box-shadow: 0 0 0 0 rgba(31, 157, 87, 0.5);
animation: dmHiwPulseDot 2s cubic-bezier(0.16, 1, 0.3, 1) infinite;
}
.dm-hiw-3d .supporting-text {
display: flex;
flex-direction: column;
gap: 2px;
}
.dm-hiw-3d .supporting-value {
font-family: var(--dm-font-head) !important;
font-size: 12.5px !important;
font-weight: 700 !important;
line-height: 1.15 !important;
letter-spacing: -0.005em !important;
color: var(--dm-ink) !important;
}
.dm-hiw-3d .supporting-label {
font-family: var(--dm-font-body) !important;
font-size: 10px !important;
font-weight: 600 !important;
letter-spacing: 0.04em !important;
color: #1f9d57 !important;
}
@keyframes dmHiwPulseDot {
0% { box-shadow: 0 0 0 0 rgba(31, 157, 87, 0.45); }
70% { box-shadow: 0 0 0 7px rgba(31, 157, 87, 0); }
100% { box-shadow: 0 0 0 0 rgba(31, 157, 87, 0); }
}
/* ---- Animations (keyframes left global; uniquely named) ---- */
@keyframes dmHiwScrollWheel {
0% { top: 6px; opacity: 1; height: 6px; }
@@ -324,62 +640,15 @@
50% { transform: translateX(8px); }
}
/* ---- Final-panel timeline (inside #analytics-section) ---- */
.dm-hiw-3d .workflow-steps {
display: flex;
flex-direction: column;
gap: 4px;
margin-top: 16px;
}
.dm-hiw-3d .workflow-step { display: flex; gap: 14px; }
.dm-hiw-3d .step-number-container {
display: flex;
flex-direction: column;
align-items: center;
width: 24px;
}
.dm-hiw-3d .step-number {
font-family: var(--dm-font-head);
font-size: 11px;
font-weight: 700;
color: var(--dm-red);
background: var(--dm-red-soft);
width: 24px;
height: 24px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
border: 1px solid rgba(192, 18, 39, 0.2);
flex-shrink: 0;
}
.dm-hiw-3d .step-line {
width: 2px;
flex-grow: 1;
background: linear-gradient(to bottom, var(--dm-red) 0%, rgba(192, 18, 39, 0.12) 100%);
margin: 5px 0;
min-height: 16px;
border-radius: 2px;
}
.dm-hiw-3d .step-content { flex-grow: 1; padding-bottom: 14px; }
.dm-hiw-3d .step-title {
font-family: var(--dm-font-head) !important;
font-size: 14px !important;
font-weight: 700 !important;
line-height: 1.2 !important;
color: var(--dm-ink) !important;
margin: 1px 0 3px !important;
}
.dm-hiw-3d .step-description {
font-family: var(--dm-font-body) !important;
font-size: 12px !important;
line-height: 1.5 !important;
color: var(--dm-body) !important;
margin: 0 !important;
}
/* ---- Responsive ---- */
@media (max-width: 1024px) {
/* Moderate gutters on tablet (radius matches the site's tablet section card). */
.dm-hiw-3d {
--hiw-gutter: 16px;
--hiw-gap-top: 16px;
--hiw-gap-bottom: 16px;
--hiw-radius: 22px;
}
.dm-hiw-3d .sections-overlay-container {
padding-left: 0;
padding-right: 0;
@@ -387,28 +656,45 @@
padding-bottom: 50px;
}
.dm-hiw-3d .section-panel {
padding: 20px 22px 22px;
padding: 26px 28px 28px;
border-radius: 16px;
}
/* Tablet/mobile: cards bottom-centred so the truck/scene stays visible above. */
.dm-hiw-3d #first-mile-section,
.dm-hiw-3d #mid-mile-section,
.dm-hiw-3d #last-mile-section,
.dm-hiw-3d #analytics-section {
.dm-hiw-3d #promise-section {
left: 50% !important;
right: auto !important;
top: auto !important;
bottom: 64px !important;
transform: translateX(-50%) translateY(18px) scale(0.97) !important;
width: min(380px, calc(100vw - 40px)) !important;
max-height: calc(100vh - 200px) !important;
width: min(460px, calc(100vw - 32px)) !important;
max-height: calc(100vh - 180px) !important;
}
.dm-hiw-3d #first-mile-section.active,
.dm-hiw-3d #mid-mile-section.active,
.dm-hiw-3d #last-mile-section.active,
.dm-hiw-3d #analytics-section.active {
.dm-hiw-3d #promise-section.active {
transform: translateX(-50%) translateY(0) scale(1) !important;
}
/* Tablet: keep the promise card wider than the stage cards so the larger
headline still runs wide and balanced. */
.dm-hiw-3d #promise-section {
width: min(760px, calc(100vw - 40px)) !important;
padding: 30px 40px !important;
}
.dm-hiw-3d #promise-section .section-badge {
font-size: 14px !important;
}
.dm-hiw-3d #promise-section .promise-title {
font-size: clamp(34px, 5.4vw, 54px) !important;
line-height: 1.08 !important;
}
.dm-hiw-3d #promise-section .promise-desc {
font-size: 18px !important;
max-width: 640px !important;
}
.dm-hiw-3d .side-navigation {
bottom: 12px;
top: auto;
@@ -430,10 +716,17 @@
}
@media (max-width: 400px) {
/* Slimmest gutters on phones — matches the hero's mobile frame. */
.dm-hiw-3d {
--hiw-gutter: 12px;
--hiw-gap-top: 12px;
--hiw-gap-bottom: 12px;
--hiw-radius: 16px;
}
.dm-hiw-3d .section-panel,
.dm-hiw-3d #analytics-section {
padding: 16px 18px 18px !important;
width: min(340px, calc(100vw - 28px)) !important;
.dm-hiw-3d #promise-section {
padding: 20px 20px 20px !important;
width: min(360px, calc(100vw - 24px)) !important;
bottom: 56px !important;
}
.dm-hiw-3d .section-badge {
@@ -441,7 +734,18 @@
margin-bottom: 6px !important;
}
.dm-hiw-3d .section-title {
font-size: 18px !important;
font-size: 19px !important;
}
.dm-hiw-3d #promise-section .section-badge {
font-size: 12.5px !important;
}
.dm-hiw-3d #promise-section .promise-title {
font-size: clamp(28px, 8.5vw, 34px) !important;
line-height: 1.08 !important;
}
.dm-hiw-3d #promise-section .promise-desc {
font-size: 16px !important;
max-width: 100% !important;
}
.dm-hiw-3d .section-subtitle {
font-size: 12.5px !important;
@@ -458,8 +762,17 @@
}
.dm-hiw-3d .metric-value { font-size: 16px !important; }
.dm-hiw-3d .metric-label { font-size: 9px !important; }
.dm-hiw-3d .step-title { font-size: 13px !important; }
.dm-hiw-3d .step-description { font-size: 11.5px !important; }
/* Stage 02 info strip stays a tidy hairline-divided column on small screens
(overrides the shared .section-metrics !important gap/padding above). */
.dm-hiw-3d #mid-mile-section .mm-info-strip {
gap: 0 !important;
padding-top: 2px !important;
}
.dm-hiw-3d #mid-mile-section .mm-info-row { padding: 13px 0; gap: 13px; }
.dm-hiw-3d #mid-mile-section .mm-info-icon { width: 36px; height: 36px; }
.dm-hiw-3d #mid-mile-section .mm-info-icon svg { width: 19px; height: 19px; }
.dm-hiw-3d #mid-mile-section .mm-info-title { font-size: 14px !important; }
.dm-hiw-3d #mid-mile-section .mm-info-text { font-size: 12.5px !important; }
.dm-hiw-3d .side-navigation {
bottom: 8px !important;
gap: 12px !important;
@@ -469,17 +782,17 @@
.dm-hiw-3d #first-mile-section,
.dm-hiw-3d #mid-mile-section,
.dm-hiw-3d #last-mile-section,
.dm-hiw-3d #analytics-section {
.dm-hiw-3d #promise-section {
left: 50% !important;
right: auto !important;
bottom: 56px !important;
width: min(340px, calc(100vw - 28px)) !important;
width: min(360px, calc(100vw - 24px)) !important;
transform: translateX(-50%) translateY(18px) scale(0.97) !important;
}
.dm-hiw-3d #first-mile-section.active,
.dm-hiw-3d #mid-mile-section.active,
.dm-hiw-3d #last-mile-section.active,
.dm-hiw-3d #analytics-section.active {
.dm-hiw-3d #promise-section.active {
transform: translateX(-50%) translateY(0) scale(1) !important;
}
}