Mountain: 8 shorter steps + summit celebration, replace Kacheln section

- Replace 11 full-sentence steps with 8 two-line pairs (title + sub)
- Reduce waypoints from 11 to 8, recalculate smooth bezier ridge
- Summit card: gradient indigo→violet bubble with celebration text
- Figure lifts flag and bounces at summit (atSummit)
- Move MountainClimb into "Nach 8 Wochen nimmst du mit:" section
- Remove redundant static IconCard grid (8 Kacheln)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Athena 2026-04-30 23:58:18 +02:00
parent badba0a9f7
commit 6afb4151cf
2 changed files with 112 additions and 75 deletions

View file

@ -2,32 +2,31 @@
import { useState, useEffect, useRef } from "react";
const STEPS = [
"Deinen Wunschkunden klar definiert \u2014 wer er ist, was er braucht, was er schon versucht hat",
"Dein Angebot auf den Punkt gebracht \u2014 was du anbietest, welches Problem du l\u00f6st",
"Deine Positionierung in einem Satz \u2014 klar, sofort verst\u00e4ndlich, f\u00fcr alle Kan\u00e4le nutzbar",
"Die komplette Struktur f\u00fcr deine Verkaufsseite \u2014 mit Feedback zur Umsetzung",
"Deine Marketing-Systemkarte \u2014 wie Sichtbarkeit, Vertrauen, Anfrage und Kauf zusammenh\u00e4ngen",
"Deinen 90-Tage-Marketingplan + Entscheidung welche 2 Kan\u00e4le du fokussierst",
"Deinen 4-Wochen Content-Plan + Themen die zeigen wof\u00fcr du stehst \u2014 f\u00fcr alle Plattformen",
"Deinen Launch-Plan \u2014 wie du dein Angebot aktiv \u00fcber Social Media in den Markt bringst",
"Video-Setup erkl\u00e4rt \u2014 professionelle Videos mit dem Handy",
"Dein pers\u00f6nliches Verkaufsskript f\u00fcr Direktansprache und Netzwerk",
"Dein Google Business Profil optimiert + SEO-Grundlagen f\u00fcr deine Website",
interface Step {
title: string;
sub: string;
}
const STEPS: Step[] = [
{ title: "Klare Wunschkunden-Persona", sub: "+ vollst\u00e4ndiger Marketing-Audit" },
{ title: "Angebot auf den Punkt", sub: "Positionierung in einem Satz \u2014 f\u00fcr alle Kan\u00e4le" },
{ title: "Deine Verkaufsseite", sub: "Vollst\u00e4ndige Struktur \u2014 fertig zum Umsetzen" },
{ title: "90-Tage-Marketingplan", sub: "+ 2 fokussierte Kan\u00e4le entschieden" },
{ title: "Content-Plan 4 Wochen", sub: "Was, wann und warum du postest" },
{ title: "Social Media Verkauf", sub: "+ professionelles Video-Setup mit dem Handy" },
{ title: "Dein Verkaufsskript", sub: "F\u00fcr Direktansprache und Netzwerkveranstaltungen" },
{ title: "Google Business optimiert", sub: "+ SEO-Grundlagen f\u00fcr deine Website" },
];
// Waypoints along the mountain ridge (SVG user units, viewBox 940 × 580)
const WP = [
{ x: 65, y: 520, lean: 8 },
{ x: 155, y: 500, lean: 9 },
{ x: 248, y: 477, lean: 12 },
{ x: 338, y: 449, lean: 13 },
{ x: 425, y: 416, lean: 16 },
{ x: 508, y: 378, lean: 19 },
{ x: 587, y: 334, lean: 20 },
{ x: 660, y: 290, lean: 19 },
{ x: 727, y: 252, lean: 18 },
{ x: 787, y: 220, lean: 18 },
{ x: 65, y: 520, lean: 8 },
{ x: 195, y: 488, lean: 12 },
{ x: 325, y: 450, lean: 15 },
{ x: 450, y: 407, lean: 17 },
{ x: 565, y: 358, lean: 20 },
{ x: 670, y: 303, lean: 22 },
{ x: 757, y: 248, lean: 24 },
{ x: 840, y: 192, lean: 0 },
] as const;
@ -37,25 +36,24 @@ const VH = 580;
// Smooth quadratic-bezier path through all waypoints (midpoint technique)
const RIDGE =
"M 65 520" +
" Q 110 510 155 500" +
" Q 201.5 488.5 248 477" +
" Q 293 463 338 449" +
" Q 381.5 432.5 425 416" +
" Q 466.5 397 508 378" +
" Q 547.5 356 587 334" +
" Q 623.5 312 660 290" +
" Q 693.5 271 727 252" +
" Q 757 236 787 220" +
" Q 813.5 206 840 192";
" Q 130 504 195 488" +
" Q 260 469 325 450" +
" Q 387.5 428.5 450 407" +
" Q 507.5 382.5 565 358" +
" Q 617.5 330.5 670 303" +
" Q 713.5 275.5 757 248" +
" Q 798.5 220 840 192";
// Filled mountain silhouette (ridge + right slope + base)
const FILL =
`M 0 ${VH} L 0 540 L ` +
RIDGE.slice(2) + // "65 520 Q …" — continues from first waypoint to summit
RIDGE.slice(2) +
` L 940 265 L 940 ${VH} Z`;
const CARD_W = 234;
const CARD_H = 128;
const CARD_H = 110;
const SUMMIT_W = 294;
const SUMMIT_H = 80;
export default function MountainClimb() {
const [step, setStep] = useState(-1);
@ -90,12 +88,16 @@ export default function MountainClimb() {
const atSummit = step === STEPS.length - 1;
const wp = step >= 0 ? WP[step] : WP[0];
// Card x: centred on person, clamped inside viewBox
// Regular card positioning
const rawCX = wp.x - CARD_W / 2;
const cardX = Math.min(Math.max(rawCX, 8), VW - CARD_W - 8);
// Card y: above figure head (figure is 3× scaled → head at ~87 SVG units above foot)
const cardY = Math.max(wp.y - CARD_H - 110, 4);
// Summit card positioning
const summitRawCX = wp.x - SUMMIT_W / 2;
const summitCardX = Math.min(Math.max(summitRawCX, 8), VW - SUMMIT_W - 8);
const summitCardY = Math.max(wp.y - SUMMIT_H - 120, 4);
const replay = () => {
started.current = true;
setStep(0);
@ -108,10 +110,10 @@ export default function MountainClimb() {
<div className="text-center mb-12">
<span className="inline-flex items-center gap-2 bg-indigo-50 text-indigo-700 text-xs font-bold uppercase tracking-widest rounded-full px-4 py-2 border border-indigo-100">
<span className="w-2 h-2 rounded-full bg-indigo-500 animate-pulse" />
Komplettpaket
Deine Ergebnisse
</span>
<h2 className="mt-4 text-3xl md:text-4xl font-extrabold text-slate-900">
Was du in 8 Wochen baust und mit nach Hause nimmst
Nach 8 Wochen nimmst du mit:
</h2>
</div>
@ -182,8 +184,8 @@ export default function MountainClimb() {
</g>
)}
{/* ── Text card ── */}
{step >= 0 && (
{/* ── Regular step card ── */}
{step >= 0 && !atSummit && (
<>
{/* Dashed connector: card → figure head */}
<line
@ -217,20 +219,75 @@ export default function MountainClimb() {
letterSpacing: "0.12em",
textTransform: "uppercase",
color: "#6366f1",
marginBottom: "5px",
marginBottom: "4px",
}}
>
Schritt {step + 1} / {STEPS.length}
</div>
<div
style={{
fontSize: "12.5px",
color: "#334155",
lineHeight: 1.55,
fontWeight: 500,
fontSize: "13px",
color: "#0f172a",
fontWeight: 700,
lineHeight: 1.3,
marginBottom: "4px",
}}
>
{STEPS[step]}
{STEPS[step].title}
</div>
<div
style={{
fontSize: "11px",
color: "#64748b",
lineHeight: 1.4,
}}
>
{STEPS[step].sub}
</div>
</div>
</foreignObject>
</>
)}
{/* ── Summit celebration card ── */}
{atSummit && (
<>
<line
x1={summitCardX + SUMMIT_W / 2}
y1={summitCardY + SUMMIT_H}
x2={wp.x}
y2={wp.y - 90}
stroke="#a5b4fc"
strokeWidth="1.5"
strokeDasharray="4 3"
/>
<foreignObject
key="summit"
x={summitCardX}
y={summitCardY}
width={SUMMIT_W}
height={SUMMIT_H}
className="mc-fade-in"
style={{ overflow: "visible" }}
>
<div
style={{
background: "linear-gradient(135deg, #6366f1, #8b5cf6)",
borderRadius: "14px",
padding: "16px 18px",
boxShadow: "0 8px 32px rgba(99,102,241,0.45)",
textAlign: "center",
}}
>
<div
style={{
fontSize: "15px",
fontWeight: 800,
color: "#ffffff",
lineHeight: 1.35,
}}
>
Ich habe jetzt ein Kundengewinnungssystem
</div>
</div>
</foreignObject>
@ -241,7 +298,7 @@ export default function MountainClimb() {
{/* Pause hint */}
{step >= 0 && !atSummit && (
<p className="text-center text-xs text-slate-400 mt-2 select-none">
{paused ? "▶ Klicken zum Fortsetzen" : "⏸ Klicken zum Pausieren"}
{paused ? "\u25B6 Klicken zum Fortsetzen" : "\u23F8 Klicken zum Pausieren"}
</p>
)}
@ -252,7 +309,7 @@ export default function MountainClimb() {
onClick={replay}
className="text-sm text-indigo-600 border border-indigo-200 rounded-full px-5 py-2 hover:bg-indigo-50 transition-colors"
>
Nochmal ansehen
Nochmal ansehen \u21BA
</button>
</div>
)}
@ -260,12 +317,15 @@ export default function MountainClimb() {
{/* ── Mobile fallback: numbered list ── */}
<div className="md:hidden space-y-3">
{STEPS.map((text, i) => (
{STEPS.map((s, i) => (
<div key={i} className="mc-card p-4 flex items-start gap-3">
<span className="w-7 h-7 rounded-full bg-gradient-to-br from-indigo-500 to-violet-500 text-white text-xs font-bold flex items-center justify-center flex-shrink-0 mt-0.5">
{i + 1}
</span>
<p className="text-slate-700 text-sm leading-relaxed">{text}</p>
<div>
<p className="text-slate-700 text-sm font-semibold leading-snug">{s.title}</p>
<p className="text-slate-500 text-xs leading-relaxed mt-0.5">{s.sub}</p>
</div>
</div>
))}
</div>

View file

@ -4,8 +4,7 @@ import FlipCards from "./components/FlipCards";
import MountainClimb from "./components/MountainClimb";
import {
CalendarIcon, GradCapIcon, UsersIcon, ClipboardIcon,
TargetIcon, LightbulbIcon, DocumentIcon, PhoneIcon,
VideoCameraIcon, HandshakeIcon, SearchIcon, MapIcon,
PhoneIcon, VideoCameraIcon, HandshakeIcon, MapIcon,
PackageIcon, ChatIcon, CheckIcon,
} from "./components/Icons";
@ -178,29 +177,7 @@ export default function Home() {
{/*
S3b NACH 8 WOCHEN NIMMST DU MIT
2×4 Icon-Kacheln
*/}
<section className="py-20 bg-white">
<div className="max-w-5xl mx-auto px-6">
<div className="text-center mb-12">
<Pill>Deine Ergebnisse</Pill>
<h2 className="mt-4 text-3xl md:text-4xl font-extrabold text-slate-900">Nach 8 Wochen nimmst du mit:</h2>
</div>
<div className="grid grid-cols-2 md:grid-cols-4 gap-5">
<IconCard icon={<TargetIcon className="w-7 h-7 text-white" />} title="Klare Wunschkunden-Persona" sub="+ vollständiger Marketing-Audit" />
<IconCard icon={<LightbulbIcon className="w-7 h-7 text-white" />} title="Angebot auf den Punkt" sub="Positionierung in einem Satz — für alle Kanäle" />
<IconCard icon={<DocumentIcon className="w-7 h-7 text-white" />} title="Deine Verkaufsseite" sub="Vollständige Struktur — fertig zum Umsetzen" />
<IconCard icon={<CalendarIcon className="w-7 h-7 text-white" />} title="90-Tage-Marketingplan" sub="+ 2 fokussierte Kanäle entschieden" />
<IconCard icon={<PhoneIcon className="w-7 h-7 text-white" />} title="Content-Plan 4 Wochen" sub="Was, wann und warum du postest" />
<IconCard icon={<VideoCameraIcon className="w-7 h-7 text-white" />} title="Social Media Verkauf" sub="+ professionelles Video-Setup mit dem Handy" />
<IconCard icon={<HandshakeIcon className="w-7 h-7 text-white" />} title="Dein Verkaufsskript" sub="Für Direktansprache und Netzwerkveranstaltungen" />
<IconCard icon={<SearchIcon className="w-7 h-7 text-white" />} title="Google Business optimiert" sub="+ SEO-Grundlagen für deine Website" />
</div>
</div>
</section>
{/*
S4 WAS DU BAUST (Mountain animation)
Mountain animation (ersetzt Kacheln)
*/}
<MountainClimb />