Files
breakpilot-core/pitch-deck/components/slides/CompetitionSlide.tsx
Benjamin Admin 3a2567b44d
All checks were successful
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / test-go-consent (push) Successful in 27s
CI / test-python-voice (push) Successful in 25s
CI / test-bqas (push) Successful in 25s
CI / Deploy (push) Successful in 4s
feat(pitch-deck): add AI Presenter mode with LiteLLM migration and FAQ system
- Migrate chat API from Ollama to LiteLLM (OpenAI-compatible SSE)
- Add 15-min presenter storyline with bilingual scripts for all 20 slides
- Add FAQ system (30 entries) with keyword matching for instant answers
- Add IntroPresenterSlide with avatar placeholder and start button
- Add PresenterOverlay (progress bar, subtitle text, play/pause/stop)
- Add AvatarPlaceholder with pulse animation during speaking
- Add usePresenterMode hook (state machine: idle→presenting→paused→answering→resuming)
- Add 'P' keyboard shortcut to toggle presenter mode
- Support [GOTO:slide-id] markers in chat responses
- Dynamic slide count (was hardcoded 13, now from SLIDE_ORDER)
- TTS stub prepared for future Piper integration

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

1043 lines
58 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, Shield, Tag,
} 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 },
// Pentesting & Code-Security (kein Compliance-Wettbewerber hat dies)
{ de: 'SAST (Static Application Security Testing)', en: 'SAST (Static Application Security Testing)', bp: true, vanta: false, drata: false, sprinto: false, proliance: false, dataguard: false, heydata: false, isDiff: false, isUSP: true },
{ de: 'DAST (Dynamic Application Security Testing)', en: 'DAST (Dynamic Application Security Testing)', bp: true, vanta: false, drata: false, sprinto: false, proliance: false, dataguard: false, heydata: false, isDiff: false, isUSP: true },
{ de: 'LLM-Auto-Fix (automatische Code-Korrekturen)', en: 'LLM Auto-Fix (Automatic Code Corrections)', bp: true, vanta: false, drata: false, sprinto: false, proliance: false, dataguard: false, heydata: false, isDiff: false, isUSP: true },
{ de: 'Container-Security Scanning (Trivy)', en: 'Container Security Scanning (Trivy)', bp: true, vanta: false, drata: false, sprinto: false, proliance: false, dataguard: false, heydata: false, isDiff: false, isUSP: true },
{ de: 'Secret Detection (Gitleaks)', en: 'Secret Detection (Gitleaks)', 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.',
}
// ─── Pricing Comparison Data ──────────────────────────────────────────────────
interface PricingTier {
name: { de: string; en: string }
price: string
annual: string
notes: { de: string; en: string }
}
interface CompetitorPricing {
name: string
flag: string
model: string
publicPricing: boolean
tiers: PricingTier[]
setupFee: string
isBP?: boolean
}
const PRICING_COMPARISON: CompetitorPricing[] = [
{
name: 'ComplAI',
flag: '🇩🇪',
model: 'Self-Hosted',
publicPricing: true,
tiers: [
{ name: { de: 'Starter', en: 'Starter' }, price: '€990/mo', annual: '€11.880/yr', notes: { de: 'Mac Mini, 30B LLM, 57 Module', en: 'Mac Mini, 30B LLM, 57 modules' } },
{ name: { de: 'Professional', en: 'Professional' }, price: '€1.490/mo', annual: '€17.880/yr', notes: { de: 'Mac Studio, 70B LLM, Priority', en: 'Mac Studio, 70B LLM, priority' } },
{ name: { de: 'Enterprise', en: 'Enterprise' }, price: '€2.990/mo', annual: '€35.880/yr', notes: { de: '2x Mac Studio, 1000B Cloud-LLM', en: '2x Mac Studio, 1000B cloud LLM' } },
],
setupFee: '€0',
isBP: true,
},
{
name: 'Vanta',
flag: '🇺🇸',
model: 'SaaS',
publicPricing: false,
tiers: [
{ name: { de: 'Startup', en: 'Startup' }, price: '~$500/mo', annual: '~$6K/yr', notes: { de: '1 Framework, <50 MA', en: '1 framework, <50 employees' } },
{ name: { de: 'Business', en: 'Business' }, price: '~$2K/mo', annual: '~$25K/yr', notes: { de: 'Multi-Framework, VRM', en: 'Multi-framework, VRM' } },
{ name: { de: 'Enterprise', en: 'Enterprise' }, price: '~$5-7K/mo', annual: '~$60-80K/yr', notes: { de: 'Custom, SSO, RBAC', en: 'Custom, SSO, RBAC' } },
],
setupFee: '~$5-15K',
},
{
name: 'Drata',
flag: '🇺🇸',
model: 'SaaS',
publicPricing: false,
tiers: [
{ name: { de: 'Foundation', en: 'Foundation' }, price: '~$500/mo', annual: '~$5-8K/yr', notes: { de: '1 Framework, Basis', en: '1 framework, basic' } },
{ name: { de: 'Business', en: 'Business' }, price: '~$1.5K/mo', annual: '~$18-20K/yr', notes: { de: 'Multi-Framework, API', en: 'Multi-framework, API' } },
{ name: { de: 'Enterprise', en: 'Enterprise' }, price: '~$4-8K/mo', annual: '~$50-100K/yr', notes: { de: 'SafeBase, Custom', en: 'SafeBase, custom' } },
],
setupFee: '~$5-10K',
},
{
name: 'Sprinto',
flag: '🇮🇳',
model: 'SaaS',
publicPricing: false,
tiers: [
{ name: { de: 'Growth', en: 'Growth' }, price: '~$350/mo', annual: '~$4K/yr', notes: { de: '1 Framework, KMU', en: '1 framework, SMB' } },
{ name: { de: 'Business', en: 'Business' }, price: '~$1K/mo', annual: '~$12K/yr', notes: { de: 'Multi-Framework', en: 'Multi-framework' } },
{ name: { de: 'Enterprise', en: 'Enterprise' }, price: '~$2K+/mo', annual: '~$25K+/yr', notes: { de: 'Custom Integrations', en: 'Custom integrations' } },
],
setupFee: '~$2-5K',
},
{
name: 'Proliance',
flag: '🇩🇪',
model: 'SaaS',
publicPricing: true,
tiers: [
{ name: { de: 'Basis', en: 'Basic' }, price: '€99/mo', annual: '€1.188/yr', notes: { de: 'DSGVO-Grundlagen', en: 'GDPR basics' } },
{ name: { de: 'Professional', en: 'Professional' }, price: '€249/mo', annual: '€2.988/yr', notes: { de: '+ Audit, VVT', en: '+ Audit, records' } },
{ name: { de: 'Enterprise', en: 'Enterprise' }, price: '€499/mo', annual: '€5.988/yr', notes: { de: 'Multi-Standort, DSB', en: 'Multi-location, DPO' } },
],
setupFee: '€0',
},
{
name: 'DataGuard',
flag: '🇩🇪',
model: 'SaaS + Beratung',
publicPricing: false,
tiers: [
{ name: { de: 'Starter', en: 'Starter' }, price: '~€250/mo', annual: '~€3K/yr', notes: { de: 'Nur Software', en: 'Software only' } },
{ name: { de: 'Managed', en: 'Managed' }, price: '~€1K/mo', annual: '~€12K/yr', notes: { de: '+ Ext. DSB', en: '+ Ext. DPO' } },
{ name: { de: 'Enterprise', en: 'Enterprise' }, price: '~€2K+/mo', annual: '~€24K+/yr', notes: { de: 'ISO 27001 + TISAX', en: 'ISO 27001 + TISAX' } },
],
setupFee: '~€2-5K',
},
{
name: 'heyData',
flag: '🇩🇪',
model: 'SaaS',
publicPricing: true,
tiers: [
{ name: { de: 'Essential', en: 'Essential' }, price: '€83/mo', annual: '€996/yr', notes: { de: '1-19 MA, DSGVO', en: '1-19 empl., GDPR' } },
{ name: { de: 'Pro', en: 'Pro' }, price: '€199/mo', annual: '€2.388/yr', notes: { de: '20-99 MA, DSB', en: '20-99 empl., DPO' } },
{ name: { de: 'Premium', en: 'Premium' }, price: '€333/mo', annual: '€3.996/yr', notes: { de: '100+ MA, Audit', en: '100+ empl., audit' } },
],
setupFee: '€0',
},
]
// ─── AppSec / Pentesting Competitor Data ─────────────────────────────────────
interface AppSecCompetitor {
name: string
flag: string
hq: string
founded: number
employees: number
revenue: string
revenueNum: number
customers: string
funding: string
pricing: string
focus: { de: string; en: string }
}
const APPSEC_COMPETITORS: AppSecCompetitor[] = [
{ name: 'Snyk', flag: '🇺🇸', hq: 'Boston', founded: 2015, employees: 1200, revenue: '~$300M ARR', revenueNum: 300_000_000, customers: '3.000+', funding: '$850M (Series G, $7.4B)', pricing: '$25K100K+/yr', focus: { de: 'SCA + SAST, Developer-First', en: 'SCA + SAST, developer-first' } },
{ name: 'Veracode', flag: '🇺🇸', hq: 'Burlington, MA', founded: 2006, employees: 1300, revenue: '~$300M', revenueNum: 300_000_000, customers: '3.500+', funding: 'PE (Thoma Bravo, $2.5B)', pricing: '$50K500K+/yr', focus: { de: 'SAST + DAST + SCA, Enterprise', en: 'SAST + DAST + SCA, enterprise' } },
{ name: 'Checkmarx', flag: '🇮🇱', hq: 'Tel Aviv', founded: 2006, employees: 1000, revenue: '~$250M', revenueNum: 250_000_000, customers: '1.800+', funding: 'PE (Hellman & Friedman)', pricing: '$40K300K+/yr', focus: { de: 'SAST + DAST + SCA + API', en: 'SAST + DAST + SCA + API' } },
{ name: 'SonarSource', flag: '🇨🇭', hq: 'Genf', founded: 2008, employees: 500, revenue: '~$250M', revenueNum: 250_000_000, customers: '400K+ Devs', funding: '$412M (Series D)', pricing: '$15K150K+/yr', focus: { de: 'Code-Qualitaet + SAST', en: 'Code quality + SAST' } },
{ name: 'Semgrep', flag: '🇺🇸', hq: 'San Francisco', founded: 2020, employees: 150, revenue: '~$30M ARR', revenueNum: 30_000_000, customers: '1.500+', funding: '$100M (Series C)', pricing: '$10K100K+/yr', focus: { de: 'Open-Source SAST, Supply Chain', en: 'Open-source SAST, supply chain' } },
{ name: 'Pentera', flag: '🇮🇱', hq: 'Tel Aviv', founded: 2015, employees: 400, revenue: '~$100M', revenueNum: 100_000_000, customers: '900+', funding: '$189M (Series C)', pricing: '$50K250K+/yr', focus: { de: 'Automatisiertes Pentesting/BAS', en: 'Automated pentesting/BAS' } },
{ name: 'Invicti', flag: '🇺🇸', hq: 'Austin, TX', founded: 2018, employees: 500, revenue: '~$100M', revenueNum: 100_000_000, customers: '3.000+', funding: 'PE (Turn/River)', pricing: '$15K100K+/yr', focus: { de: 'DAST (Acunetix + Netsparker)', en: 'DAST (Acunetix + Netsparker)' } },
{ name: 'Intruder', flag: '🇬🇧', hq: 'London', founded: 2015, employees: 100, revenue: '~$10M', revenueNum: 10_000_000, customers: '2.500+', funding: '$15M (Series A)', pricing: '$1.5K20K+/yr', focus: { de: 'Vulnerability Scanner, SMB', en: 'Vulnerability scanner, SMB' } },
]
interface AppSecFeature {
de: string
en: string
bp: FeatureStatus
snyk: FeatureStatus
veracode: FeatureStatus
checkmarx: FeatureStatus
sonar: FeatureStatus
semgrep: FeatureStatus
pentera: FeatureStatus
invicti: FeatureStatus
intruder: FeatureStatus
isUSP: boolean
}
const APPSEC_FEATURES: AppSecFeature[] = [
// ComplAI USPs — kein AppSec-Anbieter hat dies
{ de: 'DSGVO / GDPR Compliance', en: 'GDPR Compliance', bp: true, snyk: false, veracode: false, checkmarx: false, sonar: false, semgrep: false, pentera: false, invicti: false, intruder: false, isUSP: true },
{ de: 'AI Act Compliance', en: 'AI Act Compliance', bp: true, snyk: false, veracode: false, checkmarx: false, sonar: false, semgrep: false, pentera: false, invicti: false, intruder: false, isUSP: true },
{ de: 'CRA & NIS2 Compliance', en: 'CRA & NIS2 Compliance', bp: true, snyk: false, veracode: false, checkmarx: false, sonar: false, semgrep: false, pentera: false, invicti: false, intruder: false, isUSP: true },
{ de: '57 Compliance-Module (SDK)', en: '57 Compliance Modules (SDK)', bp: true, snyk: false, veracode: false, checkmarx: false, sonar: false, semgrep: false, pentera: false, invicti: false, intruder: false, isUSP: true },
{ de: 'Self-Hosted KI (On-Premise)', en: 'Self-Hosted AI (On-Premise)', bp: true, snyk: false, veracode: false, checkmarx: false, sonar: false, semgrep: false, pentera: false, invicti: false, intruder: false, isUSP: true },
{ de: 'PII-Redaction LLM Gateway', en: 'PII Redaction LLM Gateway', bp: true, snyk: false, veracode: false, checkmarx: false, sonar: false, semgrep: false, pentera: false, invicti: false, intruder: false, isUSP: true },
{ de: 'Firmware & Embedded-Security', en: 'Firmware & Embedded Security', bp: true, snyk: false, veracode: 'partial', checkmarx: false, sonar: false, semgrep: false, pentera: false, invicti: false, intruder: false, isUSP: true },
// Shared AppSec Features
{ de: 'SAST (Static Analysis)', en: 'SAST (Static Analysis)', bp: true, snyk: true, veracode: true, checkmarx: true, sonar: true, semgrep: true, pentera: false, invicti: false, intruder: false, isUSP: false },
{ de: 'DAST (Dynamic Analysis)', en: 'DAST (Dynamic Analysis)', bp: true, snyk: false, veracode: true, checkmarx: true, sonar: false, semgrep: false, pentera: true, invicti: true, intruder: true, isUSP: false },
{ de: 'SCA (Software Composition)', en: 'SCA (Software Composition)', bp: true, snyk: true, veracode: true, checkmarx: true, sonar: 'partial', semgrep: 'partial', pentera: false, invicti: false, intruder: false, isUSP: false },
{ de: 'LLM-basierte Auto-Fixes', en: 'LLM-Based Auto-Fixes', bp: true, snyk: 'partial', veracode: 'partial', checkmarx: 'partial', sonar: 'partial', semgrep: false, pentera: false, invicti: false, intruder: false, isUSP: false },
{ de: 'SBOM-Generierung', en: 'SBOM Generation', bp: true, snyk: true, veracode: 'partial', checkmarx: 'partial', sonar: false, semgrep: false, pentera: false, invicti: false, intruder: false, isUSP: false },
{ de: 'Container-Security', en: 'Container Security', bp: true, snyk: true, veracode: true, checkmarx: true, sonar: false, semgrep: 'partial', pentera: false, invicti: false, intruder: false, isUSP: false },
{ de: 'Secret Detection', en: 'Secret Detection', bp: true, snyk: false, veracode: false, checkmarx: false, sonar: 'partial', semgrep: true, pentera: false, invicti: false, intruder: false, isUSP: false },
{ de: 'IaC Scanning', en: 'IaC Scanning', bp: true, snyk: true, veracode: false, checkmarx: false, sonar: false, semgrep: true, pentera: false, invicti: false, intruder: false, isUSP: false },
{ de: 'CI/CD-Integration', en: 'CI/CD Integration', bp: true, snyk: true, veracode: true, checkmarx: true, sonar: true, semgrep: true, pentera: 'partial', invicti: 'partial', intruder: 'partial', isUSP: false },
{ de: 'API-Security Testing', en: 'API Security Testing', bp: true, snyk: false, veracode: 'partial', checkmarx: true, sonar: false, semgrep: false, pentera: 'partial', invicti: true, intruder: 'partial', isUSP: false },
{ de: 'Automatisiertes Pentesting', en: 'Automated Pentesting', bp: true, snyk: false, veracode: false, checkmarx: false, sonar: false, semgrep: false, pentera: true, invicti: false, intruder: true, isUSP: false },
{ de: 'Self-Hosted / On-Premise', en: 'Self-Hosted / On-Premise', bp: true, snyk: false, veracode: false, checkmarx: 'partial', sonar: true, semgrep: 'partial', pentera: 'partial', invicti: 'partial', intruder: false, isUSP: false },
]
// ─── 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' | 'pricing' | 'appsec'
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 flex-wrap">
{([
{ key: 'overview' as ViewTab, de: 'Ueberblick & Vergleich', en: 'Overview & Comparison' },
{ key: 'features' as ViewTab, de: 'Feature-Matrix (Detail)', en: 'Feature Matrix (Detail)' },
{ key: 'pricing' as ViewTab, de: 'Pricing-Vergleich', en: 'Pricing Comparison' },
{ key: 'appsec' as ViewTab, de: 'Pentesting & AppSec', en: 'Pentesting & AppSec' },
]).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>
)}
{/* ─── Tab: Pricing ─── */}
{activeTab === 'pricing' && (
<FadeInView delay={0.2}>
<div className="overflow-x-auto">
<table className="w-full text-[11px] border-collapse">
<thead>
<tr className="border-b border-white/10">
<th className="text-left py-2 px-2 text-white/40 font-medium min-w-[90px]">{lang === 'de' ? 'Anbieter' : 'Provider'}</th>
<th className="py-2 px-1.5 text-white/40 font-medium text-center">{lang === 'de' ? 'Modell' : 'Model'}</th>
<th className="py-2 px-1.5 text-white/40 font-medium text-center">{lang === 'de' ? 'Einstieg' : 'Entry'}</th>
<th className="py-2 px-1.5 text-white/40 font-medium text-center">Mid</th>
<th className="py-2 px-1.5 text-white/40 font-medium text-center">Enterprise</th>
<th className="py-2 px-1.5 text-white/40 font-medium text-center">Setup</th>
<th className="py-2 px-1.5 text-white/40 font-medium text-center">{lang === 'de' ? 'Oeffentlich' : 'Public'}</th>
</tr>
</thead>
<tbody>
{PRICING_COMPARISON.map((cp) => (
<tr key={cp.name} className={`border-b border-white/5 ${cp.isBP ? 'bg-indigo-500/5' : ''}`}>
<td className="py-2 px-2">
<div className="flex items-center gap-1.5">
<span>{cp.flag}</span>
<span className={`font-semibold ${cp.isBP ? 'text-indigo-400' : 'text-white/70'}`}>
{cp.isBP ? <BrandName className="text-[11px]" /> : cp.name}
</span>
</div>
</td>
<td className="py-2 px-1.5 text-center">
<span className={`text-[10px] px-1.5 py-0.5 rounded-full ${cp.model === 'Self-Hosted' ? 'bg-green-500/15 text-green-400' : 'bg-white/5 text-white/40'}`}>
{cp.model}
</span>
</td>
{cp.tiers.map((tier, idx) => (
<td key={idx} className="py-2 px-1.5 text-center">
<div className={`font-semibold ${cp.isBP ? 'text-indigo-300' : 'text-white/70'}`}>{tier.price}</div>
<div className="text-[10px] text-white/30">{tier.annual}</div>
<div className="text-[10px] text-white/25 mt-0.5">{lang === 'de' ? tier.notes.de : tier.notes.en}</div>
</td>
))}
<td className="py-2 px-1.5 text-center text-white/40">{cp.setupFee}</td>
<td className="py-2 px-1.5 text-center">
{cp.publicPricing
? <Check className="w-3.5 h-3.5 text-green-400 mx-auto" />
: <X className="w-3.5 h-3.5 text-white/15 mx-auto" />
}
</td>
</tr>
))}
</tbody>
</table>
</div>
{/* Key Insights */}
<GlassCard className="!p-3 mt-4" hover={false}>
<h4 className="text-xs font-semibold text-white/60 mb-2 flex items-center gap-1.5">
<Tag className="w-3.5 h-3.5" />
{lang === 'de' ? 'Pricing-Einordnung' : 'Pricing Context'}
</h4>
<div className="grid grid-cols-2 gap-3 text-[11px]">
<div className="bg-white/[0.03] rounded-lg p-2">
<div className="text-white/50 mb-1">{lang === 'de' ? 'Compliance-Only (DACH)' : 'Compliance Only (DACH)'}</div>
<div className="text-white/80 font-medium">83 499/mo</div>
<div className="text-white/30 text-[10px]">{lang === 'de' ? 'Proliance, heyData — nur DSGVO, kein Code-Security' : 'Proliance, heyData — GDPR only, no code security'}</div>
</div>
<div className="bg-white/[0.03] rounded-lg p-2">
<div className="text-white/50 mb-1">{lang === 'de' ? 'US-Enterprise (Global)' : 'US Enterprise (Global)'}</div>
<div className="text-white/80 font-medium">$500 $7K+/mo</div>
<div className="text-white/30 text-[10px]">{lang === 'de' ? 'Vanta, Drata — SOC 2 Fokus, Setup-Gebuehr, kein Self-Hosted' : 'Vanta, Drata — SOC 2 focus, setup fee, no self-hosted'}</div>
</div>
<div className="bg-indigo-500/5 border border-indigo-500/10 rounded-lg p-2">
<div className="text-indigo-400 mb-1 font-medium">ComplAI</div>
<div className="text-white/80 font-medium">990 2.990/mo</div>
<div className="text-white/30 text-[10px]">{lang === 'de' ? 'Compliance + Code-Security + Self-Hosted KI, kein Setup' : 'Compliance + code security + self-hosted AI, no setup fee'}</div>
</div>
<div className="bg-white/[0.03] rounded-lg p-2">
<div className="text-white/50 mb-1">{lang === 'de' ? 'AppSec-Tools (separat)' : 'AppSec Tools (separate)'}</div>
<div className="text-white/80 font-medium">$10K $500K+/yr</div>
<div className="text-white/30 text-[10px]">{lang === 'de' ? 'Snyk, Veracode — keine Compliance, Cloud-only' : 'Snyk, Veracode — no compliance, cloud only'}</div>
</div>
</div>
</GlassCard>
<p className="text-[10px] text-white/25 text-center mt-3 italic">
{lang === 'de'
? '~ = geschaetzte Preise (nicht oeffentlich). Alle Preise ohne MwSt. Stand: Q1 2026.'
: '~ = estimated pricing (not public). All prices excl. VAT. As of Q1 2026.'}
</p>
</FadeInView>
)}
{/* ─── Tab: AppSec / Pentesting ─── */}
{activeTab === 'appsec' && (
<FadeInView delay={0.2}>
{/* Intro */}
<GlassCard className="!p-3 mb-4" hover={false}>
<div className="flex items-start gap-2">
<Shield className="w-4 h-4 text-red-400 mt-0.5 shrink-0" />
<div className="text-[11px]">
<span className="text-white/80 font-semibold">
{lang === 'de' ? 'Warum ein 2. Wettbewerbsvergleich?' : 'Why a 2nd competitive comparison?'}
</span>
<p className="text-white/50 mt-1 leading-relaxed">
{lang === 'de'
? 'Kein Compliance-Anbieter (Vanta, Drata, etc.) bietet DAST, SAST oder LLM-basierte Code-Fixes. Kein AppSec-Anbieter (Snyk, Veracode, etc.) bietet DSGVO/AI-Act-Compliance. ComplAI ist die einzige Plattform, die beides kombiniert.'
: 'No compliance vendor (Vanta, Drata, etc.) offers DAST, SAST, or LLM-based code fixes. No AppSec vendor (Snyk, Veracode, etc.) offers GDPR/AI Act compliance. ComplAI is the only platform combining both.'}
</p>
</div>
</div>
</GlassCard>
{/* AppSec Competitor Cards */}
<div className="mb-4">
<div className="flex items-center gap-2 mb-2">
<Shield className="w-3.5 h-3.5 text-red-400" />
<span className="text-xs font-semibold text-red-400">{lang === 'de' ? 'AppSec / Pentesting Anbieter' : 'AppSec / Pentesting Providers'}</span>
</div>
<div className="grid grid-cols-4 gap-2">
{APPSEC_COMPETITORS.map(c => (
<AppSecCard key={c.name} competitor={c} lang={lang} />
))}
</div>
</div>
{/* AppSec Feature Matrix */}
<div className="space-y-2">
<div>
<SectionHeader
label={lang === 'de' ? 'USP — nur ComplAI' : 'USP — ComplAI only'}
count={APPSEC_FEATURES.filter(f => f.isUSP).length}
open={openSections.has('appsec-usp')}
onToggle={() => toggleSection('appsec-usp')}
accent="text-indigo-400"
/>
{openSections.has('appsec-usp') && (
<AppSecFeatureTable features={APPSEC_FEATURES.filter(f => f.isUSP)} lang={lang} highlight />
)}
</div>
<div>
<SectionHeader
label={lang === 'de' ? 'Alle AppSec Features' : 'All AppSec Features'}
count={APPSEC_FEATURES.length}
open={openSections.has('appsec-all')}
onToggle={() => toggleSection('appsec-all')}
/>
{openSections.has('appsec-all') && (
<AppSecFeatureTable features={APPSEC_FEATURES} lang={lang} />
)}
</div>
</div>
{/* Score Summary */}
<div className="mt-4 flex items-center justify-center gap-4 flex-wrap">
{[
{ name: 'ComplAI', score: APPSEC_FEATURES.filter(f => f.bp === true).length, color: 'text-indigo-400' },
{ name: 'Snyk', score: APPSEC_FEATURES.filter(f => f.snyk === true).length, color: 'text-white/50' },
{ name: 'Veracode', score: APPSEC_FEATURES.filter(f => f.veracode === true).length, color: 'text-white/50' },
{ name: 'Checkmarx', score: APPSEC_FEATURES.filter(f => f.checkmarx === true).length, color: 'text-white/50' },
{ name: 'SonarSrc', score: APPSEC_FEATURES.filter(f => f.sonar === true).length, color: 'text-white/50' },
{ name: 'Semgrep', score: APPSEC_FEATURES.filter(f => f.semgrep === true).length, color: 'text-white/50' },
{ name: 'Pentera', score: APPSEC_FEATURES.filter(f => f.pentera === true).length, color: 'text-white/50' },
{ name: 'Invicti', score: APPSEC_FEATURES.filter(f => f.invicti === true).length, color: 'text-white/50' },
{ name: 'Intruder', score: APPSEC_FEATURES.filter(f => f.intruder === 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}/{APPSEC_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>
)
}
function AppSecCard({ competitor: c, lang }: { competitor: AppSecCompetitor; lang: Language }) {
return (
<div className="bg-white/[0.04] border border-white/5 rounded-xl p-2 text-[11px]">
<div className="flex items-center gap-1.5 mb-1">
<span className="text-sm">{c.flag}</span>
<span className="font-semibold text-white/80 text-xs">{c.name}</span>
</div>
<div className="text-[10px] text-white/40 mb-1 truncate">{c.hq} · {c.founded}</div>
<div className="grid grid-cols-2 gap-x-2 gap-y-0.5 text-white/50">
<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 truncate">{c.revenue}</span>
</div>
</div>
<div className="mt-1 pt-1 border-t border-white/5 text-[10px]">
<div className="text-white/40 truncate">{c.funding}</div>
<div className="text-white/50 mt-0.5">{c.pricing}</div>
</div>
<div className="mt-1 text-[10px] text-white/35 truncate" title={c.focus[lang]}>
{c.focus[lang]}
</div>
</div>
)
}
function AppSecFeatureTable({ features, lang, highlight }: { features: AppSecFeature[]; lang: Language; highlight?: boolean }) {
const cols = ['bp', 'snyk', 'veracode', 'checkmarx', 'sonar', 'semgrep', 'pentera', 'invicti', 'intruder'] as const
const labels = ['ComplAI', 'Snyk', 'Veracode', 'Checkmarx', 'Sonar', 'Semgrep', 'Pentera', 'Invicti', 'Intruder']
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-[160px]">Feature</th>
{labels.map((l, idx) => (
<th key={l} className={`py-1.5 px-1 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.isUSP ? 'bg-indigo-500/5' : ''}`}>
<td className="py-1.5 px-2 flex items-center gap-1.5">
{f.isUSP && highlight && <Star className="w-3 h-3 text-yellow-400 shrink-0" />}
<span className={f.isUSP && highlight ? '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 text-center">
<StatusIcon value={f[col] as FeatureStatus} />
</td>
))}
</tr>
))}
</tbody>
</table>
</div>
)
}