"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

); }