feat(marketing-website): add BreakPilot marketing website with CMP integration

Multi-page marketing website positioned as "Deterministic Regulatory Engineering Platform":
- 7 pages: Home, Plattform, CE-Prozess, Product Compliance, Architektur, Team, Preise
- Platform Bridge animation (adapted from pitch-deck USP slide)
- Cookie-Banner with consent-service integration (breakpilot-marketing site)
- DE/EN language toggle + Dark/Light theme
- Docker service on port 3014

[guardrail-change] PlatformBridgeSection.tsx added to loc-exceptions (816 LOC, SVG animation)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Benjamin Admin
2026-05-10 22:41:00 +02:00
parent 937eca6b77
commit d13f4511cb
68 changed files with 11493 additions and 0 deletions
@@ -0,0 +1,295 @@
'use client'
import { useState, useRef, useEffect } from 'react'
import { motion, AnimatePresence } from 'framer-motion'
import { X, Send, Bot, User, Sparkles, Maximize2, Minimize2 } from 'lucide-react'
import { t } from '@/lib/content'
import { useApp } from '@/lib/context'
interface ChatMessage {
role: 'user' | 'assistant'
content: string
}
export default function ChatFAB() {
const { lang } = useApp()
const i = t(lang)
const [isOpen, setIsOpen] = useState(false)
const [isExpanded, setIsExpanded] = useState(false)
const [messages, setMessages] = useState<ChatMessage[]>([])
const [input, setInput] = useState('')
const [isStreaming, setIsStreaming] = useState(false)
const [isWaiting, setIsWaiting] = useState(false)
const messagesEndRef = useRef<HTMLDivElement>(null)
const inputRef = useRef<HTMLInputElement>(null)
const abortRef = useRef<AbortController | null>(null)
useEffect(() => {
messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' })
}, [messages])
useEffect(() => {
if (isOpen && inputRef.current) {
setTimeout(() => inputRef.current?.focus(), 200)
}
}, [isOpen])
async function sendMessage(text?: string) {
const message = text || input.trim()
if (!message || isStreaming) return
setInput('')
setMessages(prev => [...prev, { role: 'user', content: message }])
setIsStreaming(true)
setIsWaiting(true)
abortRef.current = new AbortController()
try {
const res = await fetch('/api/chat', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
message,
history: messages.slice(-10),
}),
signal: abortRef.current.signal,
})
if (!res.ok) throw new Error(`HTTP ${res.status}`)
const reader = res.body!.getReader()
const decoder = new TextDecoder()
let content = ''
let firstChunk = true
while (true) {
const { done, value } = await reader.read()
if (done) break
content += decoder.decode(value, { stream: true })
if (firstChunk) {
firstChunk = false
setIsWaiting(false)
setMessages(prev => [...prev, { role: 'assistant', content }])
} else {
const currentText = content
setMessages(prev => {
const updated = [...prev]
updated[updated.length - 1] = { role: 'assistant', content: currentText }
return updated
})
}
}
} catch (err: unknown) {
if (err instanceof Error && err.name === 'AbortError') return
setIsWaiting(false)
setMessages(prev => [
...prev,
{ role: 'assistant', content: i.chat.error },
])
} finally {
setIsStreaming(false)
setIsWaiting(false)
abortRef.current = null
}
}
function stopGeneration() {
if (abortRef.current) {
abortRef.current.abort()
setIsStreaming(false)
}
}
return (
<>
{/* FAB Button */}
<AnimatePresence>
{!isOpen && (
<motion.button
initial={{ scale: 0 }}
animate={{ scale: 1 }}
exit={{ scale: 0 }}
whileHover={{ scale: 1.1 }}
whileTap={{ scale: 0.95 }}
onClick={() => setIsOpen(true)}
className="fixed bottom-6 right-[5.5rem] z-50 w-14 h-14 rounded-full
bg-accent-electric hover:bg-blue-500 text-white
flex items-center justify-center shadow-lg shadow-blue-600/30
transition-colors"
aria-label="Compliance Agent oeffnen"
>
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<path d="M21 15a2 2 0 01-2 2H7l-4 4V5a2 2 0 012-2h14a2 2 0 012 2z" />
<circle cx="9" cy="10" r="1" fill="currentColor" />
<circle cx="12" cy="10" r="1" fill="currentColor" />
<circle cx="15" cy="10" r="1" fill="currentColor" />
</svg>
</motion.button>
)}
</AnimatePresence>
{/* Chat Panel */}
<AnimatePresence>
{isOpen && (
<motion.div
initial={{ opacity: 0, scale: 0.9, y: 20 }}
animate={{ opacity: 1, scale: 1, y: 0 }}
exit={{ opacity: 0, scale: 0.9, y: 20 }}
transition={{ duration: 0.2 }}
className={`fixed bottom-6 right-6 z-50
${isExpanded ? 'w-[700px] h-[80vh]' : 'w-[400px] h-[520px]'}
rounded-2xl overflow-hidden
bg-black/90 backdrop-blur-xl border border-white/10
shadow-2xl shadow-black/50 flex flex-col
transition-all duration-200`}
>
{/* Header */}
<div className="flex items-center justify-between px-4 py-3 border-b border-white/10 shrink-0">
<div className="flex items-center gap-2">
<div className="w-7 h-7 rounded-full bg-accent-electric/20 flex items-center justify-center">
<Bot className="w-4 h-4 text-accent-electric" />
</div>
<div>
<span className="text-sm font-semibold text-white">{i.chat.title}</span>
<span className="text-xs text-white/30 ml-2">
{isStreaming ? i.chat.responding : i.chat.online}
</span>
</div>
</div>
<div className="flex items-center gap-1">
<button
onClick={() => setIsExpanded(prev => !prev)}
className="w-7 h-7 rounded-full bg-white/10 flex items-center justify-center hover:bg-white/20 transition-colors"
>
{isExpanded ? <Minimize2 className="w-3.5 h-3.5 text-white/60" /> : <Maximize2 className="w-3.5 h-3.5 text-white/60" />}
</button>
<button
onClick={() => setIsOpen(false)}
className="w-7 h-7 rounded-full bg-white/10 flex items-center justify-center hover:bg-white/20 transition-colors"
>
<X className="w-4 h-4 text-white/60" />
</button>
</div>
</div>
{/* Messages */}
<div className="flex-1 overflow-y-auto px-4 py-3 space-y-3">
{messages.length === 0 && (
<div className="space-y-2">
<div className="flex items-center gap-2 text-white/40 text-xs mb-3">
<Sparkles className="w-3.5 h-3.5" />
<span>{i.chat.ask}</span>
</div>
{i.chat.suggestions.map((q, idx) => (
<motion.button
key={idx}
initial={{ opacity: 0, y: 8 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 0.1 + idx * 0.08 }}
onClick={() => sendMessage(q)}
className="block w-full text-left px-3 py-2.5 rounded-xl
bg-white/[0.05] border border-white/10
hover:bg-white/[0.1] transition-colors
text-xs text-white/70 hover:text-white"
>
{q}
</motion.button>
))}
</div>
)}
{/* Waiting indicator */}
<AnimatePresence>
{isWaiting && (
<motion.div
initial={{ opacity: 0, y: 6 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0 }}
className="flex gap-2.5"
>
<div className="w-7 h-7 rounded-full bg-accent-electric/20 flex items-center justify-center shrink-0 mt-0.5">
<Bot className="w-3.5 h-3.5 text-accent-electric" />
</div>
<div className="bg-white/[0.06] rounded-2xl px-3.5 py-3 flex items-center gap-1">
{[0, 1, 2].map(dotIdx => (
<motion.span
key={dotIdx}
className="block w-1.5 h-1.5 rounded-full bg-accent-electric/70"
animate={{ opacity: [0.3, 1, 0.3], y: [0, -3, 0] }}
transition={{ duration: 0.7, repeat: Infinity, delay: dotIdx * 0.15 }}
/>
))}
</div>
</motion.div>
)}
</AnimatePresence>
{messages.map((msg, idx) => (
<div key={idx} className={`flex gap-2.5 ${msg.role === 'user' ? 'justify-end' : ''}`}>
{msg.role === 'assistant' && (
<div className="w-7 h-7 rounded-full bg-accent-electric/20 flex items-center justify-center shrink-0 mt-0.5">
<Bot className="w-3.5 h-3.5 text-accent-electric" />
</div>
)}
<div className={`max-w-[85%] rounded-2xl px-3.5 py-2.5 text-xs leading-relaxed ${
msg.role === 'user' ? 'bg-accent-electric/20 text-white' : 'bg-white/[0.06] text-white/80'
}`}>
<div className="whitespace-pre-wrap">{msg.content}</div>
{isStreaming && idx === messages.length - 1 && msg.role === 'assistant' && (
<span className="inline-block w-1.5 h-3.5 bg-accent-electric animate-pulse ml-0.5" />
)}
</div>
{msg.role === 'user' && (
<div className="w-7 h-7 rounded-full bg-white/10 flex items-center justify-center shrink-0 mt-0.5">
<User className="w-3.5 h-3.5 text-white/60" />
</div>
)}
</div>
))}
<div ref={messagesEndRef} />
</div>
{/* Input */}
<div className="border-t border-white/10 px-4 py-3 shrink-0">
{isStreaming && (
<button
onClick={stopGeneration}
className="w-full mb-2 px-3 py-1.5 rounded-lg bg-white/[0.06] hover:bg-white/[0.1]
text-xs text-white/50 transition-colors"
>
{i.chat.stop}
</button>
)}
<div className="flex gap-2">
<input
ref={inputRef}
type="text"
value={input}
onChange={(e) => setInput(e.target.value)}
onKeyDown={(e) => e.key === 'Enter' && sendMessage()}
placeholder={i.chat.placeholder}
disabled={isStreaming}
className="flex-1 bg-white/[0.06] border border-white/10 rounded-xl px-3.5 py-2.5
text-xs text-white placeholder-white/30 outline-none
focus:border-accent-electric/50 focus:ring-1 focus:ring-accent-electric/20
disabled:opacity-50 transition-all"
/>
<button
onClick={() => sendMessage()}
disabled={isStreaming || !input.trim()}
className="px-3.5 py-2.5 bg-accent-electric hover:bg-blue-600 disabled:opacity-30
rounded-xl transition-all text-white"
>
<Send className="w-3.5 h-3.5" />
</button>
</div>
</div>
</motion.div>
)}
</AnimatePresence>
</>
)
}
@@ -0,0 +1,214 @@
'use client'
import { useState, useEffect, useCallback } from 'react'
import { motion, AnimatePresence } from 'framer-motion'
import { Shield, ChevronDown, ChevronUp } from 'lucide-react'
import { useApp } from '@/lib/context'
const COOKIE_NAME = 'bp_consent'
const SITE_ID = process.env.NEXT_PUBLIC_CONSENT_SITE_ID || 'breakpilot-marketing'
interface ConsentState {
essential: boolean
functional: boolean
analytics: boolean
}
const defaultConsent: ConsentState = {
essential: true,
functional: false,
analytics: false,
}
const texts = {
de: {
title: 'Cookie-Einwilligung',
description: 'Wir verwenden Cookies, um unsere Website zu verbessern. Essenzielle Cookies sind für die Grundfunktionen erforderlich. Weitere Informationen finden Sie in unserer',
privacyLink: 'Datenschutzerklärung',
acceptAll: 'Alle akzeptieren',
rejectAll: 'Nur notwendige',
settings: 'Einstellungen',
save: 'Auswahl speichern',
categories: {
essential: { name: 'Notwendig', description: 'Erforderlich für die Grundfunktionen der Website.', required: true },
functional: { name: 'Funktional', description: 'Ermöglicht erweiterte Funktionen wie Spracheinstellungen und Theme-Präferenzen.' },
analytics: { name: 'Analyse', description: 'Hilft uns zu verstehen, wie Besucher die Website nutzen.' },
},
},
en: {
title: 'Cookie Consent',
description: 'We use cookies to improve our website. Essential cookies are required for basic functionality. For more information, please see our',
privacyLink: 'Privacy Policy',
acceptAll: 'Accept All',
rejectAll: 'Essential Only',
settings: 'Settings',
save: 'Save Preferences',
categories: {
essential: { name: 'Essential', description: 'Required for basic website functionality.', required: true },
functional: { name: 'Functional', description: 'Enables enhanced features like language settings and theme preferences.' },
analytics: { name: 'Analytics', description: 'Helps us understand how visitors use the website.' },
},
},
}
function getFingerprint(): string {
const nav = typeof navigator !== 'undefined' ? navigator : null
const raw = [nav?.language, nav?.platform, screen?.width, screen?.height, new Date().getTimezoneOffset()].join('|')
let hash = 0
for (let i = 0; i < raw.length; i++) {
hash = ((hash << 5) - hash + raw.charCodeAt(i)) | 0
}
return 'fp_' + Math.abs(hash).toString(36)
}
function getSavedConsent(): ConsentState | null {
if (typeof window === 'undefined') return null
try {
const stored = localStorage.getItem(COOKIE_NAME)
if (stored) return JSON.parse(stored)
} catch { /* ignore */ }
return null
}
async function sendConsent(consent: ConsentState) {
try {
await fetch('/api/consent', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
site_id: SITE_ID,
device_fingerprint: getFingerprint(),
categories: [
'essential',
...(consent.functional ? ['functional'] : []),
...(consent.analytics ? ['analytics'] : []),
],
vendors: [],
user_agent: navigator.userAgent,
}),
})
} catch {
// Consent API not reachable — store locally anyway
}
}
export default function ConsentBanner() {
const { lang } = useApp()
const t = texts[lang]
const [visible, setVisible] = useState(false)
const [showDetails, setShowDetails] = useState(false)
const [consent, setConsent] = useState<ConsentState>(defaultConsent)
useEffect(() => {
const saved = getSavedConsent()
if (!saved) {
setVisible(true)
}
}, [])
const save = useCallback((state: ConsentState) => {
localStorage.setItem(COOKIE_NAME, JSON.stringify(state))
sendConsent(state)
setVisible(false)
window.dispatchEvent(new CustomEvent('consent-change', { detail: state }))
}, [])
const acceptAll = () => save({ essential: true, functional: true, analytics: true })
const rejectAll = () => save({ essential: true, functional: false, analytics: false })
const saveSelection = () => save(consent)
if (!visible) return null
const categories = Object.entries(t.categories) as [string, { name: string; description: string; required?: boolean }][]
return (
<AnimatePresence>
<motion.div
initial={{ y: 100, opacity: 0 }}
animate={{ y: 0, opacity: 1 }}
exit={{ y: 100, opacity: 0 }}
transition={{ duration: 0.3, ease: [0.22, 1, 0.36, 1] }}
className="fixed bottom-0 left-0 right-0 z-[9999] p-4 md:p-6"
>
<div className="max-w-3xl mx-auto rounded-2xl bg-enterprise-dark/95 backdrop-blur-xl border border-white/[0.08] shadow-2xl shadow-black/40 p-6">
{/* Header */}
<div className="flex items-start gap-3 mb-4">
<div className="w-8 h-8 rounded-lg bg-accent-electric/10 flex items-center justify-center shrink-0 mt-0.5">
<Shield className="w-4 h-4 text-accent-electric" />
</div>
<div>
<h3 className="text-sm font-bold text-white mb-1">{t.title}</h3>
<p className="text-xs text-white/50 leading-relaxed">
{t.description}{' '}
<a href="/datenschutz" className="text-accent-electric hover:underline">{t.privacyLink}</a>.
</p>
</div>
</div>
{/* Category details */}
<AnimatePresence>
{showDetails && (
<motion.div
initial={{ height: 0, opacity: 0 }}
animate={{ height: 'auto', opacity: 1 }}
exit={{ height: 0, opacity: 0 }}
transition={{ duration: 0.2 }}
className="overflow-hidden mb-4"
>
<div className="space-y-2 pt-2 border-t border-white/[0.06]">
{categories.map(([key, cat]) => (
<label
key={key}
className="flex items-center justify-between p-3 rounded-xl bg-white/[0.03] border border-white/[0.06] cursor-pointer hover:bg-white/[0.05] transition-colors"
>
<div className="flex-1 mr-4">
<span className="text-xs font-semibold text-white">{cat.name}</span>
<p className="text-xs text-white/40 mt-0.5">{cat.description}</p>
</div>
<input
type="checkbox"
checked={cat.required || consent[key as keyof ConsentState]}
disabled={cat.required}
onChange={(e) => setConsent(prev => ({ ...prev, [key]: e.target.checked }))}
className="w-4 h-4 rounded accent-accent-electric"
/>
</label>
))}
</div>
</motion.div>
)}
</AnimatePresence>
{/* Buttons */}
<div className="flex flex-col sm:flex-row items-stretch sm:items-center gap-2">
<button
onClick={acceptAll}
className="flex-1 px-4 py-2.5 rounded-xl bg-accent-electric text-white text-xs font-semibold hover:bg-blue-500 transition-colors"
>
{t.acceptAll}
</button>
<button
onClick={rejectAll}
className="flex-1 px-4 py-2.5 rounded-xl bg-white/[0.06] border border-white/[0.08] text-white/70 text-xs font-semibold hover:bg-white/[0.1] transition-colors"
>
{t.rejectAll}
</button>
<button
onClick={() => showDetails ? saveSelection() : setShowDetails(true)}
className="flex-1 px-4 py-2.5 rounded-xl bg-white/[0.06] border border-white/[0.08] text-white/70 text-xs font-semibold hover:bg-white/[0.1] transition-colors flex items-center justify-center gap-1.5"
>
{showDetails ? t.save : t.settings}
{!showDetails && <ChevronDown className="w-3 h-3" />}
{showDetails && <ChevronUp className="w-3 h-3" />}
</button>
</div>
{/* Powered by */}
<p className="text-center mt-3 text-[10px] text-white/20 font-mono">
Consent managed by BreakPilot CMP
</p>
</div>
</motion.div>
</AnimatePresence>
)
}
@@ -0,0 +1,69 @@
'use client'
import { t } from '@/lib/content'
import { useApp } from '@/lib/context'
export default function Footer() {
const { lang } = useApp()
const i = t(lang)
const year = new Date().getFullYear()
return (
<footer className="border-t border-white/[0.06] bg-enterprise-darker">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-16">
<div className="grid grid-cols-1 md:grid-cols-4 gap-12">
<div className="md:col-span-2">
<div className="flex items-center gap-2 mb-4">
<div className="w-8 h-8 rounded-lg bg-gradient-to-br from-accent-electric to-accent-indigo flex items-center justify-center">
<span className="text-white font-bold text-sm">B</span>
</div>
<span className="font-bold text-white text-lg">BreakPilot</span>
</div>
<p className="mono-label mb-2">{i.footer.tagline}</p>
<p className="text-white/30 text-sm max-w-sm">
{i.footer.description}
</p>
</div>
<div>
<h4 className="font-semibold text-white/80 text-sm mb-4">Produkt</h4>
<ul className="space-y-2">
{i.footer.links.product.map(link => (
<li key={link}>
<a href={`#${link.toLowerCase()}`} className="text-sm text-white/40 hover:text-white/70 transition-colors">
{link}
</a>
</li>
))}
</ul>
</div>
<div>
<h4 className="font-semibold text-white/80 text-sm mb-4">Rechtliches</h4>
<ul className="space-y-2">
{i.footer.links.legal.map(link => (
<li key={link}>
<a
href={link === 'Impressum' ? '/impressum' : link === 'Datenschutz' ? '/datenschutz' : '#'}
className="text-sm text-white/40 hover:text-white/70 transition-colors"
>
{link}
</a>
</li>
))}
</ul>
</div>
</div>
<div className="mt-12 pt-8 border-t border-white/[0.04] flex flex-col sm:flex-row justify-between items-center gap-4">
<p className="text-xs text-white/20">
&copy; {year} {i.footer.copyright}. Alle Rechte vorbehalten.
</p>
<p className="text-xs text-white/20 font-mono">
{i.footer.madeIn}
</p>
</div>
</div>
</footer>
)
}
@@ -0,0 +1,63 @@
'use client'
import { motion, AnimatePresence } from 'framer-motion'
import { X } from 'lucide-react'
import Link from 'next/link'
import { navLinks } from '@/lib/sections'
import { useApp } from '@/lib/context'
interface MobileMenuProps {
open: boolean
onClose: () => void
}
export default function MobileMenu({ open, onClose }: MobileMenuProps) {
const { lang } = useApp()
return (
<AnimatePresence>
{open && (
<>
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
onClick={onClose}
className="fixed inset-0 z-50 bg-black/60"
/>
<motion.div
initial={{ x: '100%' }}
animate={{ x: 0 }}
exit={{ x: '100%' }}
transition={{ type: 'spring', damping: 30, stiffness: 300 }}
className="fixed right-0 top-0 bottom-0 z-50 w-72 bg-enterprise-dark border-l border-white/[0.08] p-6"
>
<button onClick={onClose} className="absolute top-4 right-4 text-white/60 hover:text-white">
<X className="w-5 h-5" />
</button>
<nav className="mt-12 flex flex-col gap-1">
<Link
href="/"
onClick={onClose}
className="px-4 py-3 rounded-xl text-sm text-white/60 hover:text-white hover:bg-white/[0.06] transition-colors"
>
Start
</Link>
{navLinks.map(link => (
<Link
key={link.href}
href={link.href}
onClick={onClose}
className="px-4 py-3 rounded-xl text-sm text-white/60 hover:text-white hover:bg-white/[0.06] transition-colors"
>
{lang === 'de' ? link.labelDe : link.labelEn}
</Link>
))}
</nav>
</motion.div>
</>
)}
</AnimatePresence>
)
}
@@ -0,0 +1,111 @@
'use client'
import { useState, useEffect } from 'react'
import { motion } from 'framer-motion'
import { Menu, Sun, Moon } from 'lucide-react'
import Link from 'next/link'
import { usePathname } from 'next/navigation'
import { navLinks } from '@/lib/sections'
import { t } from '@/lib/content'
import { useApp } from '@/lib/context'
import CTAButton from '@/components/ui/CTAButton'
import MobileMenu from './MobileMenu'
export default function Navbar() {
const { lang, theme, toggleLang, toggleTheme } = useApp()
const [scrolled, setScrolled] = useState(false)
const [mobileOpen, setMobileOpen] = useState(false)
const pathname = usePathname()
const i = t(lang)
useEffect(() => {
const handleScroll = () => setScrolled(window.scrollY > 50)
window.addEventListener('scroll', handleScroll, { passive: true })
return () => window.removeEventListener('scroll', handleScroll)
}, [])
return (
<>
<motion.nav
initial={{ y: -100 }}
animate={{ y: 0 }}
transition={{ duration: 0.5, ease: [0.22, 1, 0.36, 1] }}
className={`
fixed top-0 left-0 right-0 z-50 transition-all duration-300
${scrolled
? 'bg-enterprise-dark/80 backdrop-blur-xl border-b border-white/[0.06]'
: 'bg-transparent'
}
`}
>
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="flex items-center justify-between h-16">
<Link href="/" className="flex items-center gap-2">
<div className="w-8 h-8 rounded-lg bg-gradient-to-br from-accent-electric to-accent-indigo flex items-center justify-center">
<span className="text-white font-bold text-sm">B</span>
</div>
<span className="font-bold text-white text-lg">BreakPilot</span>
</Link>
<div className="hidden md:flex items-center gap-1">
{navLinks.map(link => (
<Link
key={link.href}
href={link.href}
className={`
px-4 py-2 rounded-lg text-sm font-medium transition-colors duration-200
${pathname === link.href
? 'text-white bg-white/[0.08]'
: 'text-white/50 hover:text-white hover:bg-white/[0.04]'
}
`}
>
{lang === 'de' ? link.labelDe : link.labelEn}
</Link>
))}
</div>
<div className="flex items-center gap-2">
<button
onClick={toggleLang}
className="flex items-center gap-0.5 rounded-lg bg-white/[0.06] border border-white/[0.08] overflow-hidden"
>
<span className={`px-2 py-1 text-xs font-medium transition-colors ${lang === 'de' ? 'bg-accent-electric text-white' : 'text-white/40'}`}>
DE
</span>
<span className={`px-2 py-1 text-xs font-medium transition-colors ${lang === 'en' ? 'bg-accent-electric text-white' : 'text-white/40'}`}>
EN
</span>
</button>
<button
onClick={toggleTheme}
className="w-8 h-8 rounded-lg bg-white/[0.06] border border-white/[0.08] flex items-center justify-center
hover:bg-white/[0.1] transition-colors"
aria-label={theme === 'dark' ? 'Light mode' : 'Dark mode'}
>
{theme === 'dark'
? <Sun className="w-4 h-4 text-white/50" />
: <Moon className="w-4 h-4 text-white/50" />
}
</button>
<CTAButton href="/preise" className="hidden sm:inline-flex text-xs px-4 py-2">
{i.nav.cta}
</CTAButton>
<button
onClick={() => setMobileOpen(true)}
className="md:hidden p-2 text-white/60 hover:text-white"
>
<Menu className="w-5 h-5" />
</button>
</div>
</div>
</div>
</motion.nav>
<MobileMenu open={mobileOpen} onClose={() => setMobileOpen(false)} />
</>
)
}