diff --git a/apps/web/app/[locale]/(marketing)/pricing/_components/pricing-calculator.tsx b/apps/web/app/[locale]/(marketing)/pricing/_components/pricing-calculator.tsx
new file mode 100644
index 000000000..b3ee4eaaf
--- /dev/null
+++ b/apps/web/app/[locale]/(marketing)/pricing/_components/pricing-calculator.tsx
@@ -0,0 +1,570 @@
+'use client';
+
+import { useMemo, useState } from 'react';
+
+import Link from 'next/link';
+
+import { Check, ExternalLink, X } from 'lucide-react';
+
+import { Badge } from '@kit/ui/badge';
+import { Button } from '@kit/ui/button';
+import {
+ Card,
+ CardContent,
+ CardDescription,
+ CardHeader,
+ CardTitle,
+} from '@kit/ui/card';
+import {
+ Table,
+ TableBody,
+ TableCell,
+ TableHead,
+ TableHeader,
+ TableRow,
+} from '@kit/ui/table';
+import { cn } from '@kit/ui/utils';
+
+// ---------------------------------------------------------------------------
+// Data
+// ---------------------------------------------------------------------------
+
+interface Competitor {
+ id: string;
+ name: string;
+ note: string;
+ getPrice: (m: number) => number | null;
+ color: string;
+ maxMembers?: number;
+ verbandExtra: string | null;
+}
+
+const COMPETITORS: Competitor[] = [
+ {
+ id: 'sewobe',
+ name: 'SEWOBE VereinsManager',
+ note: 'VerbandsMANAGER separat',
+ getPrice: (m) => {
+ if (m <= 500) return 30;
+ if (m <= 1000) return 49;
+ if (m <= 2000) return 99;
+ if (m <= 3000) return 159;
+ if (m <= 5000) return 269;
+ if (m <= 7500) return 369;
+ return 469;
+ },
+ color: 'bg-red-500',
+ verbandExtra:
+ 'VerbandsMANAGER: separates Produkt, Preis auf Anfrage (deutlich teurer)',
+ },
+ {
+ id: 'easyverein',
+ name: 'easyVerein Professional',
+ note: 'Dachverbandslösung extra',
+ getPrice: (m) => {
+ if (m <= 100) return 20;
+ if (m <= 250) return 31;
+ if (m <= 500) return 49;
+ if (m <= 1000) return 79;
+ if (m <= 2000) return 129;
+ if (m <= 5000) return 249;
+ return 399;
+ },
+ color: 'bg-orange-500',
+ verbandExtra:
+ 'Dachverbandslösung: jede Instanz eigene kostenpflichtige Lizenz',
+ },
+ {
+ id: 'clubdesk',
+ name: 'ClubDesk',
+ note: 'Server in der Schweiz',
+ getPrice: (m) => {
+ if (m <= 50) return 0;
+ if (m <= 100) return 10;
+ if (m <= 250) return 15;
+ if (m <= 500) return 25;
+ if (m <= 1000) return 33;
+ return null;
+ },
+ color: 'bg-blue-500',
+ maxMembers: 1000,
+ verbandExtra: null,
+ },
+ {
+ id: 'wiso',
+ name: 'WISO MeinVerein Web',
+ note: 'Buhl / ZDF-WISO Marke',
+ getPrice: (m) => {
+ if (m <= 100) return 10;
+ if (m <= 250) return 15;
+ if (m <= 500) return 25;
+ if (m <= 1000) return 35;
+ return null;
+ },
+ color: 'bg-violet-500',
+ maxMembers: 1000,
+ verbandExtra: null,
+ },
+];
+
+const TIERS = [
+ { name: 'Starter', price: 29, maxMembers: 250 },
+ { name: 'Pro', price: 59, maxMembers: 1000 },
+ { name: 'Verband', price: 199, maxMembers: 10000 },
+ { name: 'Enterprise', price: 349, maxMembers: 99999 },
+] as const;
+
+function getTier(m: number) {
+ return TIERS.find((t) => m <= t.maxMembers) ?? TIERS[TIERS.length - 1]!;
+}
+
+function fmt(n: number) {
+ return n.toLocaleString('de-DE');
+}
+
+// ---------------------------------------------------------------------------
+// Feature comparison data
+// ---------------------------------------------------------------------------
+
+type FeatureValue = boolean | string;
+
+interface FeatureRow {
+ label: string;
+ mcms: FeatureValue;
+ sewobe: FeatureValue;
+ easy: FeatureValue;
+ club: FeatureValue;
+ wiso: FeatureValue;
+}
+
+const USP_FEATURES: FeatureRow[] = [
+ {
+ label: 'Verbandsmodul (Mehrebenen-Hierarchie)',
+ mcms: true,
+ sewobe: 'Separates Produkt',
+ easy: 'Extra Lösung',
+ club: false,
+ wiso: false,
+ },
+ {
+ label: 'Vereins-Website inklusive',
+ mcms: true,
+ sewobe: false,
+ easy: false,
+ club: true,
+ wiso: false,
+ },
+ {
+ label: 'Kursverwaltung (Dozenten, Räume)',
+ mcms: true,
+ sewobe: false,
+ easy: false,
+ club: false,
+ wiso: false,
+ },
+ {
+ label: 'SEPA-Lastschrift',
+ mcms: true,
+ sewobe: true,
+ easy: true,
+ club: true,
+ wiso: true,
+ },
+ {
+ label: 'Persönlicher Telefon-Support',
+ mcms: true,
+ sewobe: 'Kostenpflichtig',
+ easy: false,
+ club: false,
+ wiso: false,
+ },
+ {
+ label: 'Unbegrenzte Benutzer (ab Pro)',
+ mcms: true,
+ sewobe: '5 inkl., +6€/User',
+ easy: '3–10 inkl.',
+ club: false,
+ wiso: false,
+ },
+ {
+ label: 'Server in Deutschland',
+ mcms: true,
+ sewobe: true,
+ easy: true,
+ club: 'Schweiz',
+ wiso: true,
+ },
+ {
+ label: 'Individuelle Module',
+ mcms: true,
+ sewobe: 'Aufpreis',
+ easy: false,
+ club: false,
+ wiso: false,
+ },
+];
+
+// ---------------------------------------------------------------------------
+// Sub-components
+// ---------------------------------------------------------------------------
+
+function FeatureCell({ value }: { value: FeatureValue }) {
+ if (value === true) {
+ return
+ Echte Preise von SEWOBE, easyVerein, ClubDesk und WISO MeinVerein. + Alle Preise netto. +
++ {members >= 1000 + ? `${Math.round((1 - tier.price / (compPrices[0]?.p ?? tier.price)) * 100)}% günstiger als SEWOBE — mit dem Verbandsmodul inklusive.` + : 'Alle Funktionen inklusive. Keine versteckten Kosten.'} +
++ 14 Tage kostenlos testen. Persönliche Einrichtung inklusive. +
+