fix workflow section

This commit is contained in:
2026-07-13 15:10:13 +05:30
parent 333460525a
commit 7587c622c3
7 changed files with 270 additions and 20 deletions

Binary file not shown.

View File

@@ -2,6 +2,7 @@ import React from "react";
import MileTruthHero from "../../components/sections/MileTruthHero"; import MileTruthHero from "../../components/sections/MileTruthHero";
import Workflow1 from "../../components/sections/Workflow1"; import Workflow1 from "../../components/sections/Workflow1";
import Workflow2 from "../../components/sections/Workflow2"; import Workflow2 from "../../components/sections/Workflow2";
import Workflow4 from "../../components/sections/Workflow4";
import Workflow3Lazy from "../../components/sections/Workflow3Lazy"; import Workflow3Lazy from "../../components/sections/Workflow3Lazy";
export const metadata = { export const metadata = {
@@ -18,6 +19,7 @@ export default function MileTruthPage() {
<MileTruthHero /> <MileTruthHero />
<Workflow1 /> <Workflow1 />
<Workflow2 /> <Workflow2 />
<Workflow4 />
<Workflow3Lazy /> <Workflow3Lazy />
</div> </div>
</div> </div>

View File

@@ -42,6 +42,9 @@ export interface EVStat {
decimals?: number; decimals?: number;
suffix: string; suffix: string;
label: string; label: string;
/** Optional static text override — when set, renders this text instead of
* an animated CountUp (for non-numeric KPI concepts, e.g. "QUBO"). */
text?: string;
} }
/** Accent theming for the dashboard column so it matches the scene on the left /** Accent theming for the dashboard column so it matches the scene on the left
@@ -83,10 +86,19 @@ interface EVSectionProps {
* static homepage feature list. The bottom stat bar is dropped in this mode * static homepage feature list. The bottom stat bar is dropped in this mode
* to avoid repeating the metrics. */ * to avoid repeating the metrics. */
metrics?: EVStat[]; metrics?: EVStat[];
/** Optional distinct copy for the bottom `.evnd__bar` strip in dashboard
* mode. Defaults to reusing `metrics` (WF1/WF2 behaviour) when omitted. */
barStats?: EVStat[];
/** Heading above the dashboard, e.g. "PERFORMANCE INSIGHT". */ /** Heading above the dashboard, e.g. "PERFORMANCE INSIGHT". */
cardsHeading?: string; cardsHeading?: string;
/** Accent theme for the dashboard column (defaults to the section red). */ /** Accent theme for the dashboard column (defaults to the section red). */
cardsTheme?: EVCardsTheme; cardsTheme?: EVCardsTheme;
/** Dashboard system label, top-right of the header row. Defaults to "AI ENGINE". */
sysLabel?: string;
/** Extra class appended to `.evnd__imgwrap`, for workflow-specific media
* sizing overrides (e.g. video object-fit) defined in the caller's own
* scoped <style> tag rather than here. */
mediaClassName?: string;
} }
/* ---- Default content = original homepage EV Logistics section ---- */ /* ---- Default content = original homepage EV Logistics section ---- */
@@ -260,11 +272,13 @@ function DashboardPanel({
features, features,
heading, heading,
theme, theme,
sysLabel = "AI ENGINE",
}: { }: {
metrics: EVStat[]; metrics: EVStat[];
features: EVFeature[]; features: EVFeature[];
heading?: string; heading?: string;
theme?: EVCardsTheme; theme?: EVCardsTheme;
sysLabel?: string;
}) { }) {
const themeVars = theme const themeVars = theme
? ({ ? ({
@@ -287,7 +301,7 @@ function DashboardPanel({
<span className="evnd__dash-livedot" /> <span className="evnd__dash-livedot" />
{heading} {heading}
</span> </span>
<span className="evnd__dash-sys">AI ENGINE</span> <span className="evnd__dash-sys">{sysLabel}</span>
</div> </div>
)} )}
@@ -295,12 +309,16 @@ function DashboardPanel({
<div className="evnd__dash-kpis"> <div className="evnd__dash-kpis">
{metrics.map((m) => ( {metrics.map((m) => (
<div className="evnd__kpi" key={m.label}> <div className="evnd__kpi" key={m.label}>
<CountUp {m.text ? (
value={m.value} <b className="evnd__kpi-val evnd__kpi-val--text">{m.text}</b>
decimals={m.decimals} ) : (
suffix={m.suffix} <CountUp
className="evnd__kpi-val" value={m.value}
/> decimals={m.decimals}
suffix={m.suffix}
className="evnd__kpi-val"
/>
)}
<span className="evnd__kpi-label">{m.label}</span> <span className="evnd__kpi-label">{m.label}</span>
</div> </div>
))} ))}
@@ -342,11 +360,15 @@ export default function EVSection({
ariaLabel, ariaLabel,
mediaSlot, mediaSlot,
metrics, metrics,
barStats,
cardsHeading, cardsHeading,
cardsTheme, cardsTheme,
sysLabel,
mediaClassName,
}: EVSectionProps) { }: EVSectionProps) {
const bannerRef = useRef<HTMLDivElement>(null); const bannerRef = useRef<HTMLDivElement>(null);
const useDashboard = !!metrics && metrics.length > 0; const useDashboard = !!metrics && metrics.length > 0;
const isVideo = image.endsWith(".mp4");
/* In dashboard mode the workflow's accent theme is applied at the .evnd /* In dashboard mode the workflow's accent theme is applied at the .evnd
section level so the shared animated network backdrop (below) is tinted to section level so the shared animated network backdrop (below) is tinted to
@@ -595,13 +617,31 @@ export default function EVSection({
background: #ef4444; background: #ef4444;
} }
/* ---- Heading → content gap ----
Deliberately set here (on the wrapper div) rather than as
margin-bottom on .evnd__title (the <h2>): a global site.css rule
(.logico-front-end h2:not([class*="logico-title-h"]):last-child)
outweighs .evnd__title's own specificity and zeroes any bottom
margin placed on the heading itself, since the h2 is always the
last child of .evnd__heading. Setting it here sidesteps that
collision and gives every workflow section + Fleet Strategy one
shared, consistent gap. */
.evnd__heading {
margin-bottom: 40px;
}
@media (max-width: 991px) and (min-width: 768px) {
.evnd__heading {
margin-bottom: 34px;
}
}
.evnd__title { .evnd__title {
color: #fff !important; color: #fff !important;
font-weight: 800 !important; font-weight: 800 !important;
font-size: clamp(32px, 3.8vw, 48px) !important; font-size: clamp(32px, 3.8vw, 48px) !important;
line-height: 1.15 !important; line-height: 1.15 !important;
letter-spacing: -0.01em; letter-spacing: -0.01em;
margin: 0 0 36px 0; margin: 0;
} }
@media (min-width: 768px) { @media (min-width: 768px) {
.evnd__title { .evnd__title {
@@ -867,6 +907,13 @@ export default function EVSection({
font-size: 12.5px; font-size: 12.5px;
letter-spacing: 0.01em; letter-spacing: 0.01em;
} }
/* Non-numeric KPI concepts (EVStat.text) — same gradient treatment as
the counted values, sized down so short codes/words don't inherit
the numeric clamp() meant for 2-3 digit figures. */
.evnd__kpi-val--text {
font-size: clamp(18px, 1.6vw, 22px) !important;
letter-spacing: 0.02em;
}
/* ============================================================ /* ============================================================
Large-screen layout balance (WF1/WF2 dashboard only, ≥1440px). Large-screen layout balance (WF1/WF2 dashboard only, ≥1440px).
@@ -1041,6 +1088,14 @@ export default function EVSection({
text-transform: none; text-transform: none;
opacity: 0.9; opacity: 0.9;
} }
/* Non-numeric bar values (EVStat.text) — the bar's numeric clamp()
(up to 56px) is too large for words/phrases; size down and let
longer phrases (e.g. "Cost + Distance + SLA") wrap cleanly. */
.evnd__bar-val--text {
font-size: clamp(16px, 1.8vw, 22px);
line-height: 1.25;
white-space: normal;
}
@keyframes evndGlow { 0%,100% { opacity: 0.75; } 50% { opacity: 1; } } @keyframes evndGlow { 0%,100% { opacity: 0.75; } 50% { opacity: 1; } }
@@ -1052,7 +1107,6 @@ export default function EVSection({
@media (max-width: 991px) { @media (max-width: 991px) {
.evnd { padding: 48px 32px 56px; } .evnd { padding: 48px 32px 56px; }
.evnd__grid { grid-template-columns: 1fr; gap: 40px; } .evnd__grid { grid-template-columns: 1fr; gap: 40px; }
.evnd__title { margin-bottom: 28px; }
.evnd__features { gap: 14px; } .evnd__features { gap: 14px; }
/* Stacked: KPI row can spread to 4-up since it now has full width. */ /* Stacked: KPI row can spread to 4-up since it now has full width. */
.evnd__dash-kpis { grid-template-columns: repeat(4, 1fr); } .evnd__dash-kpis { grid-template-columns: repeat(4, 1fr); }
@@ -1331,7 +1385,7 @@ export default function EVSection({
<div <div
className={`evnd__inner${useDashboard ? " evnd__inner--cards" : ""}${ className={`evnd__inner${useDashboard ? " evnd__inner--cards" : ""}${
useDashboard && !mediaSlot ? " evnd__inner--img" : "" useDashboard && !mediaSlot && !isVideo ? " evnd__inner--img" : ""
}`} }`}
> >
<div className="evnd__heading"> <div className="evnd__heading">
@@ -1345,7 +1399,7 @@ export default function EVSection({
{/* MAIN GRID */} {/* MAIN GRID */}
<div <div
className={`evnd__grid${useDashboard ? " evnd__grid--cards" : ""}${ className={`evnd__grid${useDashboard ? " evnd__grid--cards" : ""}${
useDashboard && !mediaSlot ? " evnd__grid--img" : "" useDashboard && !mediaSlot && !isVideo ? " evnd__grid--img" : ""
}`} }`}
> >
{/* Left column */} {/* Left column */}
@@ -1353,11 +1407,11 @@ export default function EVSection({
<div className="evnd__media"> <div className="evnd__media">
<div className="evnd__glow" /> <div className="evnd__glow" />
<div <div
className={`evnd__imgwrap${mediaSlot ? " evnd__imgwrap--media" : ""}${image.endsWith(".mp4") ? " evnd__imgwrap--video" : ""}`} className={`evnd__imgwrap${mediaSlot ? " evnd__imgwrap--media" : ""}${isVideo ? " evnd__imgwrap--video" : ""}${mediaClassName ? ` ${mediaClassName}` : ""}`}
> >
{mediaSlot ? ( {mediaSlot ? (
mediaSlot mediaSlot
) : image.endsWith(".mp4") ? ( ) : isVideo ? (
<video <video
className="evnd__video" className="evnd__video"
autoPlay autoPlay
@@ -1401,6 +1455,7 @@ export default function EVSection({
features={features} features={features}
heading={cardsHeading} heading={cardsHeading}
theme={cardsTheme} theme={cardsTheme}
sysLabel={sysLabel}
/> />
) : ( ) : (
<div className="evnd__features"> <div className="evnd__features">
@@ -1434,15 +1489,19 @@ export default function EVSection({
all breakpoints. In dashboard mode it summarises the same workflow all breakpoints. In dashboard mode it summarises the same workflow
metrics; the homepage section uses its own stat set. */} metrics; the homepage section uses its own stat set. */}
<div className="evnd__bar"> <div className="evnd__bar">
{(useDashboard ? metrics! : stats).map((s) => ( {(useDashboard ? (barStats ?? metrics!) : stats).map((s) => (
<div className="evnd__bar-item" key={s.label}> <div className="evnd__bar-item" key={s.label}>
<span className="evnd__bar-label">{s.label}</span> <span className="evnd__bar-label">{s.label}</span>
<CountUp {s.text ? (
value={s.value} <b className="evnd__bar-val evnd__bar-val--text">{s.text}</b>
decimals={s.decimals} ) : (
suffix={s.suffix} <CountUp
className="evnd__bar-val" value={s.value}
/> decimals={s.decimals}
suffix={s.suffix}
className="evnd__bar-val"
/>
)}
</div> </div>
))} ))}
</div> </div>

View File

@@ -196,6 +196,26 @@ export default function EmpowermentHowItWorks() {
} }
} }
/* ---- Mobile title-to-description gap fix ----
.ehw-step-title is an <h3>, so it's matched by a global,
unscoped site.css rule (.logico-front-end h3:not(...) { margin:
0 0 30px }) that outranks this component's own single-class
".ehw-step-title { margin: 0 0 22px }" by specificity — bumping
the real margin-bottom to 30px everywhere, not just here. There
is no min-height, space-between, or fixed row height anywhere in
this component; the gap is purely that extra 8px of margin
reading as oversized once every other element around it (kicker,
description line-height) is tightly spaced. Overridden with
!important, matching how every other property on this selector
already has to defeat the same global rule. Scoped to mobile
only, per spec — desktop/tablet are left exactly as they were
(still resolving to the global 30px; out of scope here). */
@media (max-width: 767px) {
.ehw-step-title {
margin-bottom: 16px !important;
}
}
@media (max-width: 480px) { @media (max-width: 480px) {
.ehw-section { padding-top: 48px; padding-bottom: 68px; } .ehw-section { padding-top: 48px; padding-bottom: 68px; }
} }

View File

@@ -100,6 +100,32 @@ export default function EmpowermentStory() {
margin: 0; margin: 0;
} }
/* ---- Desktop-only inner spacing compaction ----
.esy-section never set its own padding, so it was silently
inheriting 96px top/bottom from the global bare-tag "section"
padding rule (6rem 0) in site.css — stacking with .esy-inner's
own clamp(60-98px) padding into a huge, unbalanced inset. Cancel
that leak here. Also tighten .esy-inner's own padding and widen its
max-width (so a fixed padding, not a narrow centered column,
controls the left/right inset at every desktop width) — and bring
min-height down to match the now-tighter natural content height,
since the old 690px floor was itself forcing extra empty space
once the padding was reduced. Scoped to desktop only; tablet/
mobile keep their original spacing untouched below. */
@media (min-width: 1025px) {
.esy-section {
padding: 0;
min-height: clamp(420px, 38vw, 500px);
}
.esy-inner {
max-width: 1900px;
padding-top: 64px;
padding-bottom: 56px;
padding-left: 64px;
padding-right: 64px;
}
}
@media (max-width: 1024px) { @media (max-width: 1024px) {
.esy-section { width: calc(100% - 24px); border-radius: 22px; } .esy-section { width: calc(100% - 24px); border-radius: 22px; }
.esy-inner { grid-template-columns: 1fr; align-items: start; } .esy-inner { grid-template-columns: 1fr; align-items: start; }

View File

@@ -200,6 +200,26 @@
margin: 0; margin: 0;
} }
/* ---- Step 04 / Step 05 title-alignment fix ----
.stepBottom sits in .step's 1fr grid row with align-self:end, so its
title starts wherever the leftover space above it runs out — driven by
its OWN content height, not a shared position. Steps 01-03's
descriptions wrap to 3 lines, giving .stepBottom a natural height of
~101px; "Destination Hub" (04) and "EV Last-Mile" (05) wrap to only 2
lines (~79px) at several desktop widths, so under that same
end-alignment they're left with ~22px more leftover space above them
and their titles land visibly lower. Reserving that same ~101px on
.stepBottom for these two steps only — a floor, not a cap, so it's
inert wherever their content is already taller — reproduces Steps
01-03's exact title position without touching their CSS, the shared
grid, or align-self. */
@media (min-width: 1200px) {
.step:nth-child(4) .stepBottom,
.step:nth-child(5) .stepBottom {
min-height: 102px;
}
}
@media (max-width: 1024px) { @media (max-width: 1024px) {
.headerRow { .headerRow {
flex-direction: column; flex-direction: column;

View File

@@ -0,0 +1,123 @@
"use client";
import React from "react";
import EVSection, { EVStat, EVBadge, EVFeature, EVCardsTheme } from "./EVSection";
/* Violet / Electric Purple — distinct from WF1 (cyan/teal) and WF2 (red/crimson). */
const THEME: EVCardsTheme = {
accent: "#7C5CFF",
accent2: "#4C3AE3",
glow: "rgba(124,92,255,0.20)",
};
/**
* Workflow 4 — Quantum Intelligence (hybrid split-screen).
*
* • Left — video: the hybrid optimization / energy-landscape visual.
* • Right — a COMPACT DASHBOARD: a quick KPI row (QUBO / Global / Hybrid /
* Multi) over feature cards describing the encode → energy
* landscape → global minimum → hybrid intelligence pipeline,
* sitting on the animated network backdrop (violet).
*
* Messaging is deliberately framed as work-in-progress ("building",
* "exploring") rather than a shipped quantum-computing claim.
*/
const METRICS: EVStat[] = [
{ text: "QUBO", value: 0, suffix: "", label: "Problem Model" },
{ text: "GLOBAL", value: 0, suffix: "", label: "Minimum Search" },
{ text: "HYBRID", value: 0, suffix: "", label: "Intelligence" },
{ text: "MULTI", value: 0, suffix: "", label: "Objective" },
];
/* Distinct copy for the bottom capability bar (not a repeat of the KPI row —
* Workflow 4's brief specifies separate content for each). */
const BAR_STATS: EVStat[] = [
{ text: "Multi-Rider", value: 0, suffix: "", label: "Dynamic Routing" },
{ text: "Optimized", value: 0, suffix: "", label: "Time Windows" },
{ text: "Real-Time", value: 0, suffix: "", label: "Fleet Balancing" },
{ text: "Cost + Distance + SLA", value: 0, suffix: "", label: "Objectives" },
];
const ico = (path: React.ReactNode) => (
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
>
{path}
</svg>
);
const FEATURES: EVFeature[] = [
{
icon: ico(
<>
<rect x="3" y="3" width="7" height="7" />
<rect x="14" y="3" width="7" height="7" />
<rect x="14" y="14" width="7" height="7" />
<rect x="3" y="14" width="7" height="7" />
</>,
),
title: "Encode the Problem",
desc: "Rider assignments, delivery sequences, capacity, traffic, service time, and SLA constraints become part of one mathematical optimization model.",
},
{
icon: ico(<path d="m8 3 4 8 5-5 5 15H2L8 3z" />),
title: "Build the Energy Landscape",
desc: "Each feasible routing solution is represented as a state with its own energy through a QUBO formulation.",
},
{
icon: ico(
<>
<circle cx="12" cy="12" r="9" />
<circle cx="12" cy="12" r="5" />
<circle cx="12" cy="12" r="1" />
</>,
),
title: "Search the Global Minimum",
desc: "Optimization becomes the search for the lowest-energy state instead of evaluating route combinations one by one.",
},
{
icon: ico(
<>
<polygon points="12 2 2 7 12 12 22 7 12 2" />
<polyline points="2 17 12 22 22 17" />
<polyline points="2 12 12 17 22 12" />
</>,
),
title: "Hybrid Intelligence",
desc: "Classical algorithms, AI models, and quantum optimization work together using the right computational model for each problem.",
},
];
const BADGES: EVBadge[] = [
{ value: "QUBO", label: "PROBLEM MODEL" },
{ value: "HYBRID", label: "INTELLIGENCE" },
];
export default function Workflow4() {
return (
<EVSection
ariaLabel="Workflow 4 — Quantum Intelligence"
gapBottom
image="/videos/Doormile-quantum-video3.mp4"
cardTitle="BUILDING QUANTUM INTELLIGENCE"
cardSubtitle="Exploring a hybrid optimization layer that treats routing as an energy landscape, not a search problem."
eyebrow="/ Quantum Intelligence /"
titleLead="FROM ROUTE SEARCH. "
titleAccent="TO ENERGY MINIMIZATION."
imageAlt="Hybrid quantum-classical optimization engine visualizing an energy landscape"
metrics={METRICS}
barStats={BAR_STATS}
features={FEATURES}
cardsHeading="Quantum Intelligence"
sysLabel="HYBRID ENGINE"
cardsTheme={THEME}
badges={BADGES}
mediaClassName="evnd__imgwrap--wf4"
/>
);
}