Files
breakpilot-core/pitch-deck/components/slides/CompetitionSlide.tsx
Benjamin Admin 38363b2837 feat(pitch-deck): rewrite CompetitionSlide with 6 detailed competitor profiles
- Add Vanta, Drata, Sprinto (international) alongside Proliance, DataGuard, heyData (DACH)
- Each card: HQ city/country, offices, employees, revenue, customers + countries, funding, investors, AI badge
- Two tabs: Overview & Comparison / Feature Matrix (Detail)
- 44-feature comparison table with collapsible sections: Top 5 Unterschiede, Alle Features, USP
- Efficiency ratios table (revenue/employee, customers/employee)
- DACH landscape note (Secjur, Usercentrics, Caralegal, 2B Advice, OneTrust)
- Research-backed data: Vanta $220M/$4.15B, Drata $100M/$2B, Sprinto $38M, DataGuard €52M, heyData €15M
- Dynamic feature/USP counts in subtitle
- Bilingual (de/en) with i18n subtitle update

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-20 08:26:20 +01:00

622 lines
32 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
'use client'
import { useState } from 'react'
import { Language, PitchFeature, PitchCompetitor } from '@/lib/types'
import { t } from '@/lib/i18n'
import {
ChevronDown, ChevronRight, Globe, Building2, Users, TrendingUp,
DollarSign, Cpu, Star, Check, X, Minus,
} from 'lucide-react'
import GradientText from '../ui/GradientText'
import FadeInView from '../ui/FadeInView'
import GlassCard from '../ui/GlassCard'
import BrandName from '../ui/BrandName'
interface CompetitionSlideProps {
lang: Language
features: PitchFeature[]
competitors: PitchCompetitor[]
}
// ─── Extended Competitor Data ──────────────────────────────────────────────────
interface ExtendedCompetitor {
name: string
flag: string
hq: string
hqCountry: string
offices: string[]
founded: number
employees: number
revenue: string
revenueNum: number
customers: number
customerCountries: string
fundingTotal: string
fundingRound: string
investors: string[]
aiUsage: 'full' | 'partial' | 'none'
aiDetail: { de: string; en: string }
market: { de: string; en: string }
pricing: string
isInternational: boolean
}
const EXTENDED_COMPETITORS: ExtendedCompetitor[] = [
{
name: 'Vanta',
flag: '🇺🇸',
hq: 'San Francisco, CA',
hqCountry: 'USA',
offices: ['New York', 'Dublin', 'London', 'Sydney'],
founded: 2018,
employees: 1695,
revenue: '$220M ARR',
revenueNum: 220_000_000,
customers: 12000,
customerCountries: '58 Laender',
fundingTotal: '$504M',
fundingRound: 'Series D ($150M, $4.15B val.)',
investors: ['Sequoia Capital', 'Wellington Mgmt', 'Craft Ventures', 'CrowdStrike', 'Goldman Sachs', 'Y Combinator'],
aiUsage: 'full',
aiDetail: { de: 'Vanta AI Agent: Agentic Compliance, Policy-Gen, VRM-Agent, ISO 42001', en: 'Vanta AI Agent: Agentic compliance, policy gen, VRM agent, ISO 42001' },
market: { de: 'Global — SOC 2, ISO 27001, HIPAA, PCI DSS', en: 'Global — SOC 2, ISO 27001, HIPAA, PCI DSS' },
pricing: '$10K80K/yr',
isInternational: true,
},
{
name: 'Drata',
flag: '🇺🇸',
hq: 'San Diego, CA',
hqCountry: 'USA',
offices: ['San Diego'],
founded: 2020,
employees: 732,
revenue: '$100M ARR',
revenueNum: 100_000_000,
customers: 8000,
customerCountries: '80+ Laender',
fundingTotal: '$328M',
fundingRound: 'Series C ($200M, $2B val.)',
investors: ['ICONIQ Growth', 'GGV Capital', 'Salesforce Ventures', 'SentinelOne'],
aiUsage: 'full',
aiDetail: { de: 'AI Agent: VRM, Doc-Review, Risiko-Scoring, SafeBase AIQA', en: 'AI Agent: VRM, doc review, risk scoring, SafeBase AIQA' },
market: { de: 'Global — SOC 2, ISO, HIPAA, GDPR (oberfl.)', en: 'Global — SOC 2, ISO, HIPAA, GDPR (shallow)' },
pricing: '$10K100K/yr',
isInternational: true,
},
{
name: 'Sprinto',
flag: '🇮🇳',
hq: 'Bangalore',
hqCountry: 'Indien',
offices: ['Bangalore'],
founded: 2020,
employees: 316,
revenue: '$38M ARR',
revenueNum: 38_000_000,
customers: 3000,
customerCountries: '75+ Laender',
fundingTotal: '$32M',
fundingRound: 'Series B ($20M, 2024)',
investors: ['Accel', 'Elevation Capital', 'Blume Ventures'],
aiUsage: 'full',
aiDetail: { de: 'Autonomous Compliance Engine, No-Code AI Agent Builder', en: 'Autonomous compliance engine, no-code AI agent builder' },
market: { de: 'Global SMBs — SOC 2, ISO, GDPR', en: 'Global SMBs — SOC 2, ISO, GDPR' },
pricing: '$6K25K/yr',
isInternational: true,
},
{
name: 'Proliance',
flag: '🇩🇪',
hq: 'Muenchen',
hqCountry: 'Deutschland',
offices: ['Muenchen'],
founded: 2017,
employees: 65,
revenue: '~€3.9M',
revenueNum: 3_900_000,
customers: 2000,
customerCountries: 'DACH',
fundingTotal: 'Pre-Seed',
fundingRound: 'Pre-Seed (Possible Ventures)',
investors: ['Possible Ventures'],
aiUsage: 'none',
aiDetail: { de: 'Basis-Risikoerkennung, keine LLM/Agenten', en: 'Basic risk detection, no LLM/agents' },
market: { de: 'DACH — DSGVO, ePrivacy, KMUs', en: 'DACH — GDPR, ePrivacy, SMBs' },
pricing: '€1.5K5.7K/yr',
isInternational: false,
},
{
name: 'DataGuard',
flag: '🇩🇪',
hq: 'Muenchen',
hqCountry: 'Deutschland',
offices: ['Muenchen', 'Berlin', 'London', 'Wien', 'Stockholm'],
founded: 2017,
employees: 250,
revenue: '~€52M',
revenueNum: 52_000_000,
customers: 4000,
customerCountries: '50+ Laender',
fundingTotal: '€80M',
fundingRound: 'Series B (€61M, €341M val.)',
investors: ['Morgan Stanley Expansion', 'One Peak Partners'],
aiUsage: 'partial',
aiDetail: { de: 'Marketing: 40% weniger Aufwand, keine Agenten/LLM', en: 'Marketing: 40% effort reduction, no agents/LLM' },
market: { de: 'DACH + UK — GDPR, ISO 27001, TISAX', en: 'DACH + UK — GDPR, ISO 27001, TISAX' },
pricing: '€6K24K+/yr',
isInternational: false,
},
{
name: 'heyData',
flag: '🇩🇪',
hq: 'Berlin',
hqCountry: 'Deutschland',
offices: ['Berlin'],
founded: 2020,
employees: 58,
revenue: '~€15M',
revenueNum: 15_000_000,
customers: 2000,
customerCountries: 'EU',
fundingTotal: '€18.3M',
fundingRound: 'Series A ($16.5M, Jan 2026)',
investors: ['Riverside Acceleration Capital'],
aiUsage: 'partial',
aiDetail: { de: 'KI-Marketing, keine sichtbaren Agenten', en: 'AI marketing, no visible agents' },
market: { de: 'DACH + EU — DSGVO, Kleinunternehmen', en: 'DACH + EU — GDPR, small businesses' },
pricing: '€1K3.8K/yr',
isInternational: false,
},
]
// ─── Feature Comparison Data ───────────────────────────────────────────────────
type FeatureStatus = true | false | 'partial'
interface ComparisonFeature {
de: string
en: string
bp: FeatureStatus
vanta: FeatureStatus
drata: FeatureStatus
sprinto: FeatureStatus
proliance: FeatureStatus
dataguard: FeatureStatus
heydata: FeatureStatus
isDiff: boolean
isUSP: boolean
}
const ALL_FEATURES: ComparisonFeature[] = [
// Top 5 Differentiators (isDiff=true) — no other vendor has ANY of these
{ de: 'Self-Hosted / On-Premise', en: 'Self-Hosted / On-Premise', bp: true, vanta: false, drata: false, sprinto: false, proliance: false, dataguard: false, heydata: false, isDiff: true, isUSP: true },
{ de: 'Code-Security & DevSecOps (6 Tools)', en: 'Code Security & DevSecOps (6 Tools)', bp: true, vanta: false, drata: false, sprinto: false, proliance: false, dataguard: false, heydata: false, isDiff: true, isUSP: true },
{ de: '57 SDK-Compliance-Module', en: '57 SDK Compliance Modules', bp: true, vanta: false, drata: false, sprinto: false, proliance: false, dataguard: false, heydata: false, isDiff: true, isUSP: true },
{ de: 'Hardware-Moat (Mac Mini/Studio)', en: 'Hardware Moat (Mac Mini/Studio)', bp: true, vanta: false, drata: false, sprinto: false, proliance: false, dataguard: false, heydata: false, isDiff: true, isUSP: true },
{ de: 'PII-Redaction LLM Gateway', en: 'PII Redaction LLM Gateway', bp: true, vanta: false, drata: false, sprinto: false, proliance: false, dataguard: false, heydata: false, isDiff: true, isUSP: true },
// More USPs
{ de: 'IPFS Dokumenten-Archivierung', en: 'IPFS Document Archiving', bp: true, vanta: false, drata: false, sprinto: false, proliance: false, dataguard: false, heydata: false, isDiff: false, isUSP: true },
{ de: 'SBOM-Generator (CycloneDX/SPDX)', en: 'SBOM Generator (CycloneDX/SPDX)', bp: true, vanta: false, drata: false, sprinto: false, proliance: false, dataguard: false, heydata: false, isDiff: false, isUSP: true },
{ de: 'Multi-Framework Consent SDK', en: 'Multi-Framework Consent SDK', bp: true, vanta: false, drata: false, sprinto: false, proliance: false, dataguard: false, heydata: false, isDiff: false, isUSP: true },
{ de: 'RAG mit 2.274 Rechtstexten', en: 'RAG with 2,274 Legal Texts', bp: true, vanta: false, drata: false, sprinto: false, proliance: false, dataguard: false, heydata: false, isDiff: false, isUSP: true },
// Compliance Features (shared)
{ de: 'DSGVO / GDPR', en: 'GDPR', bp: true, vanta: 'partial', drata: 'partial', sprinto: 'partial', proliance: true, dataguard: true, heydata: true, isDiff: false, isUSP: false },
{ de: 'AI Act', en: 'AI Act', bp: true, vanta: false, drata: false, sprinto: false, proliance: false, dataguard: false, heydata: false, isDiff: false, isUSP: false },
{ de: 'Cyber Resilience Act (CRA)', en: 'Cyber Resilience Act (CRA)', bp: true, vanta: false, drata: false, sprinto: false, proliance: false, dataguard: false, heydata: false, isDiff: false, isUSP: false },
{ de: 'NIS2-Richtlinie', en: 'NIS2 Directive', bp: true, vanta: false, drata: 'partial', sprinto: false, proliance: false, dataguard: 'partial', heydata: false, isDiff: false, isUSP: false },
{ de: 'SOC 2', en: 'SOC 2', bp: 'partial', vanta: true, drata: true, sprinto: true, proliance: false, dataguard: true, heydata: false, isDiff: false, isUSP: false },
{ de: 'ISO 27001', en: 'ISO 27001', bp: true, vanta: true, drata: true, sprinto: true, proliance: false, dataguard: true, heydata: false, isDiff: false, isUSP: false },
{ de: 'HIPAA', en: 'HIPAA', bp: false, vanta: true, drata: true, sprinto: true, proliance: false, dataguard: false, heydata: false, isDiff: false, isUSP: false },
{ de: 'TISAX', en: 'TISAX', bp: true, vanta: false, drata: false, sprinto: false, proliance: false, dataguard: true, heydata: false, isDiff: false, isUSP: false },
{ de: 'HinSchG (Whistleblower)', en: 'HinSchG (Whistleblower)', bp: true, vanta: false, drata: false, sprinto: false, proliance: 'partial', dataguard: false, heydata: false, isDiff: false, isUSP: false },
// Functional Features
{ de: 'VVT (Art. 30 DSGVO)', en: 'Records of Processing (Art. 30)', bp: true, vanta: false, drata: false, sprinto: false, proliance: true, dataguard: true, heydata: true, isDiff: false, isUSP: false },
{ de: 'TOM-Dokumentation', en: 'TOM Documentation', bp: true, vanta: false, drata: false, sprinto: false, proliance: true, dataguard: true, heydata: 'partial', isDiff: false, isUSP: false },
{ de: 'DSFA (Art. 35 DSGVO)', en: 'DPIA (Art. 35 GDPR)', bp: true, vanta: false, drata: false, sprinto: false, proliance: true, dataguard: true, heydata: false, isDiff: false, isUSP: false },
{ de: 'Loeschkonzept / Loeschfristen', en: 'Deletion Concept / Retention', bp: true, vanta: false, drata: false, sprinto: false, proliance: 'partial', dataguard: 'partial', heydata: false, isDiff: false, isUSP: false },
{ de: 'Auftragsverarbeiter-Mgmt', en: 'Vendor/Processor Management', bp: true, vanta: true, drata: true, sprinto: 'partial', proliance: true, dataguard: true, heydata: 'partial', isDiff: false, isUSP: false },
{ de: 'Consent Management', en: 'Consent Management', bp: true, vanta: false, drata: false, sprinto: false, proliance: 'partial', dataguard: false, heydata: 'partial', isDiff: false, isUSP: false },
{ de: 'Betroffenenrechte (DSR)', en: 'Data Subject Requests', bp: true, vanta: false, drata: false, sprinto: false, proliance: true, dataguard: true, heydata: 'partial', isDiff: false, isUSP: false },
{ de: 'Risikobewertung', en: 'Risk Assessment', bp: true, vanta: true, drata: true, sprinto: true, proliance: 'partial', dataguard: true, heydata: false, isDiff: false, isUSP: false },
{ de: 'Audit-Management', en: 'Audit Management', bp: true, vanta: true, drata: true, sprinto: true, proliance: false, dataguard: true, heydata: false, isDiff: false, isUSP: false },
{ de: 'Schulungs-Management', en: 'Training Management', bp: true, vanta: 'partial', drata: 'partial', sprinto: 'partial', proliance: false, dataguard: 'partial', heydata: false, isDiff: false, isUSP: false },
{ de: 'Policy-Generator', en: 'Policy Generator', bp: true, vanta: true, drata: true, sprinto: 'partial', proliance: true, dataguard: true, heydata: 'partial', isDiff: false, isUSP: false },
{ de: 'Incident Response', en: 'Incident Response', bp: true, vanta: true, drata: true, sprinto: true, proliance: false, dataguard: 'partial', heydata: false, isDiff: false, isUSP: false },
// Technical Features
{ de: 'KI-gestuetzte Analyse', en: 'AI-Powered Analysis', bp: true, vanta: true, drata: true, sprinto: 'partial', proliance: false, dataguard: true, heydata: false, isDiff: false, isUSP: false },
{ de: 'Automatische Evidence-Sammlung', en: 'Automatic Evidence Collection', bp: true, vanta: true, drata: true, sprinto: true, proliance: false, dataguard: 'partial', heydata: false, isDiff: false, isUSP: false },
{ de: 'Continuous Monitoring', en: 'Continuous Monitoring', bp: true, vanta: true, drata: true, sprinto: true, proliance: false, dataguard: true, heydata: false, isDiff: false, isUSP: false },
{ de: 'Integrations (Slack, Jira, etc.)', en: 'Integrations (Slack, Jira, etc.)', bp: 'partial', vanta: true, drata: true, sprinto: true, proliance: false, dataguard: 'partial', heydata: false, isDiff: false, isUSP: false },
{ de: 'API / SDK', en: 'API / SDK', bp: true, vanta: true, drata: true, sprinto: 'partial', proliance: false, dataguard: 'partial', heydata: false, isDiff: false, isUSP: false },
{ de: 'Datensouveraenitaet (EU)', en: 'Data Sovereignty (EU)', bp: true, vanta: false, drata: false, sprinto: false, proliance: true, dataguard: true, heydata: true, isDiff: false, isUSP: false },
{ de: 'Mehrmandantenfaehig', en: 'Multi-Tenancy', bp: true, vanta: true, drata: true, sprinto: true, proliance: 'partial', dataguard: true, heydata: false, isDiff: false, isUSP: false },
{ de: 'Data Mapping / Datenfluss', en: 'Data Mapping / Data Flow', bp: true, vanta: 'partial', drata: 'partial', sprinto: false, proliance: false, dataguard: 'partial', heydata: false, isDiff: false, isUSP: false },
{ de: 'Cookie-Banner Generator', en: 'Cookie Banner Generator', bp: true, vanta: false, drata: false, sprinto: false, proliance: 'partial', dataguard: false, heydata: 'partial', isDiff: false, isUSP: false },
{ de: 'Dokument-Generator (61 Vorlagen)', en: 'Document Generator (61 Templates)', bp: true, vanta: 'partial', drata: 'partial', sprinto: false, proliance: 'partial', dataguard: 'partial', heydata: false, isDiff: false, isUSP: false },
{ de: 'Whistleblower-Portal', en: 'Whistleblower Portal', bp: true, vanta: false, drata: false, sprinto: false, proliance: false, dataguard: false, heydata: false, isDiff: false, isUSP: false },
{ de: 'Maschinenbau-Branchenfokus', en: 'Manufacturing Industry Focus', bp: true, vanta: false, drata: false, sprinto: false, proliance: false, dataguard: false, heydata: false, isDiff: false, isUSP: false },
{ de: 'Firmware & Embedded-Security', en: 'Firmware & Embedded Security', bp: true, vanta: false, drata: false, sprinto: false, proliance: false, dataguard: false, heydata: false, isDiff: false, isUSP: false },
{ de: 'Autonomer KI-Support-Agent', en: 'Autonomous AI Support Agent', bp: true, vanta: false, drata: false, sprinto: false, proliance: false, dataguard: false, heydata: false, isDiff: false, isUSP: false },
]
// ─── DACH Landscape Note ───────────────────────────────────────────────────────
const DACH_NOTE = {
de: 'Weitere DACH-Anbieter: Secjur (Hamburg, KI-Compliance, ~€5.5M Seed), Usercentrics (nur CMP, $117M Rev), Caralegal (Privacy/Risk, M&A 2025), 2B Advice (Legacy, 20+ J.), OneTrust (US-Enterprise, $500M+ ARR). Keiner kombiniert DSGVO + Code-Security + Self-Hosted KI.',
en: 'Other DACH players: Secjur (Hamburg, AI compliance, ~€5.5M seed), Usercentrics (CMP only, $117M rev), Caralegal (privacy/risk, M&A 2025), 2B Advice (legacy, 20+ yrs), OneTrust (US enterprise, $500M+ ARR). None combines GDPR + code security + self-hosted AI.',
}
// ─── Helpers ───────────────────────────────────────────────────────────────────
function StatusIcon({ value }: { value: FeatureStatus }) {
if (value === true) return <Check className="w-3.5 h-3.5 text-green-400 mx-auto" />
if (value === 'partial') return <Minus className="w-3.5 h-3.5 text-yellow-400 mx-auto" />
return <X className="w-3.5 h-3.5 text-white/15 mx-auto" />
}
function AiBadge({ level, lang }: { level: 'full' | 'partial' | 'none'; lang: Language }) {
const colors = { full: 'bg-green-500/15 text-green-400', partial: 'bg-yellow-500/15 text-yellow-400', none: 'bg-white/5 text-white/30' }
const labels = { full: { de: 'KI', en: 'AI' }, partial: { de: 'Basis', en: 'Basic' }, none: { de: 'Keine', en: 'None' } }
return (
<span className={`text-[10px] px-1.5 py-0.5 rounded-full font-medium ${colors[level]}`}>
<Cpu className="w-2.5 h-2.5 inline mr-0.5 -mt-px" />
{labels[level][lang]}
</span>
)
}
function ratio(a: number, b: number): string {
if (b === 0) return '—'
const r = a / b
if (r >= 1_000_000) return `${(r / 1_000_000).toFixed(1)}M`
if (r >= 1_000) return `${(r / 1_000).toFixed(0)}k`
return r.toFixed(0)
}
// ─── Section Accordion ─────────────────────────────────────────────────────────
function SectionHeader({
label,
count,
open,
onToggle,
accent,
}: {
label: string
count: number
open: boolean
onToggle: () => void
accent?: string
}) {
return (
<button
onClick={onToggle}
className="w-full flex items-center gap-2 py-2 px-3 bg-white/[0.03] hover:bg-white/[0.06] border border-white/5 rounded-lg transition-colors text-left"
>
{open ? <ChevronDown className="w-4 h-4 text-white/40 shrink-0" /> : <ChevronRight className="w-4 h-4 text-white/40 shrink-0" />}
<span className={`text-sm font-semibold ${accent || 'text-white/80'}`}>{label}</span>
<span className="text-xs text-white/30 ml-1">({count})</span>
</button>
)
}
// ─── Component ─────────────────────────────────────────────────────────────────
type ViewTab = 'overview' | 'features'
export default function CompetitionSlide({ lang, features, competitors }: CompetitionSlideProps) {
const i = t(lang)
const [activeTab, setActiveTab] = useState<ViewTab>('overview')
const [openSections, setOpenSections] = useState<Set<string>>(new Set(['top5']))
const toggleSection = (key: string) => {
setOpenSections(prev => {
const next = new Set(prev)
if (next.has(key)) next.delete(key)
else next.add(key)
return next
})
}
const top5 = ALL_FEATURES.filter(f => f.isDiff)
const usps = ALL_FEATURES.filter(f => f.isUSP)
const allFeatures = ALL_FEATURES
const competitorCols = ['bp', 'vanta', 'drata', 'sprinto', 'proliance', 'dataguard', 'heydata'] as const
const competitorLabels = ['ComplAI', 'Vanta', 'Drata', 'Sprinto', 'Proliance', 'DataGuard', 'heyData']
const featureCount = ALL_FEATURES.length
const uspCount = usps.length
const subtitle = lang === 'de'
? `${featureCount} Features, ${uspCount} USPs — kein Anbieter kombiniert DSGVO + Code-Security + Self-Hosted KI`
: `${featureCount} features, ${uspCount} USPs — no provider combines GDPR + code security + self-hosted AI`
return (
<div className="max-h-[calc(100vh-120px)] overflow-y-auto pr-1 pb-4 scrollbar-thin">
{/* Header */}
<FadeInView className="text-center mb-4">
<h2 className="text-3xl md:text-4xl font-bold mb-2">
<GradientText>{i.competition.title}</GradientText>
</h2>
<p className="text-sm text-white/50 max-w-3xl mx-auto">{subtitle}</p>
</FadeInView>
{/* Tab Bar */}
<FadeInView delay={0.15} className="flex justify-center gap-2 mb-4">
{([
{ key: 'overview' as ViewTab, de: 'Ueberblick & Vergleich', en: 'Overview & Comparison' },
{ key: 'features' as ViewTab, de: 'Feature-Matrix (Detail)', en: 'Feature Matrix (Detail)' },
]).map(tab => (
<button
key={tab.key}
onClick={() => setActiveTab(tab.key)}
className={`px-4 py-1.5 rounded-full text-xs font-medium transition-all ${
activeTab === tab.key
? 'bg-indigo-500/20 text-indigo-300 border border-indigo-500/30'
: 'bg-white/[0.04] text-white/40 border border-white/5 hover:bg-white/[0.08]'
}`}
>
{lang === 'de' ? tab.de : tab.en}
</button>
))}
</FadeInView>
{/* ─── Tab: Overview ─── */}
{activeTab === 'overview' && (
<FadeInView delay={0.2}>
{/* Competitor Profiles */}
<div className="mb-4">
{/* International */}
<div className="flex items-center gap-2 mb-2">
<Globe className="w-3.5 h-3.5 text-blue-400" />
<span className="text-xs font-semibold text-blue-400">{lang === 'de' ? 'International' : 'International'}</span>
</div>
<div className="grid grid-cols-3 gap-2 mb-3">
{EXTENDED_COMPETITORS.filter(c => c.isInternational).map(c => (
<CompetitorCard key={c.name} competitor={c} lang={lang} />
))}
</div>
{/* DACH */}
<div className="flex items-center gap-2 mb-2">
<Building2 className="w-3.5 h-3.5 text-emerald-400" />
<span className="text-xs font-semibold text-emerald-400">DACH</span>
</div>
<div className="grid grid-cols-3 gap-2 mb-3">
{EXTENDED_COMPETITORS.filter(c => !c.isInternational).map(c => (
<CompetitorCard key={c.name} competitor={c} lang={lang} />
))}
</div>
</div>
{/* Efficiency Ratios */}
<GlassCard className="!p-3 mb-4" hover={false}>
<h4 className="text-xs font-semibold text-white/60 mb-2 flex items-center gap-1.5">
<TrendingUp className="w-3.5 h-3.5" />
{lang === 'de' ? 'Effizienz-Kennzahlen' : 'Efficiency Ratios'}
</h4>
<div className="overflow-x-auto">
<table className="w-full text-[11px]">
<thead>
<tr className="border-b border-white/10">
<th className="text-left py-1.5 px-2 text-white/40 font-medium">{lang === 'de' ? 'Kennzahl' : 'Metric'}</th>
{EXTENDED_COMPETITORS.map(c => (
<th key={c.name} className="py-1.5 px-2 text-white/50 font-medium text-center">{c.flag} {c.name}</th>
))}
</tr>
</thead>
<tbody>
<tr className="border-b border-white/5">
<td className="py-1.5 px-2 text-white/50">{lang === 'de' ? 'Umsatz / Mitarbeiter' : 'Revenue / Employee'}</td>
{EXTENDED_COMPETITORS.map(c => (
<td key={c.name} className="py-1.5 px-2 text-center text-white/70">
${ratio(c.revenueNum, c.employees)}
</td>
))}
</tr>
<tr className="border-b border-white/5">
<td className="py-1.5 px-2 text-white/50">{lang === 'de' ? 'Kunden / Mitarbeiter' : 'Customers / Employee'}</td>
{EXTENDED_COMPETITORS.map(c => (
<td key={c.name} className="py-1.5 px-2 text-center text-white/70">
{(c.customers / c.employees).toFixed(0)}
</td>
))}
</tr>
<tr>
<td className="py-1.5 px-2 text-white/50">{lang === 'de' ? 'Mitarbeiter' : 'Employees'}</td>
{EXTENDED_COMPETITORS.map(c => (
<td key={c.name} className="py-1.5 px-2 text-center text-white/70">
{c.employees.toLocaleString()}
</td>
))}
</tr>
</tbody>
</table>
</div>
</GlassCard>
{/* DACH Landscape Note */}
<div className="text-[11px] text-white/30 text-center italic">
{DACH_NOTE[lang]}
</div>
</FadeInView>
)}
{/* ─── Tab: Feature Matrix ─── */}
{activeTab === 'features' && (
<FadeInView delay={0.2}>
<div className="space-y-2">
{/* Top 5 Differences */}
<div>
<SectionHeader
label={lang === 'de' ? 'Top 5 Unterschiede' : 'Top 5 Differences'}
count={top5.length}
open={openSections.has('top5')}
onToggle={() => toggleSection('top5')}
accent="text-yellow-400"
/>
{openSections.has('top5') && (
<FeatureTable features={top5} lang={lang} cols={competitorCols} labels={competitorLabels} highlight />
)}
</div>
{/* All Features */}
<div>
<SectionHeader
label={lang === 'de' ? 'Alle Features' : 'All Features'}
count={allFeatures.length}
open={openSections.has('all')}
onToggle={() => toggleSection('all')}
/>
{openSections.has('all') && (
<FeatureTable features={allFeatures} lang={lang} cols={competitorCols} labels={competitorLabels} />
)}
</div>
{/* USPs */}
<div>
<SectionHeader
label={lang === 'de' ? 'USP — nur ComplAI' : 'USP — ComplAI only'}
count={usps.length}
open={openSections.has('usp')}
onToggle={() => toggleSection('usp')}
accent="text-indigo-400"
/>
{openSections.has('usp') && (
<FeatureTable features={usps} lang={lang} cols={competitorCols} labels={competitorLabels} highlight />
)}
</div>
</div>
{/* Score Summary */}
<div className="mt-4 flex items-center justify-center gap-6">
{[
{ name: 'ComplAI', score: ALL_FEATURES.filter(f => f.bp === true).length, color: 'text-indigo-400' },
{ name: 'Vanta', score: ALL_FEATURES.filter(f => f.vanta === true).length, color: 'text-white/50' },
{ name: 'Drata', score: ALL_FEATURES.filter(f => f.drata === true).length, color: 'text-white/50' },
{ name: 'Sprinto', score: ALL_FEATURES.filter(f => f.sprinto === true).length, color: 'text-white/50' },
{ name: 'Proliance', score: ALL_FEATURES.filter(f => f.proliance === true).length, color: 'text-white/50' },
{ name: 'DataGuard', score: ALL_FEATURES.filter(f => f.dataguard === true).length, color: 'text-white/50' },
{ name: 'heyData', score: ALL_FEATURES.filter(f => f.heydata === true).length, color: 'text-white/50' },
].map(item => (
<div key={item.name} className="text-center">
<div className={`text-lg font-bold ${item.color}`}>{item.score}/{ALL_FEATURES.length}</div>
<div className="text-[10px] text-white/40">{item.name}</div>
</div>
))}
</div>
</FadeInView>
)}
</div>
)
}
// ─── Sub-Components ────────────────────────────────────────────────────────────
function CompetitorCard({ competitor: c, lang }: { competitor: ExtendedCompetitor; lang: Language }) {
return (
<div className="bg-white/[0.04] border border-white/5 rounded-xl p-2.5 text-[11px]">
{/* Header */}
<div className="flex items-center justify-between mb-1">
<div className="flex items-center gap-1.5">
<span className="text-sm">{c.flag}</span>
<span className="font-semibold text-white/80 text-xs">{c.name}</span>
</div>
<AiBadge level={c.aiUsage} lang={lang} />
</div>
{/* HQ + Offices */}
<div className="text-[10px] text-white/40 mb-1.5 truncate" title={`HQ: ${c.hq}, ${c.hqCountry}` + (c.offices.length > 1 ? ` | Offices: ${c.offices.join(', ')}` : '')}>
<span className="text-white/55">{c.hq}, {c.hqCountry}</span>
{c.offices.length > 1 && (
<span className="ml-1">+ {c.offices.join(', ')}</span>
)}
</div>
{/* KPIs */}
<div className="grid grid-cols-2 gap-x-3 gap-y-0.5 text-white/50">
<div className="flex items-center gap-1">
<span className="text-white/30">{lang === 'de' ? 'Gr.' : 'Est.'}</span>
<span className="text-white/70">{c.founded}</span>
</div>
<div className="flex items-center gap-1">
<Users className="w-2.5 h-2.5 text-white/30" />
<span className="text-white/70">{c.employees.toLocaleString()}</span>
</div>
<div className="flex items-center gap-1">
<DollarSign className="w-2.5 h-2.5 text-white/30" />
<span className="text-white/70">{c.revenue}</span>
</div>
<div className="flex items-center gap-1">
<Globe className="w-2.5 h-2.5 text-white/30" />
<span className="text-white/70">{c.customers.toLocaleString()} {lang === 'de' ? 'Kd.' : 'cust.'} ({c.customerCountries})</span>
</div>
</div>
{/* Funding + Investors */}
<div className="mt-1.5 pt-1.5 border-t border-white/5">
<div className="text-white/40">
<span className="text-white/60 font-medium">{c.fundingTotal}</span>
<span className="ml-1 text-[10px]">{c.fundingRound}</span>
</div>
{c.investors.length > 0 && (
<div className="text-[10px] text-white/30 mt-0.5 truncate" title={c.investors.join(', ')}>
{c.investors.slice(0, 3).join(', ')}{c.investors.length > 3 ? ' +' + (c.investors.length - 3) : ''}
</div>
)}
</div>
{/* Market */}
<div className="mt-1 text-[10px] text-white/35 truncate" title={c.market[lang]}>
{c.market[lang]}
</div>
</div>
)
}
function FeatureTable({
features,
lang,
cols,
labels,
highlight,
}: {
features: ComparisonFeature[]
lang: Language
cols: readonly string[]
labels: string[]
highlight?: boolean
}) {
return (
<div className="overflow-x-auto mt-1 mb-1">
<table className="w-full text-[11px]">
<thead>
<tr className="border-b border-white/10">
<th className="text-left py-1.5 px-2 text-white/40 font-medium min-w-[180px]">Feature</th>
{labels.map((l, idx) => (
<th key={l} className={`py-1.5 px-1.5 font-medium text-center whitespace-nowrap ${idx === 0 ? 'text-indigo-400' : 'text-white/50'}`}>
{idx === 0 ? <BrandName className="text-[11px]" /> : l}
</th>
))}
</tr>
</thead>
<tbody>
{features.map((f, i) => (
<tr key={i} className={`border-b border-white/5 ${highlight && f.isDiff ? 'bg-indigo-500/5' : ''}`}>
<td className="py-1.5 px-2 flex items-center gap-1.5">
{f.isDiff && <Star className="w-3 h-3 text-yellow-400 shrink-0" />}
<span className={f.isDiff ? 'text-white font-medium' : 'text-white/60'}>
{lang === 'de' ? f.de : f.en}
</span>
</td>
{cols.map(col => (
<td key={col} className="py-1.5 px-1.5 text-center">
<StatusIcon value={f[col as keyof ComparisonFeature] as FeatureStatus} />
</td>
))}
</tr>
))}
</tbody>
</table>
</div>
)
}