fix(pitch-deck): USP slide complete redesign — grid layout
All checks were successful
Build pitch-deck / build-push-deploy (push) Successful in 1m7s
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / test-go-consent (push) Successful in 30s
CI / test-python-voice (push) Successful in 31s
CI / test-bqas (push) Successful in 31s

Replace broken absolute positioning with clean grid layout:
- Top: Compliance card | BreakPilot hub (spinning) | Code card
- Arrows + sync labels between cards
- Bottom: 4 capability cards in a row
- No more floating text, no overlapping elements

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Benjamin Admin
2026-04-15 13:25:03 +02:00
parent 40d2342086
commit bd37ff807e

View File

@@ -3,6 +3,7 @@
import { Language } from '@/lib/types' import { Language } from '@/lib/types'
import GradientText from '../ui/GradientText' import GradientText from '../ui/GradientText'
import FadeInView from '../ui/FadeInView' import FadeInView from '../ui/FadeInView'
import GlassCard from '../ui/GlassCard'
import { import {
FileCheck, FileCheck,
Code, Code,
@@ -10,6 +11,9 @@ import {
Shield, Shield,
GitPullRequest, GitPullRequest,
ArrowLeftRight, ArrowLeftRight,
ArrowRight,
ArrowDown,
RotateCw,
} from 'lucide-react' } from 'lucide-react'
interface USPSlideProps { interface USPSlideProps {
@@ -32,146 +36,143 @@ export default function USPSlide({ lang }: USPSlideProps) {
? ['SAST / DAST / SBOM-Analyse', 'Kontinuierliches Pentesting', 'Issue-Tracker-Integration', 'Automatische Code-Änderungen'] ? ['SAST / DAST / SBOM-Analyse', 'Kontinuierliches Pentesting', 'Issue-Tracker-Integration', 'Automatische Code-Änderungen']
: ['SAST / DAST / SBOM analysis', 'Continuous pentesting', 'Issue tracker integration', 'Automatic code changes'] : ['SAST / DAST / SBOM analysis', 'Continuous pentesting', 'Issue tracker integration', 'Automatic code changes']
const outerCapabilities = [ const capabilities = [
{ {
icon: GitPullRequest, icon: GitPullRequest,
color: 'text-indigo-400', color: 'text-indigo-400',
border: 'border-indigo-500/30', border: 'border-indigo-500/20',
bg: 'bg-indigo-500/10', bg: 'bg-indigo-500/10',
label: de ? 'RFQ-Prüfung' : 'RFQ Verification', label: de ? 'RFQ-Prüfung' : 'RFQ Verification',
desc: de ? 'Kunden-Dokumente gegen Code prüfen' : 'Verify customer docs against code', desc: de ? 'Kunden-Dokumente automatisch gegen Code prüfen' : 'Verify customer docs against code automatically',
position: 'top-left',
}, },
{ {
icon: ArrowLeftRight, icon: ArrowLeftRight,
color: 'text-purple-400', color: 'text-purple-400',
border: 'border-purple-500/30', border: 'border-purple-500/20',
bg: 'bg-purple-500/10', bg: 'bg-purple-500/10',
label: de ? 'Bidirektional' : 'Bidirectional', label: de ? 'Bidirektional' : 'Bidirectional',
desc: de ? 'Code ↔ Docs synchronisiert' : 'Code ↔ Docs synchronized', desc: de ? 'Code ↔ Compliance-Docs immer synchron' : 'Code ↔ Compliance docs always in sync',
position: 'top-right',
}, },
{ {
icon: Zap, icon: Zap,
color: 'text-amber-400', color: 'text-amber-400',
border: 'border-amber-500/30', border: 'border-amber-500/20',
bg: 'bg-amber-500/10', bg: 'bg-amber-500/10',
label: de ? 'Prozess-Compliance' : 'Process Compliance', label: de ? 'Prozess-Compliance' : 'Process Compliance',
desc: de ? 'Finding → Ticket → Fix automatisch' : 'Finding → Ticket → Fix automatic', desc: de ? 'Finding → Ticket → Fix vollautomatisch' : 'Finding → Ticket → Fix fully automatic',
position: 'bottom-left',
}, },
{ {
icon: Shield, icon: Shield,
color: 'text-emerald-400', color: 'text-emerald-400',
border: 'border-emerald-500/30', border: 'border-emerald-500/20',
bg: 'bg-emerald-500/10', bg: 'bg-emerald-500/10',
label: de ? 'Kontinuierlich' : 'Continuous', label: de ? 'Kontinuierlich' : 'Continuous',
desc: de ? 'Bei jeder Code-Änderung' : 'On every code change', desc: de ? 'Bei jeder Code-Änderung, nicht jährlich' : 'On every code change, not annually',
position: 'bottom-right',
}, },
] ]
return ( return (
<div> <div>
<FadeInView className="text-center mb-6"> <FadeInView className="text-center mb-6">
<h2 className="text-4xl md:text-5xl font-bold mb-3"> <h2 className="text-4xl md:text-5xl font-bold mb-2">
<GradientText>{title}</GradientText> <GradientText>{title}</GradientText>
</h2> </h2>
<p className="text-base text-white/50 max-w-3xl mx-auto">{subtitle}</p> <p className="text-base text-white/50 max-w-3xl mx-auto">{subtitle}</p>
</FadeInView> </FadeInView>
{/* Main bridge: Compliance ← BreakPilot → Code */}
<FadeInView delay={0.2}> <FadeInView delay={0.2}>
<div className="relative max-w-4xl mx-auto" style={{ height: '420px' }}> <div className="grid grid-cols-11 gap-2 items-center max-w-5xl mx-auto mb-6">
{/* Left: Compliance */}
{/* Outer rotating ring */} <div className="col-span-4">
<div className="absolute inset-0 flex items-center justify-center"> <GlassCard hover={false} className="p-4 h-full">
<div <div className="flex items-center gap-2 mb-3">
className="w-[340px] h-[340px] rounded-full border-2 border-dashed border-indigo-500/20 animate-[spin_20s_linear_infinite]" <div className="w-7 h-7 rounded-lg bg-indigo-500/10 border border-indigo-500/20 flex items-center justify-center">
/> <FileCheck className="w-3.5 h-3.5 text-indigo-400" />
</div> </div>
<span className="text-sm font-bold text-indigo-400">Compliance & Audits</span>
{/* Inner solid ring */} </div>
<div className="absolute inset-0 flex items-center justify-center"> <ul className="space-y-2">
<div className="w-[300px] h-[300px] rounded-full border border-white/[0.08] bg-white/[0.02]" /> {complianceItems.map((item, idx) => (
<li key={idx} className="flex items-start gap-2 text-xs text-white/60">
<span className="w-1.5 h-1.5 rounded-full bg-indigo-400 mt-1 shrink-0" />
{item}
</li>
))}
</ul>
</GlassCard>
</div> </div>
{/* Center: BreakPilot Hub */} {/* Center: BreakPilot Hub */}
<div className="absolute inset-0 flex items-center justify-center"> <div className="col-span-3 flex flex-col items-center justify-center py-4">
<div className="w-20 h-20 rounded-full bg-gradient-to-br from-indigo-500 to-purple-600 flex items-center justify-center shadow-xl shadow-indigo-500/30 z-10"> {/* Arrow left */}
<div className="flex items-center gap-2 mb-3">
<ArrowRight className="w-4 h-4 text-indigo-400/40 rotate-180" />
<span className="text-[9px] text-white/20 uppercase tracking-wider">{de ? 'synchron' : 'sync'}</span>
<ArrowRight className="w-4 h-4 text-purple-400/40" />
</div>
{/* Spinning ring + hub */}
<div className="relative w-28 h-28">
<div className="absolute inset-0 rounded-full border-2 border-dashed border-indigo-500/20 animate-[spin_15s_linear_infinite]" />
<div className="absolute inset-2 rounded-full border border-white/[0.06]" />
<div className="absolute inset-4 rounded-full bg-gradient-to-br from-indigo-500 to-purple-600 flex items-center justify-center shadow-xl shadow-indigo-500/30">
<div className="text-center"> <div className="text-center">
<span className="text-[10px] font-black text-white block leading-tight">Break</span> <span className="text-xs font-black text-white block leading-tight">Break</span>
<span className="text-[10px] font-black text-white block leading-tight">Pilot</span> <span className="text-xs font-black text-white block leading-tight">Pilot</span>
</div> </div>
</div> </div>
</div> </div>
{/* Left half: Compliance & Audits */} {/* Cycle indicator */}
<div className="absolute left-1/2 top-1/2 -translate-x-[190px] -translate-y-1/2 w-[130px]"> <div className="flex items-center gap-1.5 mt-3">
<div className="flex items-center gap-1.5 mb-2"> <RotateCw className="w-3 h-3 text-white/20" />
<FileCheck className="w-3.5 h-3.5 text-indigo-400" /> <span className="text-[9px] text-white/20 uppercase tracking-wider">{de ? 'Kreislauf' : 'Loop'}</span>
<span className="text-[11px] font-bold text-indigo-400">Compliance</span>
</div> </div>
<ul className="space-y-1.5">
{complianceItems.map((item, idx) => (
<li key={idx} className="flex items-start gap-1.5 text-[10px] text-white/50 leading-tight">
<span className="w-1 h-1 rounded-full bg-indigo-400 mt-1 shrink-0" />
{item}
</li>
))}
</ul>
</div> </div>
{/* Right half: Code & Security */} {/* Right: Code & Security */}
<div className="absolute left-1/2 top-1/2 translate-x-[60px] -translate-y-1/2 w-[130px]"> <div className="col-span-4">
<div className="flex items-center gap-1.5 mb-2"> <GlassCard hover={false} className="p-4 h-full">
<div className="flex items-center gap-2 mb-3">
<div className="w-7 h-7 rounded-lg bg-purple-500/10 border border-purple-500/20 flex items-center justify-center">
<Code className="w-3.5 h-3.5 text-purple-400" /> <Code className="w-3.5 h-3.5 text-purple-400" />
<span className="text-[11px] font-bold text-purple-400">Code & Security</span>
</div> </div>
<ul className="space-y-1.5"> <span className="text-sm font-bold text-purple-400">Code & Security</span>
</div>
<ul className="space-y-2">
{codeItems.map((item, idx) => ( {codeItems.map((item, idx) => (
<li key={idx} className="flex items-start gap-1.5 text-[10px] text-white/50 leading-tight"> <li key={idx} className="flex items-start gap-2 text-xs text-white/60">
<span className="w-1 h-1 rounded-full bg-purple-400 mt-1 shrink-0" /> <span className="w-1.5 h-1.5 rounded-full bg-purple-400 mt-1 shrink-0" />
{item} {item}
</li> </li>
))} ))}
</ul> </ul>
</GlassCard>
</div> </div>
{/* Connecting arrows inside circle */}
<div className="absolute inset-0 flex items-center justify-center pointer-events-none">
<div className="absolute left-1/2 top-1/2 -translate-x-[48px] -translate-y-1/2 text-indigo-400/40 text-lg">&#x25C0;</div>
<div className="absolute left-1/2 top-1/2 translate-x-[38px] -translate-y-1/2 text-purple-400/40 text-lg">&#x25B6;</div>
<div className="absolute left-1/2 top-1/2 -translate-x-[5px] -translate-y-[48px] text-white/20 text-lg">&#x25B2;</div>
<div className="absolute left-1/2 top-1/2 -translate-x-[5px] translate-y-[32px] text-white/20 text-lg">&#x25BC;</div>
</div> </div>
</FadeInView>
{/* Outer capability cards — 4 corners */} {/* Arrow down */}
{outerCapabilities.map((cap, idx) => { <FadeInView delay={0.3} className="flex justify-center mb-4">
<ArrowDown className="w-5 h-5 text-white/15" />
</FadeInView>
{/* Bottom: 4 capability cards */}
<FadeInView delay={0.4}>
<div className="grid grid-cols-4 gap-3 max-w-5xl mx-auto">
{capabilities.map((cap, idx) => {
const Icon = cap.icon const Icon = cap.icon
const posClass = idx === 0 ? 'top-0 left-0'
: idx === 1 ? 'top-0 right-0'
: idx === 2 ? 'bottom-0 left-0'
: 'bottom-0 right-0'
return ( return (
<div key={idx} className={`absolute ${posClass} w-[180px]`}> <div key={idx} className={`border ${cap.border} ${cap.bg} rounded-xl p-3`}>
<div className={`border ${cap.border} ${cap.bg} rounded-xl p-3`}> <div className="flex items-center gap-1.5 mb-1.5">
<div className="flex items-center gap-1.5 mb-1"> <Icon className={`w-4 h-4 ${cap.color}`} />
<Icon className={`w-3.5 h-3.5 ${cap.color}`} /> <span className={`text-xs font-bold ${cap.color}`}>{cap.label}</span>
<span className={`text-[11px] font-bold ${cap.color}`}>{cap.label}</span>
</div>
<p className="text-[10px] text-white/40 leading-tight">{cap.desc}</p>
</div> </div>
<p className="text-[11px] text-white/45 leading-relaxed">{cap.desc}</p>
</div> </div>
) )
})} })}
{/* Dashed connection lines from corners to circle */}
<svg className="absolute inset-0 w-full h-full pointer-events-none" viewBox="0 0 800 420">
<line x1="180" y1="60" x2="310" y2="160" stroke="rgba(99,102,241,0.2)" strokeWidth="1" strokeDasharray="4 4" />
<line x1="620" y1="60" x2="490" y2="160" stroke="rgba(168,85,247,0.2)" strokeWidth="1" strokeDasharray="4 4" />
<line x1="180" y1="360" x2="310" y2="260" stroke="rgba(245,158,11,0.2)" strokeWidth="1" strokeDasharray="4 4" />
<line x1="620" y1="360" x2="490" y2="260" stroke="rgba(16,185,129,0.2)" strokeWidth="1" strokeDasharray="4 4" />
</svg>
</div> </div>
</FadeInView> </FadeInView>
</div> </div>