/* Nexaro homepage sections. */
const SiteButtonForHome = window.SiteButton;
function Reveal({ children, delay = 0, className = "", style }) {
const ref = React.useRef(null);
const [seen, setSeen] = React.useState(false);
React.useEffect(() => {
const el = ref.current;
if (!el) return undefined;
const observer = new IntersectionObserver(
([entry]) => {
if (entry.isIntersecting) {
setSeen(true);
observer.disconnect();
}
},
{ threshold: 0.15 },
);
observer.observe(el);
return () => observer.disconnect();
}, []);
return (
{children}
);
}
const SERVICE_GUARANTEES = [
{
title: "Klare Zusagen",
text: "Produkt, Lieferfenster und Konditionen werden vor der Ausführung abgestimmt.",
icon: "ph ph-handshake",
},
{
title: "Feste Zuständigkeit",
text: "Ein Handelsteam begleitet den Auftrag von der Planung bis zur Abrechnung.",
icon: "ph ph-user-focus",
},
{
title: "Proaktive Kommunikation",
text: "Änderungen werden früh angesprochen und direkt neu koordiniert.",
icon: "ph ph-chats-circle",
},
{
title: "Nachvollziehbare Abwicklung",
text: "Bestätigung, Lieferung und Abrechnung bleiben transparent dokumentiert.",
icon: "ph ph-clipboard-text",
},
];
function Hero({ onQuote }) {
return (
Diesel / Benzin / HVO / Heizöl
Kraftstoff versorgung ohne Abweichung.
Nexaro koordiniert vertragsbasierte Kraftstoffversorgung in ganz Deutschland,
von Rack-Zuteilung und Depotplanung bis zu Lieferfenstern und Abrechnung.
Angebot anfragen
document.getElementById("network")?.scrollIntoView({ behavior: "smooth" })}>
Netzwerk ansehen
);
}
function ServiceGuarantees() {
return (
{SERVICE_GUARANTEES.map((item, index) => (
{item.title}
{item.text}
))}
);
}
const OPERATIONS_STEPS = [
{
label: "Beschaffung",
title: "Zuteilung vor der Disposition sichern.",
text: "Das Handelsteam nimmt den Auftrag auf, prüft Handelspartner und Kreditlinie und reserviert die Sorte an einem passenden Depot.",
tag: "Beschaffungszuteilung",
movement: "Auftragseingang -> Handelsteam -> Depotzuteilung",
details: ["Sorte abgeglichen", "Zuteilung gehalten"],
},
{
label: "Disposition",
title: "Aus Zuteilung wird eine Route.",
text: "Das Handelsteam verbindet Depotbestand, Fahrzeugverfügbarkeit und Lieferfenster zu einem belastbaren Dispositionsplan.",
tag: "Dispositionskoordination",
movement: "Depotzuteilung -> Ladefenster -> Tankwagen",
details: ["Fahrzeug zugewiesen", "Ladefenster gesetzt"],
},
{
label: "Tankstelle",
title: "Stationen zuverlässig auffüllen.",
text: "Wiederkehrende Lieferungen an Tankstellen und Fuhrparks werden nach Sorte, Tankstand und Annahmefenster sequenziert.",
tag: "Tankstellenversorgung",
movement: "Tankwagen -> Tankstelle",
details: ["Tankstand abgeglichen", "Annahmefenster gehalten"],
},
{
label: "Heizöl",
title: "Heizöl-Lieferungen einplanen.",
text: "Heizölaufträge für Haushalte, Wohnungswirtschaft und Gewerbestandorte werden gebündelt, ohne den Hauptplan zu stören.",
tag: "Heizölbelieferung",
movement: "Tankwagen -> Heizölstandort",
details: ["Lieferungen gebündelt", "Zugang bestätigt"],
},
];
const OPS_PATHS = [
[{ x: 88, y: 126 }, { x: 235, y: 126 }, { x: 382, y: 126 }],
[{ x: 382, y: 126 }, { x: 382, y: 248 }, { x: 520, y: 248 }],
[{ x: 520, y: 248 }, { x: 520, y: 126 }],
[{ x: 520, y: 248 }, { x: 520, y: 380 }],
];
const OPS_PATH_DATA = OPS_PATHS.map((points) => {
const legs = points.slice(1).map((point, index) => {
const previous = points[index];
return {
from: previous,
to: point,
length: Math.hypot(point.x - previous.x, point.y - previous.y),
};
});
return {
d: points.map((point, index) => `${index === 0 ? "M" : "L"} ${point.x} ${point.y}`).join(" "),
legs,
total: legs.reduce((sum, leg) => sum + leg.length, 0),
};
});
const OPS_NODES = [
{ id: "order", label: ["Auftrags-", "eingang"], x: 88, y: 126 },
{ id: "desk", label: ["Handels-", "team"], x: 235, y: 126 },
{ id: "allocation", label: ["Depot-", "zuteilung"], x: 382, y: 126 },
{ id: "slot", label: ["Lade-", "fenster"], x: 382, y: 248 },
{ id: "tanker", label: "Tankwagen", x: 520, y: 248 },
{ id: "forecourt", label: "Tankstelle", x: 520, y: 126 },
{ id: "heating", label: ["Heizöl-", "standort"], x: 520, y: 380 },
];
const OPS_ACTIVE_NODES = [
["order", "desk", "allocation"],
["allocation", "slot", "tanker"],
["tanker", "forecourt"],
["tanker", "heating"],
];
function getScrollViewportHeight() {
return window.visualViewport?.height || document.documentElement.clientHeight || window.innerHeight;
}
function pointOnPath(path, progress) {
let target = Math.max(0, Math.min(1, progress)) * path.total;
for (const leg of path.legs) {
if (target <= leg.length) {
const t = leg.length === 0 ? 0 : target / leg.length;
return {
x: leg.from.x + (leg.to.x - leg.from.x) * t,
y: leg.from.y + (leg.to.y - leg.from.y) * t,
};
}
target -= leg.length;
}
return path.legs[path.legs.length - 1].to;
}
function OperationsSchematic({ active }) {
const activeNodes = new Set(OPS_ACTIVE_NODES[active]);
const step = OPERATIONS_STEPS[active];
return (
{[126, 248, 380].map((y) => )}
{[88, 235, 382, 520].map((x) => )}
{OPS_PATH_DATA.map((path, index) => {
const isActive = index === active;
return (
);
})}
{OPS_NODES.map((node) => {
const isActive = activeNodes.has(node.id);
const lines = Array.isArray(node.label) ? node.label : [node.label];
return (
1 ? -7 : 5} textAnchor="middle">
{lines.map((line, index) => (
{line}
))}
);
})}
{step.tag}
{step.label}
{step.movement}
{step.details.map((detail) => {detail} )}
);
}
function OperationsScroll() {
const ref = React.useRef(null);
const activeRef = React.useRef(0);
const rafRef = React.useRef(0);
const [active, setActive] = React.useState(0);
React.useEffect(() => {
const apply = () => {
const el = ref.current;
if (!el) return;
const total = el.offsetHeight - getScrollViewportHeight();
const passed = total > 0 ? Math.min(Math.max(-el.getBoundingClientRect().top, 0), total) : 0;
const progress = total > 0 ? passed / total : 0;
const raw = progress * OPERATIONS_STEPS.length;
const active = Math.min(OPERATIONS_STEPS.length - 1, Math.floor(raw));
const local = Math.min(1, Math.max(0, raw - active));
const marker = pointOnPath(OPS_PATH_DATA[active], local);
el.style.setProperty("--ops-local", local.toFixed(4));
el.style.setProperty("--ops-dash", (1 - Math.max(0.08, local)).toFixed(4));
el.style.setProperty("--ops-marker-x", `${marker.x.toFixed(2)}px`);
el.style.setProperty("--ops-marker-y", `${marker.y.toFixed(2)}px`);
OPERATIONS_STEPS.forEach((_, index) => {
const fill = index < active ? 1 : index === active ? local : 0;
el.style.setProperty(`--ops-step-${index + 1}`, fill.toFixed(4));
});
if (activeRef.current !== active) {
activeRef.current = active;
setActive(active);
}
};
const schedule = () => {
if (rafRef.current) return;
rafRef.current = window.requestAnimationFrame(() => {
rafRef.current = 0;
apply();
});
};
window.addEventListener("scroll", schedule, { passive: true });
window.addEventListener("resize", schedule);
window.visualViewport?.addEventListener("resize", schedule);
apply();
return () => {
window.removeEventListener("scroll", schedule);
window.removeEventListener("resize", schedule);
window.visualViewport?.removeEventListener("resize", schedule);
if (rafRef.current) window.cancelAnimationFrame(rafRef.current);
};
}, []);
const goTo = (index) => {
const el = ref.current;
if (!el) return;
const total = el.offsetHeight - getScrollViewportHeight();
if (total <= 0) return;
window.scrollTo({
top: el.offsetTop + ((index + 0.08) / OPERATIONS_STEPS.length) * total,
behavior: "smooth",
});
};
const activeStep = OPERATIONS_STEPS[active];
return (
Ablauf
0{active + 1} / 04
{activeStep.title}
{activeStep.text}
{OPERATIONS_STEPS.map((step, index) => (
goTo(index)}
aria-label={`0${index + 1}: ${step.label}`}
>
0{index + 1}
{step.label}
))}
);
}
const GERMANY_MAP_PATH = "M427.9 480.1 L427.3 491.1 L423.6 497.4 L419.5 494.3 L412.1 493.8 L410 507.7 L404.2 512.6 L386.2 520.5 L380.8 526.3 L391.8 545.2 L387.5 554 L393.1 554.7 L395.4 558.5 L392.3 572.2 L382.5 565.9 L384 561.9 L381.8 558 L377 557.4 L370.2 560.7 L367 556.2 L358.9 557.1 L359 553.4 L356.2 555.2 L356 562.3 L331.8 563.4 L328.8 568.8 L322.7 569.4 L321.4 573.7 L315 577.3 L313.1 574.8 L303.7 577.5 L298.4 570.8 L299.9 568.7 L298.4 567.6 L294.2 568.8 L286.4 565.4 L282 567.5 L279.6 564.3 L279.6 577.2 L274.2 583.8 L267.9 586 L270 578.8 L264.5 579.8 L264 574.1 L258.5 566.9 L253.6 567.3 L251.3 563.5 L247.9 567.6 L243.9 568.2 L225.1 557.7 L211.9 558.7 L208.2 554.2 L204.7 556 L204.5 551.6 L201.5 549.2 L200.3 551.6 L198.8 548.5 L193.6 551.1 L190.4 556.2 L193.4 559.9 L199.9 558.7 L197.8 563.5 L196.2 561.2 L188.8 564.1 L183.5 561.2 L175.1 565.5 L165.4 563 L159.4 566.7 L156.2 565.2 L158.4 563 L155.2 563.8 L151.9 555.1 L156.7 536.4 L155.2 525.2 L162.4 510.2 L165 490.8 L172 480.7 L177.2 477.2 L182.1 466.5 L170.3 461.1 L157.3 460.9 L147.5 451.6 L141.5 456.1 L133 453.5 L131.4 455.9 L129.9 450.7 L125.8 448.9 L122.2 448.7 L121.7 453.1 L117.5 452.5 L108.1 433.5 L100.8 431.3 L101.1 423.4 L103.4 417.1 L107.6 413.1 L107.7 407.2 L99 404.4 L89.9 389.3 L92.2 377.6 L98.2 371.2 L102.1 370.4 L100.5 358.7 L94.8 358.3 L93.2 356.1 L96.6 349.2 L92.7 348.7 L89.3 342.2 L86.2 342.6 L84.5 337.4 L88.5 328.5 L85.7 326.9 L85.9 323.8 L80.2 324.4 L79.5 320.5 L79.3 318.9 L83 319.7 L92.2 311.1 L91.6 308.9 L88.4 309.8 L88.2 306.9 L94.8 294.5 L94.2 285.8 L89.5 279.7 L90.1 276.3 L83.1 270.1 L82.6 264.8 L89.4 261.5 L92.6 262.3 L89.8 259.2 L91.3 258.4 L100.8 263.8 L102.3 261 L106 261.8 L118.3 257.6 L121.2 252.5 L115.5 246.8 L130.7 234.8 L131.6 225.2 L128.3 219.1 L125.1 220.5 L117 218.4 L115.1 212.7 L118.3 211.5 L116.5 209.8 L118 206.1 L130.3 206.8 L132.2 192.7 L138 180.4 L138 162.9 L140.7 157.6 L145.6 158.8 L142.8 156.7 L132.8 156.4 L130.5 153.6 L131.8 144 L135.7 142.2 L133.3 138.7 L139.4 133.1 L174.7 130.1 L175.6 135.2 L180.6 141.1 L175.9 144.7 L176.7 147.1 L182.3 151.2 L184.7 151.1 L187.1 146.6 L186.1 142.8 L183.4 143.1 L185.1 136.9 L197.5 141.8 L194.7 145.8 L195.4 154.9 L195.1 146.6 L198.1 141.6 L194.6 130.7 L199 118.6 L202.7 117.1 L211 121.4 L226.3 118.5 L229.5 119.2 L242.6 138.4 L253.5 141.8 L242.6 136.9 L234.4 121.4 L228.4 117.6 L216.4 116.7 L213.4 113.9 L209.8 106.9 L217 107.3 L217.9 102.5 L215 98.8 L211 100.6 L208.9 96.7 L210.1 91.3 L215.5 87 L203 90.4 L199.6 85.5 L203.7 84.1 L201.1 83.6 L201.7 80.7 L212.1 79.9 L217.3 76.5 L217.6 73.6 L211.8 66.5 L209.4 67.1 L208.6 60.8 L203.4 57.4 L202.2 46 L212.9 45.9 L225.6 49.2 L227.8 52.7 L236.8 52.1 L242.5 48.1 L242.6 50.6 L249.2 52.3 L253.1 55.9 L258.6 54.2 L261.7 59.8 L257.8 61.7 L262.6 62.2 L262 69.8 L259.3 73.6 L253.9 75.8 L267.1 74.6 L269.8 76.8 L267.1 86.5 L270.7 80.1 L274.8 78.1 L292.9 87.5 L301.8 82.6 L310.6 82.1 L307.6 84.1 L307.6 96.4 L293.8 105.9 L299.7 112 L312.3 108.2 L315.3 113.3 L319.3 112.2 L324.7 116.1 L327.4 106.9 L329.7 106.7 L334.8 98.5 L352.3 95.7 L353.5 102.5 L352.6 99.1 L354.7 96.7 L353.2 96.5 L363.4 87.9 L371.8 74.9 L374.3 77.5 L388.7 78.7 L375.7 79.5 L371.5 83.1 L367.6 82 L364.6 90.4 L368.5 91.3 L366.4 90.4 L369.4 85.9 L378.2 80.3 L379.8 80.1 L378.4 83.1 L379.3 81.1 L385.8 84.1 L389.1 80.1 L393.7 78.7 L397.2 89.6 L404.8 92.9 L406.3 97.6 L409.9 97.2 L409 98.6 L412.6 102.5 L423.4 97.2 L427.6 102 L424.9 106.9 L431.9 114.2 L428 119.9 L437.6 126.8 L447.6 127 L445.3 130.1 L447.5 130.7 L449.3 144.3 L455.3 162.4 L451 176.8 L442.3 183.1 L441.4 190.8 L464.2 210.2 L459.9 224 L461.6 230.5 L467.2 234.4 L466 242.5 L469.3 245.7 L461.6 265 L468.1 275.3 L467.1 284.4 L477.8 291.1 L480.7 305.1 L475.9 322.4 L470.4 334.7 L468.3 335.3 L462.8 332.9 L463.5 327.5 L460.1 328.1 L461.1 323.6 L457.1 319.3 L453.4 321 L448.6 319.3 L446.4 323.2 L452.7 327.5 L451.2 330.4 L446.1 330.5 L434.2 335.9 L428.7 341.5 L416.6 342.7 L411.8 350.4 L408.3 348.2 L405.6 352 L402.4 351.5 L399.2 357.5 L392.6 357.8 L390.1 364.1 L384.2 361.4 L378.7 364.8 L370.8 365.2 L363.2 374.4 L361.6 381.3 L358.9 374.6 L351.8 370.4 L351.9 375.5 L356.1 379.8 L359.2 389.6 L368.2 394.1 L371.4 399.5 L365.2 410.9 L370.2 416.1 L376.6 433.1 L382.5 440 L387.2 439.5 L392.2 442.7 L400 455.2 L405.3 456.9 L412.3 467.5 L414.8 465.7 L418.8 467.4 L427.1 479.2 L427.9 480.1 Z M422.8 81.7 L425.8 85 L423.9 89.7 L423.4 87.9 L420.7 88.4 L423.4 85.9 L419.2 87 L421.3 84.4 L413.3 85.5 L407.9 89.9 L407.8 91.8 L410.5 90.6 L410 93.3 L405.8 91.7 L406.9 89.4 L403.9 91.3 L401.2 88.4 L398.8 88.9 L400 87.5 L397.3 85.5 L398.7 82.7 L403.9 82.1 L401.5 78.9 L399.1 79.2 L404.2 75.3 L398.5 71 L403.6 70.2 L405.2 72.6 L408.4 68 L407.5 72.4 L408.7 69.5 L411.1 74.6 L414.4 74.9 L415 72.9 L415 69 L411.5 70 L408.4 66.1 L403.3 69.5 L405 64 L402.3 63.2 L410.5 60.7 L411.7 61.7 L409 64.4 L410.8 68 L420.2 68 L421.9 71.2 L417.4 76 L418.9 80.1 L421.9 81.1 L422.8 81.7 Z M445.2 113.8 L444.8 118.1 L429 120.1 L433 116.6 L431.8 109.8 L434.8 110.2 L434.2 113.6 L435.4 112.2 L438.1 113.6 L438.2 109.1 L433.6 104.7 L431.2 108.7 L429.7 109.3 L430 105.9 L426.1 107.8 L427.9 102.3 L425.6 97.8 L427.9 97.2 L430.8 102.2 L445.2 113.8 L445.2 113.8 Z M315.8 75.5 L318.4 80.1 L309.6 80 L309 77.5 L305 77.2 L307.8 71.8 L315.1 74.4 L315.8 75.5 Z M189.1 42.3 L190.3 46.1 L201.9 46.2 L186.7 48.2 L185.7 56.9 L186.3 44.8 L189.7 36.1 L191.5 34 L193.6 35 L190.6 35.5 L192.1 36.5 L188.7 41 L189.1 42.3 Z M195.1 55.9 L199.3 57.9 L198.1 60.8 L190.6 58.8 L193.6 56 L195.1 55.9 Z M215.5 72.4 L213.2 75.8 L209.4 76.1 L208.9 73.9 L213.5 71.9 L215.5 72.4 Z";
const NETWORK_POINTS = [
{ id: "hamburg", label: "Hamburg", x: 260.6, y: 141.2, anchor: "end" },
{ id: "hannover", label: "Hannover", x: 249.1, y: 224.5, anchor: "end" },
{ id: "ruhr", label: "Rhein/Ruhr", x: 119.6, y: 291.1, anchor: "end" },
{ id: "berlin", label: "Berlin", x: 409.9, y: 214.3, anchor: "start", primary: true },
{ id: "leipzig", label: "Leipzig", x: 364.8, y: 297.9, anchor: "start" },
{ id: "frankfurt", label: "Frankfurt", x: 203.2, y: 384.9, anchor: "end", primary: true },
{ id: "nuernberg", label: "Nürnberg", x: 308, y: 431.5, anchor: "start" },
{ id: "stuttgart", label: "Stuttgart", x: 225.1, y: 479.4, anchor: "end" },
{ id: "muenchen", label: "München", x: 330.1, y: 524.8, anchor: "start", primary: true },
];
const NETWORK_LINKS = [
["hamburg", "hannover"],
["hamburg", "berlin"],
["hannover", "ruhr"],
["hannover", "berlin"],
["ruhr", "frankfurt"],
["berlin", "leipzig"],
["leipzig", "frankfurt"],
["leipzig", "nuernberg"],
["frankfurt", "nuernberg"],
["frankfurt", "stuttgart"],
["nuernberg", "muenchen"],
["stuttgart", "muenchen"],
];
const NETWORK_POINT_LOOKUP = NETWORK_POINTS.reduce((lookup, point) => {
lookup[point.id] = point;
return lookup;
}, {});
function Network() {
return (
Netzwerk
Bundesweite Abdeckung, lokale Dispositionslogik.
Ladungen laufen durch ein deutsches Depotnetz, das reagieren kann, wenn Bestand knapp wird,
ein Fahrzeug ausfällt oder sich ein Lieferfenster verschiebt.
Aktive Routen
312
Durchschn. Disposition
2,4 Std.
Deutschland-Netz
Depotpunkte und Lieferachsen
Koordiniert
Nexaro Versorgungsnetz Deutschland
Animierte Punkte und Linien verbinden deutsche Versorgungsstandorte zwischen Nord, West, Ost und Süd.
{NETWORK_LINKS.map(([fromId, toId], index) => {
const from = NETWORK_POINT_LOOKUP[fromId];
const to = NETWORK_POINT_LOOKUP[toId];
const path = `M ${from.x} ${from.y} L ${to.x} ${to.y}`;
const lineDelay = (index * 0.16).toFixed(2);
const duration = (5.4 + (index % 4) * 0.35).toFixed(2);
return (
);
})}
{NETWORK_POINTS.map((point, index) => (
{point.label}
))}
Nord-Süd-Koordination
Depotauswahl
Lieferfenster
);
}
function DeskCTA({ onQuote }) {
return (
Kontakt
Nennen Sie uns das Volumen. Wir planen die Beladung.
Das Angebot kommt über das Handelsteam zurück, mit Produktsorte, Depot, Lieferregion
und Timing abgestimmt, bevor der Vertrag in Bewegung kommt.
Angebot anfragen
Kontakt aufnehmen
);
}
function HomeSections({ onQuote }) {
return (
);
}
Object.assign(window, { HomeSections, Reveal });