"use client";
import { AnimatePresence, motion, useScroll, useTransform } from "motion/react";
import { useEffect, useRef, useState } from "react";
import { BadgeCheck, CreditCard, ShieldCheck, Server, MapPin } from "lucide-react";
import { Eyebrow, WaitlistForm } from "./ui";
import { KineticLine, Reveal, useReducedMotion } from "./motion";
import { ShowcaseStage } from "./mockup";
const TRUST = [
{ label: "Zahlungen über Stripe", Icon: CreditCard },
{ label: "DSGVO-konform", Icon: ShieldCheck },
{ label: "Hosting in Frankfurt", Icon: MapPin },
{ label: "GoBD-konforme Rechnungen", Icon: BadgeCheck },
{ label: "Entwickelt in Deutschland", Icon: Server },
];
/**
* Ambient backdrop: a slow aurora wash plus amber and navy blobs.
* This is what the glass surfaces in front actually blur — without it
* the backdrop-filter has nothing to work with.
*/
function Ambience() {
const reduced = useReducedMotion();
const { scrollY } = useScroll();
const glowY = useTransform(scrollY, [0, 800], [0, 160]);
return (
);
}
const REPLACED = [
"die Excel-Tabelle",
"die DM-Flut",
"den Zettel am Empfang",
"das Nachfassen per WhatsApp",
"die Bar-Kasse",
];
/** Cycles through what Kumasy replaces, one word swap at a time. */
function ReplacedWords() {
const reduced = useReducedMotion();
const [index, setIndex] = useState(0);
useEffect(() => {
if (reduced) return;
const id = window.setInterval(
() => setIndex((i) => (i + 1) % REPLACED.length),
2600,
);
return () => window.clearInterval(id);
}, [reduced]);
if (reduced) {
// Static fallback: name them all rather than animating through them.
return {REPLACED.join(", ")}.;
}
return (
// Fixed height + overflow clip so the swap never reflows the line.
{REPLACED[index]}
);
}
export function Hero() {
const ref = useRef(null);
const reduced = useReducedMotion();
const { scrollYProgress } = useScroll({
target: ref,
offset: ["start start", "end start"],
});
const copyY = useTransform(scrollYProgress, [0, 1], [0, -90]);
const copyOpacity = useTransform(scrollYProgress, [0, 0.65], [1, 0]);
return (
Pilotphase · Zugang über Warteliste
{/* Per-character entrance. The carries the readable text for
assistive tech; the animated spans are aria-hidden. */}
{/* The floor is 2.1rem, not 2.75rem: the longest line ("und
bezahlen sich") has to fit 321px of usable width on a 353px
Samsung viewport. 10.2vw carries it from there up to the
5.25rem ceiling. */}
Deine Kurse füllen und bezahlen sich von selbst.
{/* Rises as one block so the gradient spans the word — see
KineticLine for why this can't be per-character. The delay
continues the stagger of "von " so the line reads as one. */}
Kumasy bündelt Kurse, Räume, Trainer, Buchungen und Zahlungen in
einer Oberfläche. Deine Teilnehmer:innen buchen und bezahlen in
unter zwei Minuten selbst — ohne DM, ohne Rückfrage, ohne Excel.
{TRUST.map(({ label, Icon }) => (
-
{label}
))}
{/* One live line naming what Kumasy replaces — it keeps the hero
moving after the entrance without adding another surface. */}
Ersetzt
);
}