diff --git a/admin-compliance/app/layout.tsx b/admin-compliance/app/layout.tsx
index 53bcf349..ccf2f814 100644
--- a/admin-compliance/app/layout.tsx
+++ b/admin-compliance/app/layout.tsx
@@ -1,13 +1,8 @@
import type { Metadata } from 'next'
-import { Inter, Public_Sans, Source_Serif_4, IBM_Plex_Mono } from 'next/font/google'
+import { Inter } from 'next/font/google'
import './globals.css'
const inter = Inter({ subsets: ['latin'] })
-// Redesign fonts (design/redesign) — exposed as CSS variables; the new
-// design-language components opt in via Tailwind font-publicSans/-sourceSerif/-plexMono.
-const publicSans = Public_Sans({ subsets: ['latin'], weight: ['400', '500', '600', '700', '800'], variable: '--font-public-sans' })
-const sourceSerif = Source_Serif_4({ subsets: ['latin'], weight: ['400', '500', '600'], style: ['normal', 'italic'], variable: '--font-source-serif' })
-const plexMono = IBM_Plex_Mono({ subsets: ['latin'], weight: ['400', '500', '600'], variable: '--font-plex-mono' })
export const metadata: Metadata = {
title: 'BreakPilot Admin Compliance',
@@ -20,7 +15,7 @@ export default function RootLayout({
children: React.ReactNode
}) {
return (
-
+
{children}
)
diff --git a/admin-compliance/app/sdk/design-system/page.tsx b/admin-compliance/app/sdk/design-system/page.tsx
deleted file mode 100644
index 8905e110..00000000
--- a/admin-compliance/app/sdk/design-system/page.tsx
+++ /dev/null
@@ -1,114 +0,0 @@
-'use client'
-
-// Design-system showcase (Schritt A verification). Renders the redesign tokens +
-// chips so the design language can be reviewed in isolation. Internal reference
-// page (not in the customer sidebar).
-
-import { GeltungChip, SeverityChip, DomainTag, MonoId } from '@/components/redesign/Chips'
-import { COLORS, DOMAIN } from '@/components/redesign/tokens'
-
-function Section({ title, children }: { title: string; children: React.ReactNode }) {
- return (
-
- )
-}
-
-function Swatch({ name, hex }: { name: string; hex: string }) {
- return (
-
- )
-}
-
-export default function DesignSystemPage() {
- return (
-
-
-
- Design-Sprache
-
-
- Schritt A — Tokens & Bausteine des Redesigns (Geltung, Severity, Domänen, Typografie).
- Referenz: design/redesign/HANDOFF_README.md.
-
-
-
-
-
-
-
- + Klartext-Maßnahme
- M542
-
-
-
-
-
-
-
-
-
-
-
-
- {(['safety', 'cyber', 'bridge'] as const).map((k) => (
-
-
{DOMAIN[k].label}
-
{DOMAIN[k].accent}
-
- ))}
-
-
-
-
-
-
Public Sans — UI & Überschriften (800)
-
Source Serif 4 — Normzitate / rechtliche Texte (kursiv)
-
IBM Plex Mono — interne IDs · CRA-AI-8 · R = S × (F + W + P)
-
-
-
-
-
-
-
-
- {[
- '3 Ebenen pro Screen: Überblick → Cyber×Safety → Technik (eingeklappt).',
- 'Klartext führt. Interne IDs nur in Monospace nachgestellt.',
- 'Co-Pilot statt Roboter-Anwalt — keine Panik-Rot-Blöcke.',
- 'Pflicht / Empfehlung / Kann immer visuell getrennt.',
- ].map((t, i) => (
- -
- {i + 1}
- {t}
-
- ))}
-
-
-
-
-
- )
-}
diff --git a/admin-compliance/app/sdk/iace/[projectId]/cra/_components/CyberMeetsSafety.tsx b/admin-compliance/app/sdk/iace/[projectId]/cra/_components/CyberMeetsSafety.tsx
deleted file mode 100644
index 42457ed6..00000000
--- a/admin-compliance/app/sdk/iace/[projectId]/cra/_components/CyberMeetsSafety.tsx
+++ /dev/null
@@ -1,189 +0,0 @@
-'use client'
-
-// Ebene 2 — "Cyber trifft Safety" (Redesign-Herzstück / USP).
-// Macht sichtbar, wo ein Cyber-Befund eine bereits mechanisch gemilderte
-// CE-Gefährdung wieder aufreißt. Bindet an die ECHTEN Bridge-Daten (cross_links)
-// + findings + open_measures aus useCRA. Design nach design/redesign/HANDOFF_README.md.
-// Additiv: ersetzt den bestehenden CRACyberView NICHT.
-
-import { useState } from 'react'
-import { CRADemo, CrossLink, CRAFinding, Measure } from '../_hooks/useCRADemo'
-import { GeltungChip, MonoId } from '@/components/redesign/Chips'
-import { COLORS, DOMAIN, Geltung } from '@/components/redesign/tokens'
-
-// Maßnahme → Geltung: technische Schutzmaßnahmen = Pflicht; Info/Hardening-Guides
-// = Empfehlung. Heuristik (kein Geltung-Feld in den Daten); nie still „Kann".
-function measureGeltung(name: string, id: string): Geltung {
- const hay = `${id} ${name}`.toLowerCase()
- return /info|guide|hardening|dokumentation|beilegen|hinweis|schulung/.test(hay) ? 'empfehlung' : 'pflicht'
-}
-
-function ChainNode({ tone, marker, label, text }: {
- tone: 'ce' | 'cyber' | 'residual'; marker: string; label: string; text: string
-}) {
- const s = tone === 'ce'
- ? { bg: DOMAIN.safety.tint, border: DOMAIN.safety.border, accent: DOMAIN.safety.accent }
- : tone === 'cyber'
- ? { bg: DOMAIN.cyber.tint, border: DOMAIN.cyber.border, accent: DOMAIN.cyber.accent }
- : { bg: '#FBECEA', border: '#F3D2CC', accent: '#A23323' }
- return (
-
-
- {marker}{label}
-
-
{text}
-
- )
-}
-
-function HazardCard({ link, findings, measures, defaultOpen }: {
- link: CrossLink; findings: CRAFinding[]; measures: Measure[]; defaultOpen: boolean
-}) {
- const [open, setOpen] = useState(defaultOpen)
- const triggers = findings.filter((f) => link.cyber_finding_ids.includes(f.id))
- const cyberText = triggers.map((f) => f.title).join(' · ') || link.cyber_finding_ids.join(', ')
- const measureIds = Array.from(new Set(triggers.flatMap((f) => f.measures)))
- const measureObjs = measureIds.map((id) => measures.find((m) => m.id === id) || { id, name: id, description: '', norm_refs: [] })
- const normPills = Array.from(new Set(triggers.flatMap((f) => [f.annex_anchor, ...f.requirement_ids, ...f.iso27001_ref]).filter(Boolean)))
-
- return (
-
-
-
-
Mechanische Gefährdung
-
{link.safety_hazard}
-
-
-
- Restrisiko: wieder offen
-
-
-
-
-
- →
-
- →
-
-
-
-
- Warum:
- {link.cyber_breaks_it}
-
-
- {measureObjs.length > 0 && (
-
-
Empfohlene Maßnahmen
-
- {measureObjs.map((m) => (
- -
-
- {m.name}
- {m.id}
-
- ))}
-
-
- )}
-
-
-
- {open && (
-
-
-
Auslösende Cyber-Befunde
-
- {triggers.map((f) => {f.location || f.id})}
-
-
-
-
Norm- & Annex-Bezug
-
- {normPills.map((n) => (
- {n}
- ))}
-
-
-
- )}
-
-
- )
-}
-
-export function CyberMeetsSafety({ data }: { data: CRADemo }) {
- const links = data.cross_links || []
- const measures = data.open_measures || []
- const [filter, setFilter] = useState<'alle' | 'pflicht' | 'empfehlung'>('alle')
-
- if (links.length === 0) {
- return (
-
-
Cyber trifft Safety
-
- Aktuell keine Cyber-Befunde, die eine CE-Gefährdung wieder öffnen. Sobald Befunde vorliegen, erscheinen sie hier.
-
-
- )
- }
-
- const backlog = measures.map((m) => ({ m, g: measureGeltung(m.name, m.id) }))
- .filter((x) => filter === 'alle' || x.g === filter)
-
- return (
-
- {/* Domänen-Bar */}
-
-
-
Safety (Maschine / CE)
-
Mechanisch gemilderte Gefährdungen
-
-
-
⚡
-
{links.length} wieder geöffnet
-
-
-
Cyber (CRA)
-
Befunde, die Schutzfunktionen aushebeln
-
-
-
- {links.map((link, i) => (
-
- ))}
-
- {/* Maßnahmen-Backlog */}
-
-
-
- Maßnahmen-Backlog · {measures.length} Maßnahmen · nach Geltung
-
-
- {(['alle', 'pflicht', 'empfehlung'] as const).map((f) => (
-
- ))}
-
-
-
- {backlog.map(({ m, g }) => (
- -
-
- {m.name}
- {m.norm_refs?.[0] || 'Sicherheit'}
- {m.id}
-
- ))}
- {backlog.length === 0 && - Keine Maßnahmen in diesem Filter.
}
-
-
-
- )
-}
diff --git a/admin-compliance/app/sdk/iace/[projectId]/cra/page.tsx b/admin-compliance/app/sdk/iace/[projectId]/cra/page.tsx
index 0693183b..61c0b968 100644
--- a/admin-compliance/app/sdk/iace/[projectId]/cra/page.tsx
+++ b/admin-compliance/app/sdk/iace/[projectId]/cra/page.tsx
@@ -3,7 +3,6 @@
import { useParams } from 'next/navigation'
import { useCRA } from './_hooks/useCRA'
import { CRACyberView } from './_components/CRACyberView'
-import { CyberMeetsSafety } from './_components/CyberMeetsSafety'
import { WeightsControl } from './_components/WeightsControl'
import { SnapshotPanel } from './_components/SnapshotPanel'
import { ScannerRepoPicker } from './_components/ScannerRepoPicker'
@@ -32,22 +31,7 @@ export default function CRAPage() {
)}
-
- {/* Ebene 2 — Cyber trifft Safety (Redesign, neue Design-Sprache) */}
-
-
- Cyber trifft Safety
-
-
-
-
- {/* Bisherige Detailansicht (bleibt erhalten, bis das Redesign 100% abdeckt) */}
-
- Bisherige Detailansicht (CRACyberView)
-
-
-
-
+
)
diff --git a/admin-compliance/components/redesign/Chips.tsx b/admin-compliance/components/redesign/Chips.tsx
deleted file mode 100644
index aded5fa8..00000000
--- a/admin-compliance/components/redesign/Chips.tsx
+++ /dev/null
@@ -1,64 +0,0 @@
-'use client'
-
-// Reusable design-language chips. Geltung (Pflicht/Empfehlung/Kann) and Severity
-// follow the handoff specs exactly (bg/text/border + marker glyph). Klartext label
-// leads; internal IDs are never shown by the chip itself. See ./tokens.
-
-import {
- GELTUNG, PFLICHT_MARKER, SEVERITY, DOMAIN,
- normalizeGeltung, normalizeSeverity, Geltung, Severity, Domain,
-} from './tokens'
-
-function GeltungMarker({ g }: { g: Geltung }) {
- const m = GELTUNG[g].marker
- if (m === 'square') {
- return
- }
- // diamond ◇ (Empfehlung) / circle ○ (Kann) — open glyphs in the chip text color
- return {m === 'diamond' ? '◇' : '○'}
-}
-
-export function GeltungChip({ value, className = '' }: { value: Geltung | string; className?: string }) {
- const g = normalizeGeltung(value)
- const t = GELTUNG[g]
- return (
-
-
- {t.label}
-
- )
-}
-
-export function SeverityChip({ value, className = '' }: { value: Severity | string; className?: string }) {
- const s = normalizeSeverity(value)
- const t = SEVERITY[s]
- return (
-
- {t.label}
-
- )
-}
-
-// Small domain tag (Safety / Cyber / Schnittstelle) — tinted, not neon.
-export function DomainTag({ value, label, className = '' }: { value: Domain; label?: string; className?: string }) {
- const d = DOMAIN[value]
- return (
-
- {label || d.label}
-
- )
-}
-
-// Monospace internal ID — IDs are ALWAYS secondary/nachgestellt, never a heading.
-export function MonoId({ children, className = '' }: { children: React.ReactNode; className?: string }) {
- return {children}
-}
diff --git a/admin-compliance/components/redesign/tokens.ts b/admin-compliance/components/redesign/tokens.ts
deleted file mode 100644
index c2ff19b3..00000000
--- a/admin-compliance/components/redesign/tokens.ts
+++ /dev/null
@@ -1,55 +0,0 @@
-// Design-language tokens — single source of truth for the redesign.
-// Mirrors design/redesign/HANDOFF_README.md (Claude Design handoff). The same
-// values are mirrored into tailwind.config.ts (namespaces re/geltung/severity/domain)
-// for utility-class use; components that need the exact chip look import from here.
-
-export const COLORS = {
- page: '#EDEFF3', surface: '#FFFFFF', border: '#E4E7EE', borderSoft: '#F0F1F5',
- ink: '#1A1D29', muted: '#5A6273', muted2: '#6B7184', faint: '#8089A0', fainter: '#9AA1B2',
- brand: '#4338CA', brandText: '#3B36B0', brandTint: '#EEF0FF', brandTint2: '#F6F4FF',
- panel: '#15182A', panelText: '#E8EAF2', panelText2: '#C7CBDA', panelAccent: '#9B8BF5',
-} as const
-
-// --- Geltung: Pflicht / Empfehlung / Kann (the core 3-tier obligation system) ---
-export type Geltung = 'pflicht' | 'empfehlung' | 'kann'
-export const GELTUNG: Record = {
- pflicht: { label: 'Pflicht', bg: '#FBECEA', text: '#A23323', border: '#F3D2CC', marker: 'square' },
- empfehlung: { label: 'Empfehlung', bg: '#EEF0FF', text: '#3B36B0', border: '#DAD9F7', marker: 'diamond' },
- kann: { label: 'Kann', bg: '#F1F3F7', text: '#5A6273', border: '#E2E6EE', marker: 'circle' },
-}
-export const PFLICHT_MARKER = '#C0362C' // filled square color
-
-export function normalizeGeltung(v: string | Geltung): Geltung {
- const s = String(v || '').toLowerCase()
- if (['pflicht', 'mandatory', 'required', 'must', 'core'].includes(s)) return 'pflicht'
- if (['empfehlung', 'recommended', 'should', 'review'].includes(s)) return 'empfehlung'
- if (['kann', 'optional', 'may', 'can'].includes(s)) return 'kann'
- return 'empfehlung' // unknown → recommendation (never silently drop; never over-state as Pflicht)
-}
-
-// --- Severity (Dringlichkeit) ---
-export type Severity = 'kritisch' | 'hoch' | 'mittel' | 'niedrig'
-export const SEVERITY: Record = {
- kritisch: { label: 'Kritisch', bg: '#FBE9E7', text: '#B5362A' },
- hoch: { label: 'Hoch', bg: '#FBF1E0', text: '#9A6410' },
- mittel: { label: 'Mittel', bg: '#FAF6DD', text: '#897209' },
- niedrig: { label: 'Niedrig', bg: '#E9F5EF', text: '#2C7A52' },
-}
-export function normalizeSeverity(v: string | Severity): Severity {
- const s = String(v || '').toLowerCase()
- if (['kritisch', 'critical'].includes(s)) return 'kritisch'
- if (['hoch', 'high'].includes(s)) return 'hoch'
- if (['mittel', 'medium', 'moderate'].includes(s)) return 'mittel'
- if (['niedrig', 'low', 'minor'].includes(s)) return 'niedrig'
- return 'mittel'
-}
-
-// --- Domains (Safety / Cyber / Schnittstelle) ---
-export type Domain = 'safety' | 'cyber' | 'bridge'
-export const DOMAIN: Record = {
- safety: { label: 'Safety (Maschine/CE)', accent: '#0E8A66', tint: '#F3FAF7', border: '#D7ECE3' },
- cyber: { label: 'Cyber (CRA)', accent: '#6A43D6', tint: '#F6F1FE', border: '#E4D8F7' },
- bridge: { label: 'Cyber × Safety', accent: '#BE7714', tint: '#FCF6EF', border: '#F2E6D5', warn: '#9A6410' },
-}
diff --git a/admin-compliance/tailwind.config.ts b/admin-compliance/tailwind.config.ts
index a92c4ea1..0532d33c 100644
--- a/admin-compliance/tailwind.config.ts
+++ b/admin-compliance/tailwind.config.ts
@@ -48,39 +48,9 @@ const config: Config = {
900: '#0c4a6e',
950: '#082f49',
},
-
- // === Redesign design-language tokens (2026-06, see design/redesign) ===
- // Additive + namespaced ('re', 'geltung', 'severity', 'domain') so nothing
- // existing is overridden. Single source of truth: components/redesign/tokens.ts.
- re: {
- page: '#EDEFF3', surface: '#FFFFFF', border: '#E4E7EE', 'border-soft': '#F0F1F5',
- ink: '#1A1D29', muted: '#5A6273', 'muted-2': '#6B7184', faint: '#8089A0', fainter: '#9AA1B2',
- brand: '#4338CA', 'brand-text': '#3B36B0', 'brand-tint': '#EEF0FF', 'brand-tint-2': '#F6F4FF',
- panel: '#15182A', 'panel-text': '#E8EAF2', 'panel-text-2': '#C7CBDA', 'panel-accent': '#9B8BF5',
- },
- geltung: {
- pflicht: { bg: '#FBECEA', text: '#A23323', border: '#F3D2CC', marker: '#C0362C' },
- empfehlung: { bg: '#EEF0FF', text: '#3B36B0', border: '#DAD9F7' },
- kann: { bg: '#F1F3F7', text: '#5A6273', border: '#E2E6EE' },
- },
- severity: {
- kritisch: { bg: '#FBE9E7', text: '#B5362A' },
- hoch: { bg: '#FBF1E0', text: '#9A6410' },
- mittel: { bg: '#FAF6DD', text: '#897209' },
- niedrig: { bg: '#E9F5EF', text: '#2C7A52' },
- },
- domain: {
- safety: '#0E8A66', 'safety-tint': '#F3FAF7', 'safety-border': '#D7ECE3',
- cyber: '#6A43D6', 'cyber-tint': '#F6F1FE', 'cyber-border': '#E4D8F7',
- bridge: '#BE7714', 'bridge-tint': '#FCF6EF', 'bridge-border': '#F2E6D5', 'bridge-warn': '#9A6410',
- },
},
fontFamily: {
sans: ['Inter', 'system-ui', 'sans-serif'],
- // Redesign fonts (loaded via next/font in app/layout.tsx as CSS variables).
- publicSans: ['var(--font-public-sans)', 'Inter', 'system-ui', 'sans-serif'],
- sourceSerif: ['var(--font-source-serif)', 'Georgia', 'serif'],
- plexMono: ['var(--font-plex-mono)', 'ui-monospace', 'SFMono-Regular', 'monospace'],
},
},
},