Merge branch 'cursor/air-freight-page'

This commit is contained in:
2026-07-13 15:15:46 +05:30
55 changed files with 7247 additions and 81 deletions

View File

@@ -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
@@ -599,13 +621,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 {
@@ -756,7 +796,7 @@ export default function EVSection({
.evnd-feature__desc {
color: rgba(255,255,255,0.65) !important;
font-weight: 400 !important;
font-size: 14px !important;
font-size: 16px !important;
line-height: 1.6 !important;
margin: 0;
}
@@ -871,6 +911,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).
@@ -973,8 +1020,8 @@ export default function EVSection({
.evnd__dfeat-desc {
color: rgba(255,255,255,0.6) !important;
font-weight: 400 !important;
font-size: 13px !important;
line-height: 1.45 !important;
font-size: 16px !important;
line-height: 1.55 !important;
margin: 0 !important;
}
@@ -1045,6 +1092,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; } }
@@ -1056,7 +1111,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); }
@@ -1335,7 +1389,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">
@@ -1349,7 +1403,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 */}
@@ -1357,11 +1411,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
@@ -1405,6 +1459,7 @@ export default function EVSection({
features={features}
heading={cardsHeading}
theme={cardsTheme}
sysLabel={sysLabel}
/>
) : (
<div className="evnd__features">
@@ -1438,15 +1493,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>