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"; import { useState, useEffect, useRef } from "react";
const STEPS = [ interface Step {
"Deinen Wunschkunden klar definiert \u2014 wer er ist, was er braucht, was er schon versucht hat", title: string;
"Dein Angebot auf den Punkt gebracht \u2014 was du anbietest, welches Problem du l\u00f6st", sub: string;
"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", const STEPS: Step[] = [
"Deinen 90-Tage-Marketingplan + Entscheidung welche 2 Kan\u00e4le du fokussierst", { title: "Klare Wunschkunden-Persona", sub: "+ vollst\u00e4ndiger Marketing-Audit" },
"Deinen 4-Wochen Content-Plan + Themen die zeigen wof\u00fcr du stehst \u2014 f\u00fcr alle Plattformen", { title: "Angebot auf den Punkt", sub: "Positionierung in einem Satz \u2014 f\u00fcr alle Kan\u00e4le" },
"Deinen Launch-Plan \u2014 wie du dein Angebot aktiv \u00fcber Social Media in den Markt bringst", { title: "Deine Verkaufsseite", sub: "Vollst\u00e4ndige Struktur \u2014 fertig zum Umsetzen" },
"Video-Setup erkl\u00e4rt \u2014 professionelle Videos mit dem Handy", { title: "90-Tage-Marketingplan", sub: "+ 2 fokussierte Kan\u00e4le entschieden" },
"Dein pers\u00f6nliches Verkaufsskript f\u00fcr Direktansprache und Netzwerk", { title: "Content-Plan 4 Wochen", sub: "Was, wann und warum du postest" },
"Dein Google Business Profil optimiert + SEO-Grundlagen f\u00fcr deine Website", { 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) // Waypoints along the mountain ridge (SVG user units, viewBox 940 × 580)
const WP = [ const WP = [
{ x: 65, y: 520, lean: 8 }, { x: 65, y: 520, lean: 8 },
{ x: 155, y: 500, lean: 9 }, { x: 195, y: 488, lean: 12 },
{ x: 248, y: 477, lean: 12 }, { x: 325, y: 450, lean: 15 },
{ x: 338, y: 449, lean: 13 }, { x: 450, y: 407, lean: 17 },
{ x: 425, y: 416, lean: 16 }, { x: 565, y: 358, lean: 20 },
{ x: 508, y: 378, lean: 19 }, { x: 670, y: 303, lean: 22 },
{ x: 587, y: 334, lean: 20 }, { x: 757, y: 248, lean: 24 },
{ x: 660, y: 290, lean: 19 },
{ x: 727, y: 252, lean: 18 },
{ x: 787, y: 220, lean: 18 },
{ x: 840, y: 192, lean: 0 }, { x: 840, y: 192, lean: 0 },
] as const; ] as const;
@ -37,25 +36,24 @@ const VH = 580;
// Smooth quadratic-bezier path through all waypoints (midpoint technique) // Smooth quadratic-bezier path through all waypoints (midpoint technique)
const RIDGE = const RIDGE =
"M 65 520" + "M 65 520" +
" Q 110 510 155 500" + " Q 130 504 195 488" +
" Q 201.5 488.5 248 477" + " Q 260 469 325 450" +
" Q 293 463 338 449" + " Q 387.5 428.5 450 407" +
" Q 381.5 432.5 425 416" + " Q 507.5 382.5 565 358" +
" Q 466.5 397 508 378" + " Q 617.5 330.5 670 303" +
" Q 547.5 356 587 334" + " Q 713.5 275.5 757 248" +
" Q 623.5 312 660 290" + " Q 798.5 220 840 192";
" Q 693.5 271 727 252" +
" Q 757 236 787 220" +
" Q 813.5 206 840 192";
// Filled mountain silhouette (ridge + right slope + base) // Filled mountain silhouette (ridge + right slope + base)
const FILL = const FILL =
`M 0 ${VH} L 0 540 L ` + `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`; ` L 940 265 L 940 ${VH} Z`;
const CARD_W = 234; const CARD_W = 234;
const CARD_H = 128; const CARD_H = 110;
const SUMMIT_W = 294;
const SUMMIT_H = 80;
export default function MountainClimb() { export default function MountainClimb() {
const [step, setStep] = useState(-1); const [step, setStep] = useState(-1);
@ -90,12 +88,16 @@ export default function MountainClimb() {
const atSummit = step === STEPS.length - 1; const atSummit = step === STEPS.length - 1;
const wp = step >= 0 ? WP[step] : WP[0]; 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 rawCX = wp.x - CARD_W / 2;
const cardX = Math.min(Math.max(rawCX, 8), VW - CARD_W - 8); 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); 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 = () => { const replay = () => {
started.current = true; started.current = true;
setStep(0); setStep(0);
@ -108,10 +110,10 @@ export default function MountainClimb() {
<div className="text-center mb-12"> <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="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" /> <span className="w-2 h-2 rounded-full bg-indigo-500 animate-pulse" />
Komplettpaket Deine Ergebnisse
</span> </span>
<h2 className="mt-4 text-3xl md:text-4xl font-extrabold text-slate-900"> <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> </h2>
</div> </div>
@ -182,8 +184,8 @@ export default function MountainClimb() {
</g> </g>
)} )}
{/* ── Text card ── */} {/* ── Regular step card ── */}
{step >= 0 && ( {step >= 0 && !atSummit && (
<> <>
{/* Dashed connector: card → figure head */} {/* Dashed connector: card → figure head */}
<line <line
@ -217,20 +219,75 @@ export default function MountainClimb() {
letterSpacing: "0.12em", letterSpacing: "0.12em",
textTransform: "uppercase", textTransform: "uppercase",
color: "#6366f1", color: "#6366f1",
marginBottom: "5px", marginBottom: "4px",
}} }}
> >
Schritt {step + 1} / {STEPS.length} Schritt {step + 1} / {STEPS.length}
</div> </div>
<div <div
style={{ style={{
fontSize: "12.5px", fontSize: "13px",
color: "#334155", color: "#0f172a",
lineHeight: 1.55, fontWeight: 700,
fontWeight: 500, 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>
</div> </div>
</foreignObject> </foreignObject>
@ -241,7 +298,7 @@ export default function MountainClimb() {
{/* Pause hint */} {/* Pause hint */}
{step >= 0 && !atSummit && ( {step >= 0 && !atSummit && (
<p className="text-center text-xs text-slate-400 mt-2 select-none"> <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> </p>
)} )}
@ -252,7 +309,7 @@ export default function MountainClimb() {
onClick={replay} onClick={replay}
className="text-sm text-indigo-600 border border-indigo-200 rounded-full px-5 py-2 hover:bg-indigo-50 transition-colors" 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> </button>
</div> </div>
)} )}
@ -260,12 +317,15 @@ export default function MountainClimb() {
{/* ── Mobile fallback: numbered list ── */} {/* ── Mobile fallback: numbered list ── */}
<div className="md:hidden space-y-3"> <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"> <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"> <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} {i + 1}
</span> </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>
))} ))}
</div> </div>

View file

@ -4,8 +4,7 @@ import FlipCards from "./components/FlipCards";
import MountainClimb from "./components/MountainClimb"; import MountainClimb from "./components/MountainClimb";
import { import {
CalendarIcon, GradCapIcon, UsersIcon, ClipboardIcon, CalendarIcon, GradCapIcon, UsersIcon, ClipboardIcon,
TargetIcon, LightbulbIcon, DocumentIcon, PhoneIcon, PhoneIcon, VideoCameraIcon, HandshakeIcon, MapIcon,
VideoCameraIcon, HandshakeIcon, SearchIcon, MapIcon,
PackageIcon, ChatIcon, CheckIcon, PackageIcon, ChatIcon, CheckIcon,
} from "./components/Icons"; } from "./components/Icons";
@ -178,29 +177,7 @@ export default function Home() {
{/* {/*
S3b NACH 8 WOCHEN NIMMST DU MIT S3b NACH 8 WOCHEN NIMMST DU MIT
2×4 Icon-Kacheln Mountain animation (ersetzt 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)
*/} */}
<MountainClimb /> <MountainClimb />