Redesign im Stil von crispmtl.com: minimalistisch, Foto-Hero, weniger CTAs

- Hell mit feinen Rasterlinien, breite Versal-Headlines (Archivo Expanded),
  kleine Serifen-Labels, eckige Buttons mit Füll-/Text-Roll-Hover
- Hero: Foto aus dem Salon statt animiertem Hintergrund, eine Headline,
  ein Button; "Termin buchen" oben rechts nur noch als Textlink
- Chrom-Wortmarke, Seidenhintergrund, Laufband, Kreis-Badge, großer
  Schluss-CTA und mobile Buchungsleiste entfernt; deutlich weniger Text
- Neue interaktive Elemente: Menü-Overlay mit Bildwechsel pro Link,
  Team als Namensliste mit Porträt-Wisch-Übergang, Preise als Akkordeon
  mit Team-Thumbnails, Footer mit Fotoraster zwischen den Wörtern
- Bilder aus den echten Salon-Fotos (Logo-Wand), neues Favicon/OG-Bild

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KBHsCnWNXAB2Le3gAEsivF
This commit is contained in:
Claude committed 2026-09-29 12:41:03 +00:00
1 parent f21d79c08d
commit c25a3f9381
49 files changed
+815 -1494

No files matched your search

+68
View File
@@ -0,0 +1,68 @@
import { useState } from 'react'
import { team } from '../data/salon'
import { cn } from '../lib/cn'
/**
* Team als große Namensliste — das Porträt daneben wechselt beim Überfahren
* (auf dem Handy per Tippen) und schiebt sich von unten ins Bild.
*/
export function TeamList() {
// `previous` bleibt sichtbar, bis das neue Bild darübergeglitten ist
const [{ active, previous }, setSelection] = useState({ active: 0, previous: 0 })
const select = (i: number) => setSelection((s) => (s.active === i ? s : { active: i, previous: s.active }))
const current = team[active]
return (
<section id="team" className="border-t border-ink/10 px-4 py-24 md:px-8 md:py-36">
<div className="mini flex justify-between gap-6">
<span>Team</span>
<span className="text-right" aria-live="polite">
{current.name} — {current.role}
</span>
</div>
<div className="mt-10 grid gap-8 md:mt-14 md:grid-cols-2">
<ul className="order-2 md:order-1">
{team.map((m, i) => (
<li key={m.key}>
<button
type="button"
aria-pressed={active === i}
onMouseEnter={() => select(i)}
onFocus={() => select(i)}
onClick={() => select(i)}
className={cn(
'display block cursor-pointer py-0.5 text-left text-[clamp(2.6rem,6.5vw,6rem)] transition-opacity duration-300',
active === i ? 'opacity-100' : 'opacity-25 hover:opacity-60',
)}
>
{m.short}
</button>
</li>
))}
</ul>
<div className="relative order-1 aspect-square overflow-hidden bg-ink md:order-2 md:aspect-auto md:min-h-[32rem]">
{team.map((m, i) => (
<img
key={m.key}
src={m.photo}
alt={i === active ? `Porträt: ${m.name}` : ''}
loading="lazy"
decoding="async"
className={cn(
'absolute inset-0 size-full object-cover',
i === active
? 'z-20 [clip-path:inset(0_0_0_0)] transition-[clip-path] duration-700 ease-out-expo'
: i === previous
? 'z-10 [clip-path:inset(0_0_0_0)]'
: 'z-0 [clip-path:inset(100%_0_0_0)]',
)}
/>
))}
</div>
</div>
</section>
)
}