fix workflow section
This commit is contained in:
@@ -2,6 +2,7 @@ import React from "react";
|
||||
import MileTruthHero from "../../components/sections/MileTruthHero";
|
||||
import Workflow1 from "../../components/sections/Workflow1";
|
||||
import Workflow2 from "../../components/sections/Workflow2";
|
||||
import Workflow4 from "../../components/sections/Workflow4";
|
||||
import Workflow3Lazy from "../../components/sections/Workflow3Lazy";
|
||||
|
||||
export const metadata = {
|
||||
@@ -18,6 +19,7 @@ export default function MileTruthPage() {
|
||||
<MileTruthHero />
|
||||
<Workflow1 />
|
||||
<Workflow2 />
|
||||
<Workflow4 />
|
||||
<Workflow3Lazy />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -42,6 +42,9 @@ export interface EVStat {
|
||||
decimals?: number;
|
||||
suffix: 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
|
||||
@@ -83,10 +86,19 @@ interface EVSectionProps {
|
||||
* static homepage feature list. The bottom stat bar is dropped in this mode
|
||||
* to avoid repeating the metrics. */
|
||||
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". */
|
||||
cardsHeading?: string;
|
||||
/** Accent theme for the dashboard column (defaults to the section red). */
|
||||
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 ---- */
|
||||
@@ -260,11 +272,13 @@ function DashboardPanel({
|
||||
features,
|
||||
heading,
|
||||
theme,
|
||||
sysLabel = "AI ENGINE",
|
||||
}: {
|
||||
metrics: EVStat[];
|
||||
features: EVFeature[];
|
||||
heading?: string;
|
||||
theme?: EVCardsTheme;
|
||||
sysLabel?: string;
|
||||
}) {
|
||||
const themeVars = theme
|
||||
? ({
|
||||
@@ -287,7 +301,7 @@ function DashboardPanel({
|
||||
<span className="evnd__dash-livedot" />
|
||||
{heading}
|
||||
</span>
|
||||
<span className="evnd__dash-sys">AI ENGINE</span>
|
||||
<span className="evnd__dash-sys">{sysLabel}</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -295,12 +309,16 @@ function DashboardPanel({
|
||||
<div className="evnd__dash-kpis">
|
||||
{metrics.map((m) => (
|
||||
<div className="evnd__kpi" key={m.label}>
|
||||
<CountUp
|
||||
value={m.value}
|
||||
decimals={m.decimals}
|
||||
suffix={m.suffix}
|
||||
className="evnd__kpi-val"
|
||||
/>
|
||||
{m.text ? (
|
||||
<b className="evnd__kpi-val evnd__kpi-val--text">{m.text}</b>
|
||||
) : (
|
||||
<CountUp
|
||||
value={m.value}
|
||||
decimals={m.decimals}
|
||||
suffix={m.suffix}
|
||||
className="evnd__kpi-val"
|
||||
/>
|
||||
)}
|
||||
<span className="evnd__kpi-label">{m.label}</span>
|
||||
</div>
|
||||
))}
|
||||
@@ -342,11 +360,15 @@ export default function EVSection({
|
||||
ariaLabel,
|
||||
mediaSlot,
|
||||
metrics,
|
||||
barStats,
|
||||
cardsHeading,
|
||||
cardsTheme,
|
||||
sysLabel,
|
||||
mediaClassName,
|
||||
}: EVSectionProps) {
|
||||
const bannerRef = useRef<HTMLDivElement>(null);
|
||||
const useDashboard = !!metrics && metrics.length > 0;
|
||||
const isVideo = image.endsWith(".mp4");
|
||||
|
||||
/* 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
|
||||
@@ -595,13 +617,31 @@ export default function EVSection({
|
||||
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 {
|
||||
color: #fff !important;
|
||||
font-weight: 800 !important;
|
||||
font-size: clamp(32px, 3.8vw, 48px) !important;
|
||||
line-height: 1.15 !important;
|
||||
letter-spacing: -0.01em;
|
||||
margin: 0 0 36px 0;
|
||||
margin: 0;
|
||||
}
|
||||
@media (min-width: 768px) {
|
||||
.evnd__title {
|
||||
@@ -867,6 +907,13 @@ export default function EVSection({
|
||||
font-size: 12.5px;
|
||||
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).
|
||||
@@ -1041,6 +1088,14 @@ export default function EVSection({
|
||||
text-transform: none;
|
||||
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; } }
|
||||
|
||||
@@ -1052,7 +1107,6 @@ export default function EVSection({
|
||||
@media (max-width: 991px) {
|
||||
.evnd { padding: 48px 32px 56px; }
|
||||
.evnd__grid { grid-template-columns: 1fr; gap: 40px; }
|
||||
.evnd__title { margin-bottom: 28px; }
|
||||
.evnd__features { gap: 14px; }
|
||||
/* Stacked: KPI row can spread to 4-up since it now has full width. */
|
||||
.evnd__dash-kpis { grid-template-columns: repeat(4, 1fr); }
|
||||
@@ -1331,7 +1385,7 @@ export default function EVSection({
|
||||
|
||||
<div
|
||||
className={`evnd__inner${useDashboard ? " evnd__inner--cards" : ""}${
|
||||
useDashboard && !mediaSlot ? " evnd__inner--img" : ""
|
||||
useDashboard && !mediaSlot && !isVideo ? " evnd__inner--img" : ""
|
||||
}`}
|
||||
>
|
||||
<div className="evnd__heading">
|
||||
@@ -1345,7 +1399,7 @@ export default function EVSection({
|
||||
{/* MAIN GRID */}
|
||||
<div
|
||||
className={`evnd__grid${useDashboard ? " evnd__grid--cards" : ""}${
|
||||
useDashboard && !mediaSlot ? " evnd__grid--img" : ""
|
||||
useDashboard && !mediaSlot && !isVideo ? " evnd__grid--img" : ""
|
||||
}`}
|
||||
>
|
||||
{/* Left column */}
|
||||
@@ -1353,11 +1407,11 @@ export default function EVSection({
|
||||
<div className="evnd__media">
|
||||
<div className="evnd__glow" />
|
||||
<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
|
||||
) : image.endsWith(".mp4") ? (
|
||||
) : isVideo ? (
|
||||
<video
|
||||
className="evnd__video"
|
||||
autoPlay
|
||||
@@ -1401,6 +1455,7 @@ export default function EVSection({
|
||||
features={features}
|
||||
heading={cardsHeading}
|
||||
theme={cardsTheme}
|
||||
sysLabel={sysLabel}
|
||||
/>
|
||||
) : (
|
||||
<div className="evnd__features">
|
||||
@@ -1434,15 +1489,19 @@ export default function EVSection({
|
||||
all breakpoints. In dashboard mode it summarises the same workflow
|
||||
metrics; the homepage section uses its own stat set. */}
|
||||
<div className="evnd__bar">
|
||||
{(useDashboard ? metrics! : stats).map((s) => (
|
||||
{(useDashboard ? (barStats ?? metrics!) : stats).map((s) => (
|
||||
<div className="evnd__bar-item" key={s.label}>
|
||||
<span className="evnd__bar-label">{s.label}</span>
|
||||
<CountUp
|
||||
value={s.value}
|
||||
decimals={s.decimals}
|
||||
suffix={s.suffix}
|
||||
className="evnd__bar-val"
|
||||
/>
|
||||
{s.text ? (
|
||||
<b className="evnd__bar-val evnd__bar-val--text">{s.text}</b>
|
||||
) : (
|
||||
<CountUp
|
||||
value={s.value}
|
||||
decimals={s.decimals}
|
||||
suffix={s.suffix}
|
||||
className="evnd__bar-val"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
@@ -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) {
|
||||
.ehw-section { padding-top: 48px; padding-bottom: 68px; }
|
||||
}
|
||||
|
||||
@@ -100,6 +100,32 @@ export default function EmpowermentStory() {
|
||||
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) {
|
||||
.esy-section { width: calc(100% - 24px); border-radius: 22px; }
|
||||
.esy-inner { grid-template-columns: 1fr; align-items: start; }
|
||||
|
||||
@@ -200,6 +200,26 @@
|
||||
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) {
|
||||
.headerRow {
|
||||
flex-direction: column;
|
||||
|
||||
123
src/components/sections/Workflow4.tsx
Normal file
123
src/components/sections/Workflow4.tsx
Normal 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"
|
||||
/>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user