'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 (