-
- {securityFeatures.map((feat, idx) => {
- const Icon = feat.icon
+ {/* ── Main canvas ── */}
+
+
+ {/* Ambient glows */}
+ {!isLight && (
+ <>
+
+
+ >
+ )}
+
+ {/* Slabs + connectors */}
+
+ {LAYERS.map((layer, li) => {
+ const nodes = layer.nodeIds.map(id => nodeMap[id])
return (
-
-
- {feat.label}
-
+
+
+ {li < LAYERS.length - 1 && }
+
)
})}
-
+
+ {/* Footer badges */}
+
+ {([
+ { Icon: Lock, label: de ? 'Kein US-Anbieter · 100% DSGVO' : 'No US providers · 100% GDPR' },
+ { Icon: Server, label: de ? 'BSI-zertifiziertes Rechenzentrum' : 'BSI-certified data center' },
+ { Icon: BadgeCheck, label: de ? 'EU-souveräne Inferenz' : 'EU-sovereign inference' },
+ ] as { Icon: React.ElementType; label: string }[]).map(({ Icon, label }) => (
+
+
+ {label}
+
+ ))}
+
+
+ {/* Detail panel */}
+
+ {active && (
+
+
+
+
+
+
+
+
+ {active.title}
+
+
+ {active.tier === 'product' ? (de ? 'Anwendung' : 'Application') :
+ active.tier === 'proxy' ? 'Gateway' :
+ (de ? 'Inferenz' : 'Inference')}
+
+
+
+ {active.subtitle}
+
+
+
+
setActiveId(null)}
+ style={{
+ background: 'transparent',
+ border: `1px solid ${isLight ? 'rgba(0,0,0,.15)' : 'rgba(167,139,250,.25)'}`,
+ color: isLight ? '#64748b' : 'rgba(236,233,247,.5)',
+ width: 28, height: 28, borderRadius: 14,
+ cursor: 'pointer', display: 'flex',
+ alignItems: 'center', justifyContent: 'center', flexShrink: 0,
+ }}
+ >
+
+
+
+
+
+
+ {de ? 'Stack' : 'Tech Stack'}
+
+
+ {active.tech.map(tk => (
+ {tk}
+ ))}
+
+
+
+
+ {de ? 'Funktionen' : 'Capabilities'}
+
+
+ {active.services.map(s => (
+
+
+
{s.name}
+
{s.desc}
+
+ ))}
+
+
+
+
+
+ )}
+
+
)
diff --git a/pitch-deck/components/slides/MilestonesSlide.tsx b/pitch-deck/components/slides/MilestonesSlide.tsx
new file mode 100644
index 0000000..9dcf748
--- /dev/null
+++ b/pitch-deck/components/slides/MilestonesSlide.tsx
@@ -0,0 +1,796 @@
+'use client'
+
+import { useState, useEffect, useRef, useMemo, useCallback, Fragment } from 'react'
+import { Language } from '@/lib/types'
+import GradientText from '../ui/GradientText'
+import FadeInView from '../ui/FadeInView'
+
+interface MilestonesSlideProps { lang: Language }
+
+const MONO: React.CSSProperties = {
+ fontFamily: '"JetBrains Mono","SF Mono",ui-monospace,monospace',
+ fontVariantNumeric: 'tabular-nums',
+}
+
+const CSS_KF = `
+ @keyframes msFlow { 0%{stroke-dashoffset:0} 100%{stroke-dashoffset:-18} }
+ @keyframes msFadeIn { from{opacity:0} to{opacity:1} }
+ @keyframes msScaleIn { from{opacity:0;transform:scale(.94)} to{opacity:1;transform:scale(1)} }
+ @keyframes msHeadingDark {
+ 0%,100%{text-shadow:0 0 22px rgba(167,139,250,.3)}
+ 50% {text-shadow:0 0 40px rgba(167,139,250,.6)}
+ }
+ @keyframes msHeadingLight {
+ 0%,100%{text-shadow:0 0 22px rgba(124,58,237,.15)}
+ 50% {text-shadow:0 0 36px rgba(124,58,237,.30)}
+ }
+ @keyframes msPulse {
+ 0%,100%{r:9;opacity:.4}
+ 50% {r:14;opacity:.05}
+ }
+`
+
+// ── Light mode hook ───────────────────────────────────────────────────────────
+function useIsLight() {
+ const [isLight, setIsLight] = useState(false)
+ useEffect(() => {
+ const check = () => setIsLight(document.documentElement.classList.contains('theme-light'))
+ check()
+ const obs = new MutationObserver(check)
+ obs.observe(document.documentElement, { attributes: true, attributeFilter: ['class'] })
+ return () => obs.disconnect()
+ }, [])
+ return isLight
+}
+
+// ── Themes ────────────────────────────────────────────────────────────────────
+const THEMES = {
+ dark: {
+ key: 'dark' as const,
+ bg: 'radial-gradient(ellipse at 50% 25%, #1a0f34 0%, #0e0720 55%, #050210 100%)',
+ ambient: 'radial-gradient(ellipse, rgba(167,139,250,.18), transparent 65%)',
+ stars: true,
+ fg: '#f7f5fc',
+ fgSoft: 'rgba(236,233,247,.82)',
+ fgMid: 'rgba(236,233,247,.72)',
+ fgMuted: 'rgba(236,233,247,.62)',
+ fgFaint: 'rgba(236,233,247,.55)',
+ fgGhost: 'rgba(236,233,247,.45)',
+ fgWhisper: 'rgba(236,233,247,.4)',
+ accent: '#a78bfa',
+ accent80: 'rgba(167,139,250,.8)',
+ accent70: 'rgba(167,139,250,.7)',
+ accent50: 'rgba(167,139,250,.5)',
+ accent40: 'rgba(167,139,250,.4)',
+ accent20: 'rgba(167,139,250,.2)',
+ headingGrad: 'linear-gradient(90deg, #e9e2ff, #a78bfa 50%, #e9e2ff)',
+ headingAnim: 'msHeadingDark 4s ease-in-out infinite',
+ heuteText: '#e4d4ff',
+ heutePillBg: 'rgba(14,8,28,.95)',
+ heuteCore: '#f0e9ff',
+ done: '#4ade80',
+ doneBright: '#86efac',
+ doneDeep: '#166534',
+ doneSolid: '#22c55e',
+ cardBase: 'rgba(14,8,28,',
+ cardBaseA: '.9',
+ cardBaseAH: '.95',
+ cardTintTop: '18', cardTintTopH: '2e',
+ cardTintMid: '08', cardTintMidH: '14',
+ cardShadowSoft: '0 10px 24px rgba(0,0,0,.45)',
+ cardShadowLift: (t: string) => `0 20px 44px ${t}33, 0 0 0 1px ${t}66, inset 0 1px 0 ${t}66`,
+ statTintTop: '18', statTintTopH: '2a',
+ statTintMid: '06',
+ statShadowSoft: '0 10px 24px rgba(0,0,0,.45)',
+ statShadowLift: (t: string) => `0 18px 40px ${t}33, 0 0 0 1px ${t}55, inset 0 1px 0 ${t}55`,
+ modalScrim: 'rgba(5,2,16,.75)',
+ modalBgMid: 'rgba(20,10,40,.97)',
+ modalBgLow: 'rgba(14,8,28,.98)',
+ modalShadow: (t: string) => `0 30px 80px rgba(0,0,0,.65), 0 0 60px ${t}33, inset 0 1px 0 ${t}55`,
+ bulletBg: 'rgba(0,0,0,.3)',
+ progressTrackBg: 'rgba(255,255,255,.08)',
+ progressTrackBorder: 'rgba(167,139,250,.2)',
+ dotTodoDeep: '#1a0f34',
+ dotLitHi: 'rgba(255,255,255,.5)',
+ dotSoftHi: 'rgba(255,255,255,.3)',
+ sparkOp: 0.45,
+ },
+ light: {
+ key: 'light' as const,
+ bg: 'radial-gradient(ellipse at 50% 12%, #ffffff 0%, #f5efff 55%, #ebdfff 100%)',
+ ambient: 'radial-gradient(ellipse, rgba(124,58,237,.14), transparent 65%)',
+ stars: false,
+ fg: '#1a0f34',
+ fgSoft: 'rgba(26,15,52,.85)',
+ fgMid: 'rgba(26,15,52,.72)',
+ fgMuted: 'rgba(26,15,52,.62)',
+ fgFaint: 'rgba(26,15,52,.50)',
+ fgGhost: 'rgba(26,15,52,.40)',
+ fgWhisper: 'rgba(26,15,52,.32)',
+ accent: '#7c3aed',
+ accent80: 'rgba(124,58,237,.8)',
+ accent70: 'rgba(124,58,237,.75)',
+ accent50: 'rgba(124,58,237,.55)',
+ accent40: 'rgba(124,58,237,.4)',
+ accent20: 'rgba(124,58,237,.18)',
+ headingGrad: 'linear-gradient(90deg, #3b0e7a, #7c3aed 50%, #3b0e7a)',
+ headingAnim: 'msHeadingLight 4s ease-in-out infinite',
+ heuteText: '#4c1d95',
+ heutePillBg: 'rgba(255,255,255,.98)',
+ heuteCore: '#7c3aed',
+ done: '#16a34a',
+ doneBright: '#4ade80',
+ doneDeep: '#14532d',
+ doneSolid: '#22c55e',
+ cardBase: 'rgba(255,255,255,',
+ cardBaseA: '.92',
+ cardBaseAH: '.98',
+ cardTintTop: '22', cardTintTopH: '3a',
+ cardTintMid: '10', cardTintMidH: '1c',
+ cardShadowSoft: '0 10px 24px rgba(59,26,122,.10), 0 2px 6px rgba(59,26,122,.06)',
+ cardShadowLift: (t: string) => `0 20px 44px ${t}38, 0 0 0 1px ${t}77, inset 0 1px 0 rgba(255,255,255,.9)`,
+ statTintTop: '1e', statTintTopH: '34',
+ statTintMid: '08',
+ statShadowSoft: '0 10px 24px rgba(59,26,122,.10), 0 2px 6px rgba(59,26,122,.06)',
+ statShadowLift: (t: string) => `0 18px 40px ${t}38, 0 0 0 1px ${t}77, inset 0 1px 0 rgba(255,255,255,.9)`,
+ modalScrim: 'rgba(40,20,80,.28)',
+ modalBgMid: 'rgba(255,255,255,.98)',
+ modalBgLow: 'rgba(250,247,255,.98)',
+ modalShadow: (t: string) => `0 30px 80px rgba(59,26,122,.25), 0 0 60px ${t}33, inset 0 1px 0 rgba(255,255,255,.9)`,
+ bulletBg: 'rgba(124,58,237,.06)',
+ progressTrackBg: 'rgba(124,58,237,.12)',
+ progressTrackBorder: 'rgba(124,58,237,.25)',
+ dotTodoDeep: '#faf5ff',
+ dotLitHi: 'rgba(255,255,255,.85)',
+ dotSoftHi: 'rgba(255,255,255,.55)',
+ sparkOp: 0.55,
+ },
+}
+
+type Theme = typeof THEMES.dark
+
+// ── Data ──────────────────────────────────────────────────────────────────────
+const TODAY_POSITION = 0.56
+
+interface Milestone {
+ id: string
+ when: string
+ tick: string
+ title: { de: string; en: string }
+ short: { de: string; en: string }
+ body: { de: string; en: string }
+ bullets: { de: string[]; en: string[] }
+ tint: string
+ done: boolean
+ next?: boolean
+}
+
+const MILESTONES: Milestone[] = [
+ {
+ id: 'start',
+ when: 'Mär. 2025', tick: '03 · 25',
+ title: { de: 'Idee & Team-Start', en: 'Idea & Team Start' },
+ short: { de: 'Gründerteam formiert sich, erste Konzeption.', en: 'Founding team forms, first product concept.' },
+ body: {
+ de: 'Zwei Gründer, ein klares Problem: Compliance-Doks und Code leben in getrennten Welten. Start der Konzeption für eine Plattform, die beide Welten verbindet.',
+ en: 'Two founders, one clear problem: compliance docs and code live in separate worlds. Started designing a platform that bridges both.',
+ },
+ bullets: {
+ de: ['Team von 2 Gründern', 'Markt-Research DACH + EU', 'Erste Architektur-Skizze'],
+ en: ['Team of 2 founders', 'Market research DACH + EU', 'First architecture sketch'],
+ },
+ tint: '#a78bfa', done: true,
+ },
+ {
+ id: 'ihk',
+ when: 'Okt. 2025', tick: '10 · 25',
+ title: { de: 'IHK & Agentur für Arbeit', en: 'IHK & Employment Agency' },
+ short: { de: 'Gründerzuschuss beantragt & gesichert.', en: 'Founder grant applied for & secured.' },
+ body: {
+ de: 'Information und Austausch mit Agentur für Arbeit und IHK Konstanz für den Gründerzuschuss — seit Oktober 2025 in Bearbeitung und Aufbau.',
+ en: 'Collaboration with Employment Agency and IHK Konstanz for the founder grant — in processing since October 2025.',
+ },
+ bullets: {
+ de: ['Gründerzuschuss genehmigt', 'Mentorship-Programm IHK', 'Erste öffentliche Sichtbarkeit'],
+ en: ['Founder grant approved', 'IHK mentorship program', 'First public visibility'],
+ },
+ tint: '#a78bfa', done: true,
+ },
+ {
+ id: 'proto',
+ when: 'Dez. 2025', tick: '12 · 25',
+ title: { de: 'Prototyp Compliance SDK', en: 'Compliance SDK Prototype' },
+ short: { de: 'Compliance SDK & Security Cloud laufen.', en: 'Compliance SDK & Security Cloud running.' },
+ body: {
+ de: 'Entwicklung eines funktionsfähigen Prototypen der Compliance SDK und der Security-Cloud-Lösung — erste End-to-End-Demo läuft seit Dezember 2025.',
+ en: 'Built a working prototype of the Compliance SDK and Security Cloud solution — first end-to-end demo running since December 2025.',
+ },
+ bullets: {
+ de: ['SDK: policy → code mapping', 'Security Cloud MVP', 'Interne Demo-Audits erfolgreich'],
+ en: ['SDK: policy → code mapping', 'Security Cloud MVP', 'Internal demo audits successful'],
+ },
+ tint: '#c084fc', done: true,
+ },
+ {
+ id: 'pilot',
+ when: 'Dez. 2025', tick: '12 · 25',
+ title: { de: '2 Pilotkunden im Gespräch', en: '2 Pilot Customers in Talks' },
+ short: { de: 'Schwarzwald + Mobilitäts-Sektor.', en: 'Black Forest + Mobility Sector.' },
+ body: {
+ de: 'Kommunikation seit Dezember 2025 mit Kunden aus dem Schwarzwald (CE-Software-Risikobeurteilung) und einem globalen Maschinen- und Anlagenbauer aus dem Mobilitätssektor (KI-Roadmap).',
+ en: 'Since December 2025 in talks with a Black Forest CE-software customer (risk assessment) and a global mobility-sector machine builder (AI roadmap).',
+ },
+ bullets: {
+ de: ['CE-Software-Risikobeurteilung', 'KI-Roadmap für Mobilitätssektor', 'LOIs in Vorbereitung'],
+ en: ['CE software risk assessment', 'AI roadmap for mobility sector', 'LOIs in preparation'],
+ },
+ tint: '#c084fc', done: true,
+ },
+ {
+ id: 'reg',
+ when: '27. Mär. 2026', tick: '03 · 26',
+ title: { de: 'Eintragung GmbH', en: 'GmbH Registration' },
+ short: { de: 'Offizielle Gründung im Handelsregister.', en: 'Official incorporation in commercial register.' },
+ body: {
+ de: 'Notartermin und Eintragung ins Handelsregister am 27.03.2026. Ab diesem Datum voll operative GmbH mit klaren Governance-Strukturen.',
+ en: 'Notary appointment and commercial register entry on 27.03.2026. Fully operative GmbH with clear governance structures from this date.',
+ },
+ bullets: {
+ de: ['Gesellschaftsvertrag unterzeichnet', 'HRB-Eintrag Konstanz', 'Erste Rechnung ausgestellt'],
+ en: ['Articles of association signed', 'HRB entry Constance', 'First invoice issued'],
+ },
+ tint: '#fbbf24', done: false, next: true,
+ },
+ {
+ id: 'seed',
+ when: 'Q2 2026', tick: 'Q2 · 26',
+ title: { de: 'Seed-Runde', en: 'Seed Round' },
+ short: { de: '1,5 Mio € für 18 Monate Runway.', en: '€1.5M for 18 months runway.' },
+ body: {
+ de: 'Pre-Seed / Seed-Runde zur Finanzierung des ersten Kundensegments, Ausbau des Teams und Zertifizierung (ISO 27001, BSI C5).',
+ en: 'Pre-Seed / Seed round to fund first customer segment, team growth and certification (ISO 27001, BSI C5).',
+ },
+ bullets: {
+ de: ['Ziel: 1,5 Mio € Seed', 'Ausbau auf 8 FTE', 'Zertifizierungs-Track startet'],
+ en: ['Target: €1.5M seed', 'Scale to 8 FTE', 'Certification track starts'],
+ },
+ tint: '#fbbf24', done: false,
+ },
+ {
+ id: 'beta',
+ when: 'Q3 2026', tick: 'Q3 · 26',
+ title: { de: 'Öffentliches Beta', en: 'Public Beta' },
+ short: { de: 'Beta-Launch mit ersten zahlenden Kunden.', en: 'Beta launch with first paying customers.' },
+ body: {
+ de: 'Öffentliches Beta-Release der Plattform. Erste zahlende Kunden aus dem Pilotprogramm gehen live. Integration in Gitlab + GitHub Cloud.',
+ en: 'Public beta release of the platform. First paying customers from the pilot program go live. GitLab + GitHub Cloud integration.',
+ },
+ bullets: {
+ de: ['3–5 zahlende Pilot-Kunden', 'Public Beta verfügbar', 'Git-Integration live'],
+ en: ['3–5 paying pilot customers', 'Public beta available', 'Git integration live'],
+ },
+ tint: '#f59e0b', done: false,
+ },
+ {
+ id: 'v1',
+ when: 'Q4 2026', tick: 'Q4 · 26',
+ title: { de: 'EU Trust Stack v1.0', en: 'EU Trust Stack v1.0' },
+ short: { de: 'DSGVO · NIS-2 · DORA · EU AI Act.', en: 'GDPR · NIS-2 · DORA · EU AI Act.' },
+ body: {
+ de: 'Alle vier zentralen EU-Frameworks voll abgedeckt. EU-souveränes Hosting, vollständige Audit-Trail-Unterstützung, Zertifizierung ISO 27001 abgeschlossen.',
+ en: 'All four central EU frameworks fully covered. EU-sovereign hosting, complete audit trail support, ISO 27001 certification completed.',
+ },
+ bullets: {
+ de: ['4 EU-Frameworks live', 'EU-souveränes Hosting', 'ISO 27001 zertifiziert'],
+ en: ['4 EU frameworks live', 'EU-sovereign hosting', 'ISO 27001 certified'],
+ },
+ tint: '#f59e0b', done: false,
+ },
+]
+
+interface StatItem { k: { de: string; en: string }; v: string; tint: string }
+
+const STATS: StatItem[] = [
+ { k: { de: 'Gesetze & Dokumente im RAG', en: 'Laws & Docs in RAG' }, v: '385', tint: '#a78bfa' },
+ { k: { de: 'Atomare Controls', en: 'Atomic Controls' }, v: '25.000+', tint: '#c084fc' },
+ { k: { de: 'Compliance-Module', en: 'Compliance Modules' }, v: '12', tint: '#fbbf24' },
+ { k: { de: 'Pilotkunden', en: 'Pilot Customers' }, v: '2', tint: '#f59e0b' },
+ { k: { de: 'Lines of Code', en: 'Lines of Code' }, v: '500.000+', tint: '#8b5cf6' },
+]
+
+// ── Star Field ────────────────────────────────────────────────────────────────
+function StarField() {
+ const stars = useMemo(() => {
+ let s = 77
+ const r = () => { s = (s * 9301 + 49297) % 233280; return s / 233280 }
+ return Array.from({ length: 95 }, () => ({ x: r() * 100, y: r() * 100, size: r() * 1.4 + 0.3, op: r() * 0.5 + 0.15 }))
+ }, [])
+ return (
+
+ {stars.map((st, i) => (
+
+ ))}
+
+ )
+}
+
+function SoftGrid({ t }: { t: Theme }) {
+ return (
+
+ )
+}
+
+// ── Timeline ──────────────────────────────────────────────────────────────────
+interface MilestoneWithPos extends Milestone { x: number; row: 'top' | 'bottom' }
+
+function Timeline({ onSelect, selectedId, t, de }: {
+ onSelect: (m: Milestone) => void
+ selectedId: string | null
+ t: Theme
+ de: boolean
+}) {
+ const trackW = 1160
+ const innerPad = 120
+ const usableW = trackW - innerPad * 2
+ const positions = MILESTONES.map((_, i) => innerPad + (usableW * i) / (MILESTONES.length - 1))
+ const todayX = innerPad + usableW * TODAY_POSITION
+
+ const layout: MilestoneWithPos[] = MILESTONES.map((m, i) => ({
+ ...m, x: positions[i],
+ row: i % 2 === 0 ? 'top' : 'bottom',
+ }))
+
+ const railColor = t.key === 'dark' ? '#a78bfa' : '#7c3aed'
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {/* rail background */}
+
+ {/* past progress */}
+
+ {/* future dashed */}
+
+
+ {/* connector stubs */}
+ {layout.map((m) => (
+
+ ))}
+
+ {/* HEUTE marker — circles only; pill is HTML below */}
+
+
+
+
+
+
+
+
+
+
+ {/* HEUTE pill — HTML so it sits above milestone cards */}
+
HEUTE
+
+ {layout.map((m) => (
+
onSelect(m)}
+ active={selectedId === m.id} />
+ ))}
+
+ )
+}
+
+function MilestoneNode({ m, onClick, active, t, de }: {
+ m: MilestoneWithPos; onClick: () => void; active: boolean; t: Theme; de: boolean
+}) {
+ const [hover, setHover] = useState(false)
+ const lit = hover || active
+ const isTop = m.row === 'top'
+ const cardY = isTop ? 4 : 200
+ const nodeColor = m.done ? t.done : m.tint
+
+ const bgTopA = lit ? m.tint + t.cardTintTopH : m.tint + t.cardTintTop
+ const bgMidA = lit ? m.tint + t.cardTintMidH : m.tint + t.cardTintMid
+ const cardBg = `linear-gradient(180deg, ${bgTopA} 0%, ${bgMidA} 55%, ${t.cardBase}${lit ? t.cardBaseAH : t.cardBaseA})`
+ const badge = m.done ? (de ? 'erledigt' : 'done') : (m.next ? (de ? 'als nächstes' : 'next') : (de ? 'geplant' : 'plan'))
+
+ return (
+ <>
+ {/* dot */}
+ setHover(true)}
+ onMouseLeave={() => setHover(false)}
+ style={{
+ position: 'absolute', left: m.x - 14, top: 180 - 14,
+ width: 28, height: 28, borderRadius: '50%',
+ background: m.done
+ ? `radial-gradient(circle at 35% 30%, ${t.doneBright}, ${t.doneSolid} 60%, ${t.doneDeep})`
+ : `radial-gradient(circle at 35% 30%, ${m.tint}dd, ${m.tint}66 60%, ${t.dotTodoDeep})`,
+ border: `2px solid ${lit ? '#fff' : nodeColor}`,
+ boxShadow: lit
+ ? `0 0 22px ${nodeColor}, 0 0 44px ${nodeColor}66, inset 0 1px 0 ${t.dotLitHi}`
+ : `0 0 10px ${nodeColor}88, inset 0 1px 0 ${t.dotSoftHi}`,
+ display: 'flex', alignItems: 'center', justifyContent: 'center',
+ color: '#fff', fontSize: 11, fontWeight: 700,
+ cursor: 'pointer', zIndex: 5,
+ transition: 'all .25s',
+ transform: lit ? 'scale(1.15)' : 'scale(1)',
+ }}>
+ {m.done ? '✓' : (m.next ? '◉' : '○')}
+
+
+ {/* card */}
+ setHover(true)}
+ onMouseLeave={() => setHover(false)}
+ style={{
+ position: 'absolute', left: m.x - 112, top: cardY,
+ width: 224, height: 150, padding: '12px 14px',
+ borderRadius: 12,
+ background: cardBg,
+ border: `1px solid ${lit ? m.tint : m.tint + '55'}`,
+ boxShadow: lit ? t.cardShadowLift(m.tint) : t.cardShadowSoft,
+ cursor: 'pointer', zIndex: 4,
+ transition: 'all .25s',
+ transform: lit ? `translateY(${isTop ? -2 : 2}px)` : 'translateY(0)',
+ display: 'flex', flexDirection: 'column', gap: 6,
+ backdropFilter: t.key === 'light' ? 'blur(6px)' : 'none',
+ }}>
+
+ {m.tick}
+
+ {badge}
+
+
+ {de ? m.title.de : m.title.en}
+
+
+ {de ? m.short.de : m.short.en}
+
+
+ {m.when}
+ {de ? 'Details →' : 'Details →'}
+
+
+ >
+ )
+}
+
+// ── Stat Card ─────────────────────────────────────────────────────────────────
+function StatCard({ item, t, de }: { item: StatItem; t: Theme; de: boolean }) {
+ const [hover, setHover] = useState(false)
+ const bgTop = hover ? item.tint + t.statTintTopH : item.tint + t.statTintTop
+ const bgMid = item.tint + t.statTintMid
+ return (
+ setHover(true)}
+ onMouseLeave={() => setHover(false)}
+ style={{
+ position: 'relative', padding: '14px 18px', borderRadius: 12,
+ background: `linear-gradient(180deg, ${bgTop} 0%, ${bgMid} 60%, ${t.cardBase}${t.cardBaseA})`,
+ border: `1px solid ${hover ? item.tint : item.tint + '55'}`,
+ boxShadow: hover ? t.statShadowLift(item.tint) : t.statShadowSoft,
+ transform: hover ? 'translateY(-3px)' : 'translateY(0)',
+ transition: 'all .25s',
+ overflow: 'hidden',
+ backdropFilter: t.key === 'light' ? 'blur(6px)' : 'none',
+ }}>
+
+
+ {de ? item.k.de : item.k.en}
+
+
+ {item.v}
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+}
+
+// ── Detail modal ──────────────────────────────────────────────────────────────
+function DetailModal({ item, onClose, t, de }: {
+ item: Milestone | null; onClose: () => void; t: Theme; de: boolean
+}) {
+ useEffect(() => {
+ if (!item) return
+ const onKey = (e: KeyboardEvent) => { if (e.key === 'Escape') onClose() }
+ window.addEventListener('keydown', onKey)
+ return () => window.removeEventListener('keydown', onKey)
+ }, [item, onClose])
+
+ if (!item) return null
+ const tint = item.tint
+ const badge = item.done
+ ? (de ? 'ABGESCHLOSSEN' : 'COMPLETED')
+ : (item.next ? (de ? 'ALS NÄCHSTES' : 'NEXT UP') : (de ? 'GEPLANT' : 'PLANNED'))
+ const badgeColor = item.done ? t.done : tint
+
+ return (
+
+
e.stopPropagation()} style={{
+ width: 580, maxWidth: '88%',
+ background: `linear-gradient(180deg, ${tint}22 0%, ${t.modalBgMid} 50%, ${t.modalBgLow} 100%)`,
+ border: `1px solid ${tint}77`,
+ borderRadius: 16,
+ boxShadow: t.modalShadow(tint),
+ padding: '24px 28px', color: t.fg,
+ animation: 'msScaleIn .22s ease-out',
+ }}>
+
+
{item.done ? '✓' : (item.next ? '◉' : '○')}
+
+
+ {badge}
+ {item.when}
+
+
+ {de ? item.title.de : item.title.en}
+
+
+
✕
+
+
+ {de ? item.body.de : item.body.en}
+
+
+ {(de ? item.bullets.de : item.bullets.en).map((b, i) => (
+
+
+ {item.done ? '✓' : '▸'}
+
+ {b}
+
+ ))}
+
+
+
+ )
+}
+
+// ── Inner slide (fixed 1280×680) ──────────────────────────────────────────────
+function MilestonesInner({ t, de, sel, setSel }: {
+ t: Theme; de: boolean
+ sel: Milestone | null
+ setSel: (m: Milestone | null) => void
+}) {
+ const doneCnt = useMemo(() => MILESTONES.filter(m => m.done).length, [])
+ const total = MILESTONES.length
+
+ return (
+
+ {/* Ambient glow */}
+
+
+ {t.stars ?
:
}
+
+ {/* Progress indicator */}
+
+
+ {de ? 'Fortschritt' : 'Progress'}
+
+
+
+ {doneCnt}
+ / {total}
+
+
+
+ {/* Tip */}
+
+ {de ? 'Tipp:' : 'Tip:'}
+ {de ? 'Klick auf einen Meilenstein' : 'Click any milestone'}
+
+
+ {/* Timeline */}
+
+
+
+
+ {/* Stats */}
+
+ {STATS.map(s => )}
+
+
+ {/* Footer */}
+
+ {de ? 'Stand heute · live-Metriken aus der Plattform' : 'As of today · live metrics from the platform'}
+
+
+
setSel(null)} t={t} de={de} />
+
+ )
+}
+
+// ── Main slide ────────────────────────────────────────────────────────────────
+const INNER_W = 1280
+const INNER_H = 600
+
+export default function MilestonesSlide({ lang }: MilestonesSlideProps) {
+ const de = lang === 'de'
+ const isLight = useIsLight()
+ const t = isLight ? THEMES.light : THEMES.dark
+ const [sel, setSel] = useState(null)
+ const [scale, setScale] = useState(1)
+ const containerRef = useRef(null)
+
+ const calcScale = useCallback(() => {
+ if (containerRef.current) {
+ const w = containerRef.current.offsetWidth
+ setScale(Math.min(w / INNER_W, 1))
+ }
+ }, [])
+
+ useEffect(() => {
+ calcScale()
+ const obs = new ResizeObserver(calcScale)
+ if (containerRef.current) obs.observe(containerRef.current)
+ return () => obs.disconnect()
+ }, [calcScale])
+
+ return (
+
+
+
+
+
+ {de ? 'Meilensteine' : 'Milestones'}
+
+
+
+
+
+
+
+ )
+}
diff --git a/pitch-deck/components/slides/USPSlide.tsx b/pitch-deck/components/slides/USPSlide.tsx
index 7c0904b..9395992 100644
--- a/pitch-deck/components/slides/USPSlide.tsx
+++ b/pitch-deck/components/slides/USPSlide.tsx
@@ -1,222 +1,830 @@
'use client'
+import { useState, useEffect, useRef, useMemo } from 'react'
+import { motion, AnimatePresence } from 'framer-motion'
import { Language } from '@/lib/types'
import GradientText from '../ui/GradientText'
import FadeInView from '../ui/FadeInView'
-import GlassCard from '../ui/GlassCard'
-import {
- FileCheck,
- Code,
- Zap,
- Shield,
- GitPullRequest,
- ArrowLeftRight,
-} from 'lucide-react'
+import { X } from 'lucide-react'
-interface USPSlideProps {
- lang: Language
+interface USPSlideProps { lang: Language }
+
+const MONO: React.CSSProperties = {
+ fontFamily: '"JetBrains Mono","SF Mono",ui-monospace,monospace',
+ fontVariantNumeric: 'tabular-nums',
}
-export default function USPSlide({ lang }: USPSlideProps) {
- const de = lang === 'de'
+const CSS_KF = `
+ @keyframes uspFlowR { 0%{stroke-dashoffset:0} 100%{stroke-dashoffset:-14px} }
+ @keyframes uspSpin { from{transform:rotate(0deg)} to{transform:rotate(360deg)} }
+ @keyframes uspPulse {
+ 0%,100% { box-shadow: 0 0 38px rgba(167,139,250,.55), 0 0 80px rgba(167,139,250,.2), inset 0 3px 0 rgba(255,255,255,.35), inset 0 -6px 12px rgba(0,0,0,.35); }
+ 50% { box-shadow: 0 0 58px rgba(167,139,250,.85), 0 0 110px rgba(167,139,250,.35), inset 0 3px 0 rgba(255,255,255,.4), inset 0 -6px 12px rgba(0,0,0,.35); }
+ }
+ @keyframes uspPulseLight {
+ 0%,100% { box-shadow: 0 0 28px rgba(167,139,250,.4), 0 0 56px rgba(167,139,250,.15), inset 0 3px 0 rgba(255,255,255,.5), inset 0 -6px 12px rgba(0,0,0,.2); }
+ 50% { box-shadow: 0 0 44px rgba(167,139,250,.65), 0 0 80px rgba(167,139,250,.25), inset 0 3px 0 rgba(255,255,255,.55), inset 0 -6px 12px rgba(0,0,0,.2); }
+ }
+ @keyframes uspHeading {
+ 0%,100% { text-shadow: 0 0 22px rgba(167,139,250,.3); }
+ 50% { text-shadow: 0 0 36px rgba(167,139,250,.55); }
+ }
+`
- const subtitle = de
- ? 'Die erste Plattform, die Compliance-Dokumente und tatsächliche Code-Umsetzung verbindet'
- : 'The first platform that connects compliance documents with actual code implementation'
+// ── Light mode hook ───────────────────────────────────────────────────────────
+function useIsLight() {
+ const [isLight, setIsLight] = useState(false)
+ useEffect(() => {
+ const check = () => setIsLight(document.documentElement.classList.contains('theme-light'))
+ check()
+ const obs = new MutationObserver(check)
+ obs.observe(document.documentElement, { attributes: true, attributeFilter: ['class'] })
+ return () => obs.disconnect()
+ }, [])
+ return isLight
+}
- const complianceItems = de
- ? ['DSGVO-Dokumente', 'Audit-Management', 'RFQ-Anforderungen', 'CE-Bewertungen']
- : ['GDPR documents', 'Audit management', 'RFQ requirements', 'CE assessments']
+// ── Ticker ────────────────────────────────────────────────────────────────────
+function useTicker(fn: () => void, min = 180, max = 420, skip = 0.1) {
+ const ref = useRef(fn)
+ ref.current = fn
+ useEffect(() => {
+ let t: ReturnType
+ const loop = () => {
+ if (Math.random() > skip) ref.current()
+ t = setTimeout(loop, min + Math.random() * (max - min))
+ }
+ loop()
+ return () => clearTimeout(t)
+ }, [min, max, skip])
+}
- const codeItems = de
- ? ['SAST / DAST / SBOM', 'Pentesting', 'Issue-Tracker', 'Auto-Fixes']
- : ['SAST / DAST / SBOM', 'Pentesting', 'Issue tracker', 'Auto-fixes']
+function TickerShell({ tint, isLight, children }: { tint: string; isLight: boolean; children: React.ReactNode }) {
+ return (
+ {children}
+ )
+}
- const capabilities = [
- {
- icon: GitPullRequest,
- color: 'text-indigo-400',
- label: de ? 'RFQ-Prüfung' : 'RFQ Verification',
- desc: de
- ? 'Kunden-Anforderungsdokumente werden automatisiert gegen die aktuelle Source-Code-Umsetzung geprüft. Abweichungen werden erkannt, Änderungen vorgeschlagen und auf Wunsch direkt im Code umgesetzt — ohne manuelles Nacharbeiten.'
+function TickTrace({ tint, isLight }: { tint: string; isLight: boolean }) {
+ const [n, setN] = useState(12748)
+ useTicker(() => setN(v => v + 1 + Math.floor(Math.random() * 3)), 250, 500)
+ return (
+
+ ●
+ trace
+ {n.toLocaleString()}
+ evidence-chain
+
+ )
+}
+
+function TickEngine({ tint, isLight }: { tint: string; isLight: boolean }) {
+ const [v, setV] = useState(428)
+ const [rate, setRate] = useState(99.4)
+ useTicker(() => {
+ setV(x => x + 1 + Math.floor(Math.random() * 4))
+ setRate(r => Math.max(97, Math.min(99.9, r + (Math.random() - 0.5) * 0.3)))
+ }, 220, 420)
+ return (
+
+ ●
+ validate
+ {v.toLocaleString()}
+ {rate.toFixed(1)}%
+
+ )
+}
+
+function TickOptimizer({ tint, isLight }: { tint: string; isLight: boolean }) {
+ const ops = ['ROI: 2.418 € / dev', 'gap → policy §4.2', 'dedup 128 tickets', 'sweet-spot: 22 KLOC', 'tradeoff: speed↔risk']
+ const [i, setI] = useState(0)
+ useTicker(() => setI(x => (x + 1) % ops.length), 900, 1600, 0.05)
+ return (
+
+ ✦
+ optimize
+ {ops[i]}
+
+ )
+}
+
+function TickStack({ tint, isLight }: { tint: string; isLight: boolean }) {
+ const regs = ['DSGVO', 'NIS-2', 'DORA', 'EU AI Act', 'ISO 27001', 'BSI C5']
+ const [i, setI] = useState(0)
+ const [c, setC] = useState(1208)
+ useTicker(() => { setI(x => (x + 1) % regs.length); setC(v => v + Math.floor(Math.random() * 3)) }, 800, 1400, 0.05)
+ return (
+
+ ●
+ check
+ {regs[i]}
+ ·
+ {c.toLocaleString()}
+
+ )
+}
+
+// ── Data ──────────────────────────────────────────────────────────────────────
+interface DetailItem {
+ tint: string
+ icon: string
+ kicker: string
+ title: string
+ body: string
+ bullets?: string[]
+ stat?: { k: string; v: string }
+}
+
+function getDetails(de: boolean): Record {
+ return {
+ rfq: {
+ tint: '#a78bfa', icon: '⇄',
+ kicker: de ? 'Säule · Compliance' : 'Pillar · Compliance',
+ title: de ? 'RFQ-Prüfung' : 'RFQ Verification',
+ body: de
+ ? 'Kunden-Anforderungsdokumente werden automatisch gegen den aktuellen Source-Code geprüft. Abweichungen werden erkannt, Änderungen vorgeschlagen und auf Wunsch direkt im Code umgesetzt — ohne manuelles Nacharbeiten.'
: 'Customer requirement documents are automatically verified against current source code. Deviations are detected, changes proposed and implemented directly in code on request — no manual rework needed.',
+ bullets: de
+ ? ['Klauseln automatisch gegen SBOM, SAST-Findings und Policy-Docs abgeglichen', 'Lücken mit konkreten Implementierungsvorschlägen markiert', 'RFQ-Antworten in Stunden statt Wochen']
+ : ['Auto-match clauses against SBOM, SAST findings and policy docs', 'Flag gaps with concrete implementation proposals', 'Win-ready RFQ replies in hours, not weeks'],
+ stat: { k: de ? 'Ø Antwortzeit' : 'avg response time', v: de ? '4,2h (war 12 Tage)' : '4.2h (was 12 days)' },
},
- {
- icon: ArrowLeftRight,
- color: 'text-purple-400',
- label: de ? 'Bidirektional' : 'Bidirectional',
- desc: de
- ? 'Compliance-Anforderungen fliessen direkt in den Code. Umgekehrt aktualisieren Code-Änderungen automatisch die Compliance-Dokumentation. Beide Seiten sind immer synchron — kein Informationsverlust zwischen Audit und Entwicklung.'
- : 'Compliance requirements flow directly into code. Conversely, code changes automatically update compliance documentation. Both sides always stay in sync — no information loss between audit and development.',
- },
- {
- icon: Zap,
- color: 'text-amber-400',
- label: de ? 'Prozess-Compliance' : 'Process Compliance',
- desc: de
+ process: {
+ tint: '#c084fc', icon: '⟲',
+ kicker: de ? 'Säule · Compliance' : 'Pillar · Compliance',
+ title: de ? 'Prozess-Compliance' : 'Process Compliance',
+ body: de
? 'Vom Audit-Finding über das Ticket bis zur Code-Änderung läuft der gesamte Prozess automatisiert durch. Rollen, Fristen und Eskalation werden End-to-End verwaltet. Nachweise werden automatisch generiert und archiviert.'
: 'From audit finding to ticket to code change, the entire process runs automatically. Roles, deadlines and escalation are managed end-to-end. Evidence is automatically generated and archived.',
+ bullets: de
+ ? ['Finding → Ticket → PR → Nachweis in einem Thread', 'SLA-Tracking pro Control mit Auto-Eskalation', 'Unveränderliches Audit-Log, pro Änderung signiert']
+ : ['Finding → ticket → PR → evidence in one thread', 'SLA tracking per control with auto-escalation', 'Immutable audit log signed per change'],
+ stat: { k: de ? 'automatisierte Prozessschritte' : 'process steps automated', v: '87%' },
},
- {
- icon: Shield,
- color: 'text-emerald-400',
- label: de ? 'Kontinuierlich' : 'Continuous',
- desc: de
+ bidir: {
+ tint: '#fbbf24', icon: '⟷',
+ kicker: de ? 'Säule · Code' : 'Pillar · Code',
+ title: de ? 'Bidirektional' : 'Bidirectional Sync',
+ body: de
+ ? 'Compliance-Anforderungen fliessen direkt in den Code. Umgekehrt aktualisieren Code-Änderungen automatisch die Compliance-Dokumentation. Beide Seiten sind immer synchron — kein Informationsverlust zwischen Audit und Entwicklung.'
+ : 'Compliance requirements flow directly into code. Conversely, code changes automatically update compliance documentation. Both sides always stay in sync — no information loss between audit and development.',
+ bullets: de
+ ? ['Policy ↔ Code-Mapping via semantischem Diff', 'Git-nativ: jede Änderung als PR', 'Zero Drift zwischen Audit-Artefakten und Realität']
+ : ['Policy ↔ code mapping via semantic diff', 'Git-native: every change shipped as a PR', 'Zero drift between audit artefacts and reality'],
+ stat: { k: de ? 'Drift-Vorfälle' : 'drift incidents', v: de ? '0 seit März 2024' : '0 since Mar-2024' },
+ },
+ cont: {
+ tint: '#f59e0b', icon: '◎',
+ kicker: de ? 'Säule · Code' : 'Pillar · Code',
+ title: de ? 'Kontinuierlich' : 'Continuous, Not Yearly',
+ body: de
? 'Klassische Compliance prüft einmal im Jahr und hofft auf das Beste. Unsere Plattform prüft bei jeder Code-Änderung. Findings werden sofort zu Tickets mit konkreten Implementierungsvorschlägen im Issue-Tracker der Wahl.'
: 'Traditional compliance checks once a year and hopes for the best. Our platform checks on every code change. Findings immediately become tickets with concrete implementation proposals in the issue tracker of choice.',
+ bullets: de
+ ? ['CI-integrierte Validierung bei jedem Push', 'Fix-Vorschläge generiert, nicht nur gemeldet', 'Compliance-Frische: Minuten statt Monate']
+ : ['CI-integrated validation on each push', 'Fix suggestions generated, not just reported', 'Compliance freshness: minutes, not months'],
+ stat: { k: de ? 'Validierungen / Tag' : 'validations / day', v: '~2.400 / repo' },
},
- ]
+ trace: {
+ tint: '#a78bfa', icon: '⇄',
+ kicker: de ? 'Under the Hood' : 'Under the Hood',
+ title: de ? 'End-to-End Rückverfolgbarkeit' : 'End-to-End Traceability',
+ body: de
+ ? 'Regulatorische Anforderungen (Gesetz → Obligation → Control) deterministisch mit realem Systemzustand und Code verknüpft — inklusive revisionssicherem Evidence-Layer.'
+ : 'Regulatory requirements (law → obligation → control) deterministically linked to real system state and code — including audit-proof evidence layer.',
+ bullets: de
+ ? ['Versionierter Evidence-Chain, unveränderlich gespeichert', 'Ein Klick von Klausel bis Codezeile', 'Signierte Attestierungen pro Build']
+ : ['Versioned evidence chain stored immutably', 'One-click drill from clause to line of code', 'Signed attestations per build'],
+ },
+ engine: {
+ tint: '#c084fc', icon: '◉',
+ kicker: de ? 'Under the Hood' : 'Under the Hood',
+ title: de ? 'Continuous Compliance Engine' : 'Continuous Compliance Engine',
+ body: de
+ ? 'Statt punktueller Audits: Validierung bei jeder Änderung (Code, Infrastruktur, Prozesse) mit auditierbaren Nachweisen in Echtzeit.'
+ : 'Instead of point-in-time audits: validation on every change (code, infrastructure, processes) with auditable evidence in real time.',
+ bullets: de
+ ? ['Rule-Packs pro Framework (NIS-2, DORA, …)', 'Verarbeitet Code, IaC und Prozess-Events', 'Findings automatisch ans richtige Team geroutet']
+ : ['Rule packs per framework (NIS-2, DORA, …)', 'Handles code, infra-as-code, and process events', 'Findings routed to the right team automatically'],
+ },
+ opt: {
+ tint: '#fbbf24', icon: '✦',
+ kicker: de ? 'Under the Hood' : 'Under the Hood',
+ title: de ? 'Compliance Optimizer' : 'Compliance Optimizer',
+ body: de
+ ? 'Nicht nur „erlaubt/verboten", sondern die maximal zulässige Ausgestaltung jedes KI-Use-Cases. Deterministische Constraint-Optimierung zeigt den Sweet Spot zwischen Regulierung und Innovation — ersetzt 20–200k EUR Anwaltskosten.'
+ : 'Not just "allowed/forbidden" but the maximum permissible configuration of every AI use case. Deterministic constraint optimization shows the sweet spot between regulation and innovation — replaces EUR 20–200k in legal fees.',
+ bullets: de
+ ? ['ROI-Ranking jedes offenen Findings', 'Abwägung zwischen Liefergeschwindigkeit und Restrisiko', 'Low-Hanging-Wins zuerst']
+ : ['ROI-ranks every open finding', 'Balances speed of delivery with residual risk', 'Highlights low-hanging wins first'],
+ },
+ stack: {
+ tint: '#f59e0b', icon: '◎',
+ kicker: de ? 'Under the Hood' : 'Under the Hood',
+ title: de ? 'EU-Trust & Governance Stack' : 'EU Trust & Governance Stack',
+ body: de
+ ? 'Souveräne, DSGVO-/AI-Act-konforme Architektur (EU-Hosting, Isolation, Betriebsrat-Fähigkeit) — Marktzugang, den US-Lösungen strukturell nicht erreichen.'
+ : 'Sovereign, GDPR/AI Act compliant architecture (EU hosting, isolation, works council capability) — market access that US solutions structurally cannot achieve.',
+ bullets: de
+ ? ['DSGVO · NIS-2 · DORA · EU AI Act · ISO 27001 · BSI C5', 'EU-souveränes Hosting und Key-Management', 'Eine Plattform, ein Audit, eine Rechnung']
+ : ['DSGVO · NIS-2 · DORA · EU AI Act · ISO 27001 · BSI C5', 'EU-sovereign hosting and key-management', 'One platform, one audit, one bill'],
+ },
+ hub: {
+ tint: '#a78bfa', icon: '∞',
+ kicker: de ? 'Die Schleife' : 'The Loop',
+ title: de ? 'Compliance ↔ Code · Immer in Sync' : 'Compliance ↔ Code · Always in sync',
+ body: de
+ ? 'Die Plattform ist eine einzige geschlossene Schleife. Jede Policy-Änderung fliesst in den Code; jede Code-Änderung fliesst in die Policy zurück.'
+ : 'The platform is a single closed loop. Every policy change ripples into code; every code change ripples back into policy. That\'s the USP in one diagram.',
+ bullets: de
+ ? ['Single Source of Truth, zwei Oberflächen', 'Echtzeit-Sync, kein Batch-Abgleich', 'Auditoren, Entwickler und Sales fragen denselben Graphen ab']
+ : ['Single source of truth, two surfaces', 'Real-time sync, not batch reconciliation', 'Auditors, engineers and sales all query the same graph'],
+ },
+ }
+}
+
+// ── Pillar row ────────────────────────────────────────────────────────────────
+function PillarRow({ side, title, body, tint, onClick, active, isLight }: {
+ side: 'left' | 'right'
+ title: string; body: string; tint: string
+ onClick: () => void; active: boolean; isLight: boolean
+}) {
+ const [hover, setHover] = useState(false)
+ const lit = hover || active
+ const isLeft = side === 'left'
+ return (
+ setHover(true)}
+ onMouseLeave={() => setHover(false)}
+ style={{
+ display: 'flex', alignItems: 'flex-start', gap: 12,
+ flexDirection: isLeft ? 'row-reverse' : 'row',
+ textAlign: isLeft ? 'right' : 'left',
+ padding: '10px 14px', borderRadius: 10, cursor: 'pointer',
+ transition: 'transform .25s, background .25s, box-shadow .25s',
+ background: lit
+ ? `linear-gradient(${isLeft ? '270deg' : '90deg'}, ${tint}24 0%, ${tint}0a 70%, transparent 100%)`
+ : 'transparent',
+ boxShadow: lit
+ ? `0 10px 30px ${tint}26, inset 0 0 0 1px ${tint}44`
+ : 'inset 0 0 0 1px transparent',
+ transform: lit ? (isLeft ? 'translateX(-3px)' : 'translateX(3px)') : 'translateX(0)',
+ }}
+ >
+
◆
+
+
+ {title}
+ {isLeft ? '‹' : '›'}
+
+
{body}
+
+
+ )
+}
+
+// ── Column header ─────────────────────────────────────────────────────────────
+function ColHeader({ side, label, color, icon, sub, isLight }: {
+ side: 'left' | 'right'; label: string; color: string; icon: string; sub: string; isLight: boolean
+}) {
+ const isLeft = side === 'left'
+ return (
+
+ )
+}
+
+// ── Central hub ───────────────────────────────────────────────────────────────
+function CentralHub({ caption, isLight }: { caption: string; isLight: boolean }) {
+ return (
+
+ )
+}
+
+// ── Bridge SVG connectors ─────────────────────────────────────────────────────
+function BridgeConnectors({ isLight }: { isLight: boolean }) {
+ const rfpY = 130
+ const sub2Y = 250
+ const hubCx = 500
+ const hubR = 72
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {([rfpY, sub2Y] as number[]).map(y => (
+
+
+
+
+
+
+ ))}
+
+
+
+
+
+
+
+
+
+
+ )
+}
+
+// ── Under-the-hood feature card ───────────────────────────────────────────────
+function FeatureCard({ icon, title, body, tint, Ticker, onClick, active, isLight }: {
+ icon: string; title: string; body: string; tint: string
+ Ticker: React.ComponentType<{ tint: string; isLight: boolean }>
+ onClick: () => void; active: boolean; isLight: boolean
+}) {
+ const [hover, setHover] = useState(false)
+ const lit = hover || active
+ return (
+ setHover(true)}
+ onMouseLeave={() => setHover(false)}
+ style={{
+ position: 'relative', padding: '13px 15px',
+ background: isLight
+ ? lit
+ ? `linear-gradient(180deg, ${tint}18 0%, ${tint}08 55%, rgba(248,250,252,.95) 100%)`
+ : 'linear-gradient(180deg, #ffffff, #f8fafc)'
+ : `linear-gradient(180deg, ${tint}${lit ? '2a' : '1a'} 0%, ${tint}07 55%, rgba(14,8,28,.85) 100%)`,
+ border: `1px solid ${lit ? tint : isLight ? 'rgba(0,0,0,.1)' : tint + '4a'}`,
+ borderRadius: 12,
+ boxShadow: lit
+ ? `0 18px 40px ${tint}33, 0 0 0 1px ${tint}66, inset 0 1px 0 ${tint}60`
+ : isLight
+ ? '0 2px 8px rgba(0,0,0,.08), inset 0 1px 0 rgba(255,255,255,.8)'
+ : `0 10px 24px rgba(0,0,0,.4), inset 0 1px 0 ${tint}35`,
+ minWidth: 0, cursor: 'pointer',
+ transform: lit ? 'translateY(-3px)' : 'translateY(0)',
+ transition: 'transform .25s, box-shadow .25s, background .25s, border-color .25s',
+ }}
+ >
+
+ {icon}
+ {title}
+ ↗
+
+
{body}
+
+
+ )
+}
+
+// ── Detail modal ──────────────────────────────────────────────────────────────
+function DetailModal({ item, onClose, isLight }: { item: DetailItem | null; onClose: () => void; isLight: boolean }) {
+ useEffect(() => {
+ if (!item) return
+ const onKey = (e: KeyboardEvent) => { if (e.key === 'Escape') onClose() }
+ window.addEventListener('keydown', onKey)
+ return () => window.removeEventListener('keydown', onKey)
+ }, [item, onClose])
+
+ return (
+
+ {item && (
+
+ e.stopPropagation()}
+ style={{
+ width: 560, maxWidth: '88%',
+ background: isLight
+ ? `linear-gradient(180deg, ${item.tint}10 0%, rgba(255,255,255,.98) 50%, rgba(248,250,252,.99) 100%)`
+ : `linear-gradient(180deg, ${item.tint}18 0%, rgba(20,10,40,.96) 50%, rgba(14,8,28,.98) 100%)`,
+ border: `1px solid ${item.tint}${isLight ? '44' : '66'}`,
+ borderRadius: 16,
+ boxShadow: isLight
+ ? `0 20px 60px rgba(0,0,0,.12), 0 0 40px ${item.tint}18, inset 0 1px 0 rgba(255,255,255,.9)`
+ : `0 30px 80px rgba(0,0,0,.6), 0 0 60px ${item.tint}33, inset 0 1px 0 ${item.tint}55`,
+ padding: '22px 26px',
+ color: isLight ? '#1a1a2e' : '#ece9f7',
+ }}
+ >
+
+
{item.icon}
+
+
+ {item.kicker}
+
+
{item.title}
+
+
+
+
+
+
+ {item.body}
+
+ {item.bullets && (
+
+ {item.bullets.map((b, i) => (
+
+ ▸
+ {b}
+
+ ))}
+
+ )}
+ {item.stat && (
+
+ ●
+ {item.stat.k}
+ {item.stat.v}
+
+ )}
+
+
+ )}
+
+ )
+}
+
+// ── Star field ────────────────────────────────────────────────────────────────
+function StarField({ isLight }: { isLight: boolean }) {
+ const stars = useMemo(() => {
+ let s = 41
+ const r = () => { s = (s * 9301 + 49297) % 233280; return s / 233280 }
+ return Array.from({ length: 90 }, () => ({ x: r() * 100, y: r() * 100, size: r() * 1.4 + 0.3, op: r() * 0.5 + 0.15 }))
+ }, [])
+ if (isLight) return null
+ return (
+
+ {stars.map((st, i) => (
+
+ ))}
+
+ )
+}
+
+// ── Main slide ────────────────────────────────────────────────────────────────
+export default function USPSlide({ lang }: USPSlideProps) {
+ const de = lang === 'de'
+ const isLight = useIsLight()
+ const details = getDetails(de)
+ const [detail, setDetail] = useState(null)
+ const open = (k: string) => setDetail(details[k])
+ const close = () => setDetail(null)
return (
-
-
+
+
+
+
USP
- {subtitle}
-
-
+
+ {/* ── MAIN CANVAS ───────────────────────────────────────────────── */}
+
+ {/* Ambient glow — dark only */}
+ {!isLight && (
+
+ )}
+
- {/* CENTER: Large circle */}
-
-
-
-
-
-
-
-
-
- Compliance
-
-
- {complianceItems.map((item, idx) => (
-
-
- {item}
-
- ))}
-
-
-
-
-
-
- Code
-
-
- {codeItems.map((item, idx) => (
-
-
- {item}
-
- ))}
-
-
-
-
◀
-
▶
-
◀
-
▶
+ {/* Interaction hint */}
+
+
+ {de ? 'Element anklicken' : 'Click any element'}
- {/* 4 CORNER CARDS */}
- {capabilities.map((cap, idx) => {
- 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 (
-
-
-
-
-
{cap.label}
+ {/* Bridge */}
+
+
+
+ {/* LEFT — Compliance */}
+
+
+
+
+
+
+
open('rfq')}
+ active={detail?.title === details.rfq.title}
+ />
-
{cap.desc}
-
+
+
+
+
open('process')}
+ active={detail?.title === details.process.title}
+ />
+
+
- )
- })}
- {/* SVG connection lines */}
-
-
-
-
-
-
-
-
+ {/* CENTER hub */}
+
+
open('hub')}
+ style={{ cursor: 'pointer', transition: 'transform .25s, filter .25s' }}
+ onMouseEnter={e => { (e.currentTarget as HTMLDivElement).style.transform = 'scale(1.05)'; (e.currentTarget as HTMLDivElement).style.filter = 'brightness(1.15)' }}
+ onMouseLeave={e => { (e.currentTarget as HTMLDivElement).style.transform = 'scale(1)'; (e.currentTarget as HTMLDivElement).style.filter = 'brightness(1)' }}
+ >
+
+
+
- {/* MOAT — 3 Sätze */}
-
-
- {de ? 'Unser MOAT' : 'Our MOAT'}
-
-
-
-
-
-
End-to-End Traceability
+ {/* RIGHT — Code */}
+
+
+
+
+
+
+
open('bidir')}
+ active={detail?.title === details.bidir.title}
+ />
+
+
+
+
+
open('cont')}
+ active={detail?.title === details.cont.title}
+ />
+
+
+
-
- {de
- ? 'Regulatorische Anforderungen (Gesetz → Obligation → Control) deterministisch mit realem Systemzustand und Code verknüpft — inklusive revisionssicherem Evidence-Layer.'
- : 'Regulatory requirements (law → obligation → control) deterministically linked to real system state and code — including audit-proof evidence layer.'}
-
-
-
-
-
-
Continuous Compliance Engine
-
-
- {de
- ? 'Statt punktueller Audits: Validierung bei jeder Änderung (Code, Infrastruktur, Prozesse) mit auditierbaren Nachweisen in Echtzeit.'
- : 'Instead of point-in-time audits: validation on every change (code, infrastructure, processes) with auditable evidence in real time.'}
-
-
-
-
-
-
Compliance Optimizer
-
-
- {de
- ? 'Nicht nur „erlaubt/verboten", sondern die maximal zulässige Ausgestaltung jedes KI-Use-Cases. Deterministische Constraint-Optimierung zeigt den Sweet Spot zwischen Regulierung und Innovation — ersetzt 20-200k EUR Anwaltskosten.'
- : 'Not just "allowed/forbidden" but the maximum permissible configuration of every AI use case. Deterministic constraint optimization shows the sweet spot between regulation and innovation — replaces EUR 20-200k in legal fees.'}
-
-
-
-
-
-
EU-Trust & Governance Stack
-
-
- {de
- ? 'Souveräne, DSGVO-/AI-Act-konforme Architektur (EU-Hosting, Isolation, Betriebsrat-Fähigkeit) — Marktzugang, den US-Lösungen strukturell nicht erreichen.'
- : 'Sovereign, GDPR/AI Act compliant architecture (EU hosting, isolation, works council capability) — market access that US solutions structurally cannot achieve.'}
-
-
-
-
+
- {/* Killer Quote */}
-
-
-
+ {/* Under the Hood */}
+
+
+
+ {de ? 'Unter der Haube' : 'Under the Hood'}
+
+
+
+ open('trace')}
+ active={detail?.title === details.trace.title}
+ Ticker={TickTrace}
+ />
+ open('engine')}
+ active={detail?.title === details.engine.title}
+ Ticker={TickEngine}
+ />
+ open('opt')}
+ active={detail?.title === details.opt.title}
+ Ticker={TickOptimizer}
+ />
+ open('stack')}
+ active={detail?.title === details.stack.title}
+ Ticker={TickStack}
+ />
+
+
+
+ {/* Killer quote */}
+
+ "
{de
- ? '„Jeder kann sagen, was verboten ist. Kaum jemand kann sagen, wie weit du maximal gehen kannst. Das ist unser Produkt."'
- : '"Everyone can say what is forbidden. Almost no one can say how far you can go. That is our product."'}
-
+ ? 'Jeder kann sagen, was verboten ist. Kaum jemand kann sagen, wie weit du maximal gehen kannst. Das ist unser Produkt.'
+ : 'Anyone can say what\'s forbidden. Almost no one can tell you how far you can actually go. That\'s our product.'}
+ "
+
+
+
diff --git a/pitch-deck/lib/i18n.ts b/pitch-deck/lib/i18n.ts
index a3e68b3..b6abff2 100644
--- a/pitch-deck/lib/i18n.ts
+++ b/pitch-deck/lib/i18n.ts
@@ -26,7 +26,7 @@ const translations = {
'Investition & Cap Table',
'Kundenersparnis',
'KI Q&A',
- 'Anhang: Architektur',
+ 'Anhang: Systemarchitektur',
'Anhang: Regulatorik',
'Anhang: Engineering',
'Anhang: KI-Pipeline',
@@ -276,8 +276,8 @@ const translations = {
subtitle: 'Drei Szenarien für robuste Planung',
},
architecture: {
- title: 'Technische Architektur',
- subtitle: 'Self-Hosted KI-Stack für maximale Datensouveränität',
+ title: 'Systemarchitektur',
+ subtitle: 'BreakPilot · CERTifAI · Compliance Scanner — verbunden über LiteLLM',
},
gtm: {
title: 'Go-to-Market Strategie',
@@ -322,7 +322,7 @@ const translations = {
'Investment & Cap Table',
'Customer Savings',
'AI Q&A',
- 'Appendix: Architecture',
+ 'Appendix: System Architecture',
'Appendix: Regulatory',
'Appendix: Engineering',
'Appendix: AI Pipeline',
@@ -572,8 +572,8 @@ const translations = {
subtitle: 'Three scenarios for robust planning',
},
architecture: {
- title: 'Technical Architecture',
- subtitle: 'Self-hosted AI stack for maximum data sovereignty',
+ title: 'System Architecture',
+ subtitle: 'BreakPilot · CERTifAI · Compliance Scanner — connected via LiteLLM',
},
gtm: {
title: 'Go-to-Market Strategy',
diff --git a/pitch-deck/middleware.ts b/pitch-deck/middleware.ts
index 5a0f33d..2cfd3ba 100644
--- a/pitch-deck/middleware.ts
+++ b/pitch-deck/middleware.ts
@@ -34,6 +34,11 @@ export async function middleware(request: NextRequest) {
const { pathname } = request.nextUrl
const secret = process.env.PITCH_JWT_SECRET
+ // Skip all auth in local dev when no secret is configured
+ if (!secret && process.env.NODE_ENV === 'development') {
+ return NextResponse.next()
+ }
+
// Allow public paths
if (isPublicPath(pathname)) {
return NextResponse.next()
diff --git a/pitch-deck/package.json b/pitch-deck/package.json
index 2c0a658..e78f486 100644
--- a/pitch-deck/package.json
+++ b/pitch-deck/package.json
@@ -3,7 +3,7 @@
"version": "1.0.0",
"private": true,
"scripts": {
- "dev": "next dev -p 3012",
+ "dev": "next dev --turbopack -p 3012",
"build": "next build",
"start": "next start -p 3012",
"admin:create": "tsx scripts/create-admin.ts",