Problem: Regulierungs-Tsunami (5+ Gesetze, persoenliche GF-Haftung), jaehrliche Stichproben (50k+ EUR/Jahr), Datensouveraenitaet (0 DE-Alternativen) Loesung: Kontinuierliche Code-Security statt Stichproben, Compliance auf Autopilot (VVT, TOMs, DSFA, Loeschfristen, CE), Deutsche Cloud (BSI DE / OVH FR), Jitsi, Matrix, Jira-Integration ROI: Kunde zahlt 50k/Jahr, spart 50k+ (Pentests, CE, Auditmanager) DB: Funding 1M EUR, SOM 24M EUR Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
219 lines
8.5 KiB
TypeScript
219 lines
8.5 KiB
TypeScript
'use client'
|
|
|
|
import { useState } from 'react'
|
|
import { motion, AnimatePresence } from 'framer-motion'
|
|
import { Language } from '@/lib/types'
|
|
import { t } from '@/lib/i18n'
|
|
import { AlertTriangle, Scale, Shield, ExternalLink, X } from 'lucide-react'
|
|
import GlassCard from '../ui/GlassCard'
|
|
import GradientText from '../ui/GradientText'
|
|
import FadeInView from '../ui/FadeInView'
|
|
|
|
interface ProblemSlideProps {
|
|
lang: Language
|
|
}
|
|
|
|
interface SourceInfo {
|
|
name: string
|
|
url: string
|
|
date: string
|
|
excerpt_de: string
|
|
excerpt_en: string
|
|
}
|
|
|
|
interface ProblemCardData {
|
|
sources: SourceInfo[]
|
|
}
|
|
|
|
// Quellenangaben fuer jede Behauptung
|
|
const cardSources: ProblemCardData[] = [
|
|
{
|
|
// Regulierungs-Tsunami: 5+ Gesetze, persoenliche Haftung
|
|
sources: [
|
|
{
|
|
name: 'DIHK Digitalisierungsumfrage 2024',
|
|
url: 'https://www.dihk.de/de/themen-und-positionen/wirtschaft-digital/digitalisierung',
|
|
date: '2024',
|
|
excerpt_de: '83% der KMU geben an, die DSGVO-Anforderungen nicht vollstaendig umgesetzt zu haben. Hauptgruende: mangelnde Ressourcen, fehlendes Know-how und die Komplexitaet der Vorschriften. Mit AI Act, CRA und NIS2 verschaerft sich die Lage drastisch.',
|
|
excerpt_en: '83% of SMEs report not having fully implemented GDPR requirements. Main reasons: lack of resources, missing expertise, and regulatory complexity. With AI Act, CRA and NIS2, the situation is getting drastically worse.',
|
|
},
|
|
{
|
|
name: 'DSGVO Art. 83 — Persoenliche Haftung',
|
|
url: 'https://www.enforcementtracker.com/',
|
|
date: '2025',
|
|
excerpt_de: 'Ueber 4,1 Mrd. EUR Bussgelder seit 2018. Art. 83 DSGVO sieht Bussgelder bis 20 Mio. EUR oder 4% des Jahresumsatzes vor. Geschaeftsfuehrer haften bei Organisationsverschulden persoenlich.',
|
|
excerpt_en: 'Over EUR 4.1B in fines since 2018. Art. 83 GDPR provides for fines up to EUR 20M or 4% of annual turnover. CEOs are personally liable for organizational negligence.',
|
|
},
|
|
],
|
|
},
|
|
{
|
|
// Jaehrliche Stichproben: 50.000+ EUR/Jahr
|
|
sources: [
|
|
{
|
|
name: 'VDMA Branchenanalyse — Compliance-Kosten Maschinenbau',
|
|
url: 'https://www.vdma.org/',
|
|
date: '2024',
|
|
excerpt_de: 'Externe Pentests kosten 15.000-40.000 EUR pro Durchlauf. CE-Software-Risikobeurteilungen 10.000-25.000 EUR. Diese Pruefungen erfolgen typischerweise einmal jaehrlich und decken nur eine Momentaufnahme ab — nicht den laufenden Entwicklungsprozess.',
|
|
excerpt_en: 'External pentests cost EUR 15,000-40,000 per run. CE software risk assessments EUR 10,000-25,000. These audits typically occur once annually, covering only a snapshot — not the ongoing development process.',
|
|
},
|
|
],
|
|
},
|
|
{
|
|
// Datensouveraenitaet: 0 Alternativen
|
|
sources: [
|
|
{
|
|
name: 'Bitkom Cloud Monitor 2024',
|
|
url: 'https://www.bitkom.org/Themen/Datenschutz-Sicherheit/Cloud-Monitor',
|
|
date: '2024',
|
|
excerpt_de: 'Laut Bitkom Cloud Monitor lehnen 64% der deutschen Industrieunternehmen US-Cloud-Dienste fuer sensible Daten ab. Im Maschinenbau liegt die Ablehnung bei ueber 70%. Die Gruende: Schrems II, CLOUD Act und mangelndes Vertrauen in US-Datenschutzstandards.',
|
|
excerpt_en: 'According to Bitkom Cloud Monitor, 64% of German industrial companies reject US cloud services for sensitive data. In machine manufacturing, rejection exceeds 70%. Reasons: Schrems II, CLOUD Act and lack of trust in US data protection standards.',
|
|
},
|
|
],
|
|
},
|
|
]
|
|
|
|
const icons = [AlertTriangle, Scale, Shield]
|
|
|
|
function SourceModal({
|
|
isOpen,
|
|
onClose,
|
|
cardIndex,
|
|
lang,
|
|
cardTitle,
|
|
}: {
|
|
isOpen: boolean
|
|
onClose: () => void
|
|
cardIndex: number
|
|
lang: Language
|
|
cardTitle: string
|
|
}) {
|
|
if (!isOpen) return null
|
|
const sources = cardSources[cardIndex]?.sources || []
|
|
|
|
return (
|
|
<AnimatePresence>
|
|
{isOpen && (
|
|
<motion.div
|
|
initial={{ opacity: 0 }}
|
|
animate={{ opacity: 1 }}
|
|
exit={{ opacity: 0 }}
|
|
className="fixed inset-0 z-50 flex items-center justify-center p-4"
|
|
onClick={onClose}
|
|
>
|
|
<div className="absolute inset-0 bg-black/60 backdrop-blur-sm" />
|
|
<motion.div
|
|
initial={{ scale: 0.9, opacity: 0 }}
|
|
animate={{ scale: 1, opacity: 1 }}
|
|
exit={{ scale: 0.9, opacity: 0 }}
|
|
className="relative bg-slate-900/95 border border-white/10 rounded-2xl p-6 max-w-2xl w-full max-h-[80vh] overflow-y-auto"
|
|
onClick={(e) => e.stopPropagation()}
|
|
>
|
|
<button
|
|
onClick={onClose}
|
|
className="absolute top-4 right-4 p-1 text-white/40 hover:text-white/80 transition-colors"
|
|
>
|
|
<X className="w-5 h-5" />
|
|
</button>
|
|
|
|
<h3 className="text-xl font-bold text-white mb-1">{cardTitle}</h3>
|
|
<p className="text-sm text-white/40 mb-6">
|
|
{lang === 'de' ? 'Quellenangaben' : 'Sources'}
|
|
</p>
|
|
|
|
<div className="space-y-4">
|
|
{sources.map((src, idx) => (
|
|
<div
|
|
key={idx}
|
|
className="bg-white/[0.05] border border-white/10 rounded-xl p-4"
|
|
>
|
|
<div className="flex items-start justify-between gap-3 mb-2">
|
|
<div>
|
|
<p className="text-sm font-semibold text-white">{src.name}</p>
|
|
<p className="text-xs text-white/30">{src.date}</p>
|
|
</div>
|
|
<a
|
|
href={src.url}
|
|
target="_blank"
|
|
rel="noopener noreferrer"
|
|
className="flex-shrink-0 p-1.5 text-indigo-400 hover:text-indigo-300 hover:bg-indigo-500/10 rounded-lg transition-colors"
|
|
title={lang === 'de' ? 'Quelle oeffnen' : 'Open source'}
|
|
>
|
|
<ExternalLink className="w-4 h-4" />
|
|
</a>
|
|
</div>
|
|
<p className="text-sm text-white/60 leading-relaxed">
|
|
{lang === 'de' ? src.excerpt_de : src.excerpt_en}
|
|
</p>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</motion.div>
|
|
</motion.div>
|
|
)}
|
|
</AnimatePresence>
|
|
)
|
|
}
|
|
|
|
export default function ProblemSlide({ lang }: ProblemSlideProps) {
|
|
const i = t(lang)
|
|
const [activeModal, setActiveModal] = useState<number | null>(null)
|
|
|
|
return (
|
|
<div>
|
|
<FadeInView className="text-center mb-12">
|
|
<h2 className="text-4xl md:text-5xl font-bold mb-3">
|
|
<GradientText>{i.problem.title}</GradientText>
|
|
</h2>
|
|
<p className="text-lg text-white/50 max-w-2xl mx-auto">{i.problem.subtitle}</p>
|
|
</FadeInView>
|
|
|
|
<div className="grid md:grid-cols-3 gap-6 mb-12">
|
|
{i.problem.cards.map((card, idx) => {
|
|
const Icon = icons[idx]
|
|
const sourceCount = cardSources[idx]?.sources.length || 0
|
|
return (
|
|
<GlassCard
|
|
key={idx}
|
|
delay={0.2 + idx * 0.15}
|
|
className="text-center cursor-pointer group"
|
|
onClick={() => setActiveModal(idx)}
|
|
>
|
|
<div className="w-12 h-12 mx-auto mb-4 rounded-xl bg-red-500/10 flex items-center justify-center">
|
|
<Icon className="w-6 h-6 text-red-400" />
|
|
</div>
|
|
<h3 className="text-lg font-bold mb-2 text-white">{card.title}</h3>
|
|
<p className="text-3xl font-bold text-red-400 mb-3">{card.stat}</p>
|
|
<p className="text-sm text-white/50 leading-relaxed mb-3">{card.desc}</p>
|
|
<p className="text-[10px] text-indigo-400/60 group-hover:text-indigo-400 transition-colors">
|
|
{sourceCount} {lang === 'de' ? (sourceCount === 1 ? 'Quelle' : 'Quellen') : (sourceCount === 1 ? 'source' : 'sources')}
|
|
{' · '}
|
|
{lang === 'de' ? 'Klicken fuer Details' : 'Click for details'}
|
|
</p>
|
|
</GlassCard>
|
|
)
|
|
})}
|
|
</div>
|
|
|
|
<FadeInView delay={0.8} className="max-w-3xl mx-auto">
|
|
<blockquote className="text-center">
|
|
<p className="text-lg md:text-xl text-white/70 italic leading-relaxed">
|
|
“{i.problem.quote}”
|
|
</p>
|
|
</blockquote>
|
|
</FadeInView>
|
|
|
|
{/* Source Modals */}
|
|
{i.problem.cards.map((card, idx) => (
|
|
<SourceModal
|
|
key={idx}
|
|
isOpen={activeModal === idx}
|
|
onClose={() => setActiveModal(null)}
|
|
cardIndex={idx}
|
|
lang={lang}
|
|
cardTitle={card.title}
|
|
/>
|
|
))}
|
|
</div>
|
|
)
|
|
}
|