feat(pitch-deck): add AI Presenter mode with LiteLLM migration and FAQ system
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

- 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>
This commit is contained in:
Benjamin Admin
2026-03-20 11:45:55 +01:00
parent df0a9d6cf0
commit 3a2567b44d
20 changed files with 2434 additions and 164 deletions

View File

@@ -5,7 +5,7 @@ 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,
DollarSign, Cpu, Star, Check, X, Minus, Shield, Tag,
} from 'lucide-react'
import GradientText from '../ui/GradientText'
import FadeInView from '../ui/FadeInView'
@@ -201,6 +201,12 @@ const ALL_FEATURES: ComparisonFeature[] = [
{ 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 },
@@ -248,6 +254,179 @@ const DACH_NOTE = {
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 }) {
@@ -304,7 +483,7 @@ function SectionHeader({
// ─── Component ─────────────────────────────────────────────────────────────────
type ViewTab = 'overview' | 'features'
type ViewTab = 'overview' | 'features' | 'pricing' | 'appsec'
export default function CompetitionSlide({ lang, features, competitors }: CompetitionSlideProps) {
const i = t(lang)
@@ -344,10 +523,12 @@ export default function CompetitionSlide({ lang, features, competitors }: Compet
</FadeInView>
{/* Tab Bar */}
<FadeInView delay={0.15} className="flex justify-center gap-2 mb-4">
<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}
@@ -509,6 +690,178 @@ export default function CompetitionSlide({ lang, features, competitors }: Compet
</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>
)
}
@@ -619,3 +972,71 @@ function FeatureTable({
</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>
)
}