e4a5ec1775
- Swap the testimonial band's placeholder photo for one cropped directly
from the actual mockup pixels (mockups/einfach-produktiv_mockup_404.png)
instead of reusing an unrelated existing site asset.
- Remove the search bar — no search backend exists to wire it to, so it
was a dead decorative element.
- Add micro-interactions: main CTA arrow slides right on hover, sticky
note un-rotates on hover, help-link cards lift + icon circle inverts to
brand fill + arrow slides right on hover.
- Help-link CTAs ("Zur Startseite" etc.) now text-text-primary (black)
instead of text-brand.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
223 lines
9.7 KiB
TypeScript
223 lines
9.7 KiB
TypeScript
import type { Metadata } from "next";
|
||
import Link from "next/link";
|
||
import { Reveal, RevealGroup, RevealItem } from "./components/Reveal";
|
||
import { Footer } from "./components/Footer";
|
||
import { TrustRow } from "./components/TrustRow";
|
||
|
||
export const metadata: Metadata = {
|
||
title: "Seite nicht gefunden",
|
||
description: "Diese Seite ist gerade nicht dort, wo sie sein sollte.",
|
||
robots: { index: false, follow: true },
|
||
};
|
||
|
||
const helpLinks = [
|
||
{
|
||
href: "/",
|
||
title: "Startseite",
|
||
desc: "Zurück zu den wichtigsten Inhalten und Angeboten.",
|
||
cta: "Zur Startseite",
|
||
icon: (
|
||
<svg viewBox="0 0 24 24" className="size-6" fill="none" aria-hidden="true">
|
||
<path
|
||
d="M4 11.5 12 4l8 7.5M6 9.5V20h5v-5.5h2V20h5V9.5"
|
||
stroke="currentColor"
|
||
strokeWidth="1.6"
|
||
strokeLinecap="round"
|
||
strokeLinejoin="round"
|
||
/>
|
||
</svg>
|
||
),
|
||
},
|
||
{
|
||
href: "/blog",
|
||
title: "Im Blog stöbern",
|
||
desc: "Lass dich von Impulsen, Methoden und Gedanken inspirieren.",
|
||
cta: "Zum Blog",
|
||
icon: (
|
||
<svg viewBox="0 0 24 24" className="size-6" fill="none" aria-hidden="true">
|
||
<path
|
||
d="M6 3.5h9.5L20 8v12.5a1 1 0 0 1-1 1H6a1 1 0 0 1-1-1v-16a1 1 0 0 1 1-1Z"
|
||
stroke="currentColor"
|
||
strokeWidth="1.6"
|
||
strokeLinejoin="round"
|
||
/>
|
||
<path d="M8.5 9.5h7M8.5 13h7M8.5 16.5h4.5" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" />
|
||
</svg>
|
||
),
|
||
},
|
||
{
|
||
href: "/#werkzeuge",
|
||
title: "Werkzeuge entdecken",
|
||
desc: "Praktische Tools für mehr Fokus, Struktur und Klarheit.",
|
||
cta: "Zu den Werkzeugen",
|
||
icon: (
|
||
<svg viewBox="0 0 24 24" className="size-6" fill="none" aria-hidden="true">
|
||
<path
|
||
d="M4 9.5h16a1 1 0 0 1 1 1V19a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1v-8.5a1 1 0 0 1 1-1Z"
|
||
stroke="currentColor"
|
||
strokeWidth="1.6"
|
||
strokeLinejoin="round"
|
||
/>
|
||
<path
|
||
d="M8.5 9.5V7a2 2 0 0 1 2-2h3a2 2 0 0 1 2 2v2.5"
|
||
stroke="currentColor"
|
||
strokeWidth="1.6"
|
||
strokeLinejoin="round"
|
||
/>
|
||
</svg>
|
||
),
|
||
},
|
||
];
|
||
|
||
export default function NotFound() {
|
||
return (
|
||
<>
|
||
<main className="flex flex-col flex-1 bg-bg-base">
|
||
{/* Hero — eyebrow / Ups. / subheading / copy / CTA, sticky note beside it */}
|
||
<div className="flex flex-col lg:flex-row gap-12 lg:gap-16 items-center pt-16 pb-20 px-[var(--layout-padding-x)] w-full">
|
||
<Reveal className="flex flex-col gap-4 items-start w-full lg:flex-1 max-w-[32rem]">
|
||
<p className="font-semibold text-body-sm text-brand tracking-wide">404 – Seite nicht gefunden</p>
|
||
<p
|
||
className="font-semibold text-[3.5rem] leading-[1.05] text-text-primary"
|
||
style={{ fontFamily: "var(--font-lora)" }}
|
||
>
|
||
Ups.
|
||
</p>
|
||
<p
|
||
className="font-semibold text-h-feature text-text-primary"
|
||
style={{ fontFamily: "var(--font-lora)" }}
|
||
>
|
||
Diese Seite ist gerade nicht dort, wo sie sein sollte.
|
||
</p>
|
||
<div className="h-[0.125rem] w-8 bg-brand" />
|
||
<p className="text-body text-text-muted">
|
||
Vielleicht wurde sie verschoben, umbenannt oder es hat sich ein kleiner Tippfehler eingeschlichen.
|
||
</p>
|
||
<p className="text-body text-text-muted">Aber kein Problem – wir bringen dich gerne zurück auf Kurs.</p>
|
||
<Link
|
||
href="/"
|
||
className="group flex items-center gap-2 mt-2 px-7 py-4 rounded-sm bg-brand text-h4 font-bold text-text-primary hover:bg-brand-hover active:scale-[0.97] transition-all"
|
||
>
|
||
Zur Startseite
|
||
<svg
|
||
viewBox="0 0 20 20"
|
||
className="size-4 transition-transform duration-200 group-hover:translate-x-1"
|
||
fill="none"
|
||
aria-hidden="true"
|
||
>
|
||
<path d="M4 10h12m0 0-5-5m5 5-5 5" stroke="currentColor" strokeWidth="1.75" strokeLinecap="round" strokeLinejoin="round" />
|
||
</svg>
|
||
</Link>
|
||
</Reveal>
|
||
|
||
{/* Sticky note — drawn natively (rotated card + tape + Caveat
|
||
handwriting) rather than a cropped photo asset, since there's
|
||
no such image in /public and this reads just as well as a
|
||
coded illustration built from the same tokens (Lora for the
|
||
"404", Caveat for the handwritten line) the rest of the site
|
||
already uses for handwritten-style accents (see About.tsx's
|
||
signature quote). */}
|
||
<Reveal delay={0.15} className="w-full lg:flex-1 flex items-center justify-center">
|
||
<div className="relative w-full max-w-[22rem] aspect-square rotate-2 hover:rotate-0 rounded-sm bg-[#EDE3D0] shadow-modal p-8 flex flex-col items-center text-center transition-transform duration-300">
|
||
<div className="absolute -top-3 left-1/2 -translate-x-1/2 -rotate-3 w-16 h-6 bg-[#d8cdb8]/80" />
|
||
<p
|
||
className="font-bold text-text-primary text-[4.5rem] leading-none mt-6"
|
||
style={{ fontFamily: "var(--font-lora)" }}
|
||
>
|
||
404
|
||
</p>
|
||
<div className="h-[0.1875rem] w-24 bg-brand mt-3 mb-4" />
|
||
<p
|
||
className="text-text-primary text-[1.75rem] leading-[1.15]"
|
||
style={{ fontFamily: "var(--font-caveat)" }}
|
||
>
|
||
Nicht hier.
|
||
<br />
|
||
Aber dein Ziel ist
|
||
<br />
|
||
sicher nicht weit.
|
||
</p>
|
||
<svg viewBox="0 0 32 32" className="size-8 mt-4 text-text-primary" fill="none" aria-hidden="true">
|
||
<circle cx="11" cy="13" r="1.6" fill="currentColor" />
|
||
<circle cx="21" cy="13" r="1.6" fill="currentColor" />
|
||
<path d="M9 19c1.8 2.4 4.4 3.6 7 3.6s5.2-1.2 7-3.6" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" />
|
||
</svg>
|
||
</div>
|
||
</Reveal>
|
||
</div>
|
||
|
||
{/* Help links */}
|
||
<div className="flex flex-col gap-10 items-center pb-16 px-[var(--layout-padding-x)] w-full">
|
||
<Reveal className="flex flex-col items-center gap-2">
|
||
<p
|
||
className="font-semibold text-h-small text-text-primary"
|
||
style={{ fontFamily: "var(--font-lora)" }}
|
||
>
|
||
Vielleicht hilft dir das weiter:
|
||
</p>
|
||
<div className="h-[0.125rem] w-8 bg-brand" />
|
||
</Reveal>
|
||
|
||
<RevealGroup className="grid grid-cols-1 md:grid-cols-3 gap-10 md:gap-8 w-full max-w-[64rem] divide-y md:divide-y-0 md:divide-x divide-border">
|
||
{helpLinks.map((link) => (
|
||
<RevealItem
|
||
key={link.href}
|
||
className="group flex flex-col items-center text-center gap-3 pt-10 md:pt-0 first:pt-0 px-4 transition-transform duration-200 hover:-translate-y-1"
|
||
>
|
||
<div className="flex size-14 items-center justify-center rounded-full bg-bg-muted text-brand transition-colors duration-200 group-hover:bg-brand group-hover:text-text-primary">
|
||
{link.icon}
|
||
</div>
|
||
<p className="font-semibold text-body text-text-primary">{link.title}</p>
|
||
<p className="text-body-sm text-text-muted">{link.desc}</p>
|
||
<Link href={link.href} className="flex items-center gap-1.5 text-body-sm font-semibold text-text-primary hover:underline">
|
||
{link.cta}
|
||
<svg
|
||
viewBox="0 0 20 20"
|
||
className="size-3.5 transition-transform duration-200 group-hover:translate-x-1"
|
||
fill="none"
|
||
aria-hidden="true"
|
||
>
|
||
<path d="M4 10h12m0 0-5-5m5 5-5 5" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
|
||
</svg>
|
||
</Link>
|
||
</RevealItem>
|
||
))}
|
||
</RevealGroup>
|
||
</div>
|
||
|
||
{/* Testimonial band — photo bleeds to the viewport edge, gradient
|
||
fade into bg-base on its trailing edge instead of a hard cut,
|
||
same idea as page-bestellbestaetigung's photo+quote pattern.
|
||
404-testimonial-photo.jpg is cropped directly from the actual
|
||
mockup pixels (mockups/einfach-produktiv_mockup_404.png) rather
|
||
than reusing an unrelated existing asset — same real-photo
|
||
extraction convention the Figma rebuild used, just done on the
|
||
flat mockup image instead of in Figma. */}
|
||
<Reveal className="relative w-full flex items-stretch min-h-[16rem] bg-bg-muted overflow-hidden">
|
||
<div className="relative w-full md:w-[45%] shrink-0">
|
||
<img
|
||
alt=""
|
||
src="/404-testimonial-photo.jpg"
|
||
className="absolute inset-0 w-full h-full object-cover"
|
||
/>
|
||
<div className="hidden md:block absolute inset-y-0 right-0 w-40 bg-gradient-to-l from-bg-muted to-transparent" />
|
||
</div>
|
||
<div className="flex-1 flex flex-col justify-center gap-3 px-8 md:px-16 py-12">
|
||
<p
|
||
className="font-semibold text-h-section text-text-primary leading-[1.3] max-w-[28rem]"
|
||
style={{ fontFamily: "var(--font-lora)" }}
|
||
>
|
||
„Manchmal führt der falsche Weg zu neuen klaren Gedanken.“
|
||
</p>
|
||
<div className="h-[0.125rem] w-8 bg-brand" />
|
||
<p className="text-body text-text-muted">Björn</p>
|
||
</div>
|
||
</Reveal>
|
||
|
||
<TrustRow />
|
||
</main>
|
||
<Footer />
|
||
</>
|
||
);
|
||
}
|