// ============================================================
// EvIntegratedMobile — MOBILE port of the desktop "Integrated energy
// infrastructure" section (EvPlanning) from ev-financial-cta.jsx.
//
// Desktop = interactive facility schematic (left) + 2×2 hover grid (right).
// Mobile keeps the SAME story & visual language but swaps hover for touch:
// • Intro (eyebrow + headline + supporting copy), stacked
// • Interactive diagram, always visible, the visual focus
// • Solution cards as a horizontal swipe carousel below the diagram
// • Swiping / tapping a card -> updates the active diagram zone
// • Tapping a diagram marker -> scrolls the matching card into view
// • Default active zone: 01 — Demand-Charge Reduction
// Copy, colours, type, iconography all carried over verbatim.
// ============================================================
const EV_AMBER_LOCAL_M = '#D4A24C';
const EV_BLOCKS = [
{
label: 'Demand-Charge Reduction',
icon: 'activity',
body: 'Solar generation offsets daytime charging demand while battery storage dispatches during peak charging periods—helping flatten facility demand spikes and reduce monthly demand charges.'
},
{
label: 'Reduced Utility Upgrades',
icon: 'zap-off',
body: 'Battery storage can reduce the peak electrical demand placed on the grid, helping facilities avoid or defer costly utility infrastructure upgrades, transformer replacements, and service capacity expansions.'
},
{
label: 'Solar-Powered Charging',
icon: 'sun',
body: 'Daytime EV charging aligns naturally with commercial solar production. Co-locating solar with EV infrastructure reduces net charging costs and improves long-term energy economics.'
},
{
label: 'Infrastructure Designed for Expansion',
icon: 'layers',
body: 'Integrated systems allow facilities to scale fleet electrification over time while planning electrical infrastructure, charging loads, solar generation, and battery capacity together from the start.'
}
];
const EV_CAPTIONS = [
{ zone: 'Solar + Battery', flow: 'Peak demand flattened' },
{ zone: 'Battery + Service Panel', flow: 'Grid draw reduced' },
{ zone: 'Solar + EV Chargers', flow: 'Daytime self-supply' },
{ zone: 'Whole facility', flow: 'Designed for growth' }
];
// ============================================================
// EvSchematicMobile — identical SVG schematic to desktop, with the
// numbered markers made tappable (large invisible hit targets).
// ============================================================
const EvSchematicMobile = ({ activeIndex, onSelectZone }) => {
const W = 540;
const H = 420;
const amber = EV_AMBER_LOCAL_M;
const amberFill = 'rgba(212,162,76,0.18)';
const ink = 'rgba(255,255,255,0.55)';
const inkDim = 'rgba(255,255,255,0.32)';
const inkFaint = 'rgba(255,255,255,0.18)';
const inkText = 'rgba(255,255,255,0.62)';
const showAll = activeIndex === 3;
const isSolar = activeIndex === 2 || showAll;
const isBattery = activeIndex === 0 || activeIndex === 1 || showAll;
const isService = activeIndex === 1 || showAll;
const isEV = activeIndex === 2 || showAll;
const isDemandCombo = activeIndex === 0;
const flowSolarBatt = activeIndex === 0 || showAll;
const flowBattGrid = activeIndex === 1 || showAll;
const flowSolarEV = activeIndex === 2 || showAll;
const solarLit = isSolar || isDemandCombo;
const batteryLit = isBattery;
const evLit = isEV || isDemandCombo;
const zones = [
{ id: 0, label: '01', cx: 270, cy: 200 },
{ id: 1, label: '02', cx: 60, cy: 178 },
{ id: 2, label: '03', cx: 270, cy: 78 },
{ id: 3, label: '04', cx: 502, cy: 388 }
];
return (
);
};
// ============================================================
// EvIntegratedMobile — full mobile section
// ============================================================
const EvIntegratedMobile = () => {
const [active, setActive] = React.useState(0);
const scrollerRef = React.useRef(null);
const cardRefs = React.useRef([]);
const programmatic = React.useRef(false);
const rafId = React.useRef(0);
// (Re)draw lucide icons whenever the active card changes.
React.useEffect(() => {
const t = setTimeout(() => window.lucide && window.lucide.createIcons({ attrs: { 'stroke-width': 1.4 } }), 20);
return () => clearTimeout(t);
}, [active]);
const scrollToCard = (i) => {
const sc = scrollerRef.current;
const card = cardRefs.current[i];
if (!sc || !card) return;
programmatic.current = true;
const target = card.offsetLeft - (sc.clientWidth - card.clientWidth) / 2;
const max = sc.scrollWidth - sc.clientWidth;
const end = Math.max(0, Math.min(max, target));
const start = sc.scrollLeft;
const dist = end - start;
// Programmatic smooth scroll via scrollTo() is unreliable next to
// scroll-snap, so animate scrollLeft by hand. Snap is suspended during
// the tween and restored after we land on a snap point.
sc.style.scrollSnapType = 'none';
window.cancelAnimationFrame(scrollToCard._raf);
if (Math.abs(dist) < 1) {
sc.style.scrollSnapType = 'x mandatory';
programmatic.current = false;
return;
}
const dur = 420;
const t0 = (window.performance || Date).now();
const ease = (t) => 1 - Math.pow(1 - t, 3); // easeOutCubic
const step = (now) => {
const p = Math.min(1, (now - t0) / dur);
sc.scrollLeft = start + dist * ease(p);
if (p < 1) {
scrollToCard._raf = window.requestAnimationFrame(step);
} else {
sc.style.scrollSnapType = 'x mandatory';
programmatic.current = false;
}
};
scrollToCard._raf = window.requestAnimationFrame(step);
};
// Tap a card OR a diagram marker -> select that zone + center its card.
const selectZone = (i) => {
setActive(i);
scrollToCard(i);
};
// Swipe -> detect the card nearest the scroller centre, set it active.
const handleScroll = () => {
// Ignore scroll events fired by our own smooth-scroll (tap / marker / dot),
// otherwise the in-flight scroll position resets `active` to card 0.
if (programmatic.current) return;
if (rafId.current) return;
rafId.current = requestAnimationFrame(() => {
rafId.current = 0;
const sc = scrollerRef.current;
if (!sc) return;
const center = sc.scrollLeft + sc.clientWidth / 2;
let best = 0, bestDist = Infinity;
cardRefs.current.forEach((c, i) => {
if (!c) return;
const cc = c.offsetLeft + c.clientWidth / 2;
const d = Math.abs(cc - center);
if (d < bestDist) { bestDist = d; best = i; }
});
setActive((prev) => (prev === best ? prev : best));
});
};
return (
{/* Decorative grid-rule pattern, top right (mirrors desktop) */}
{/* ===== 1 · INTRO ===== */}
Integrated energy infrastructure
The future of EV charging is{' '}
integrated energy infrastructure.
When EV charging, solar, and battery storage are designed together,
facilities can reduce grid dependency, flatten peak demand, and avoid
portions of the utility infrastructure upgrades often triggered by
large charging loads.