import type { ConfidenceLevel, DataQualityLevel } from '../domain/enums' import { CONF_HIGH, CONF_MEDIUM, DQ_HIGH, DQ_MEDIUM } from './constants' // ── Semantic color tokens ───────────────────────────────────────────────────── export const DS_COLORS = { resultType: { VERIFIED_PORTFOLIO: { bg: 'rgba(21,38,66,0.10)', fg: '#152642' }, MAISON_WORK: { bg: 'rgba(45,90,138,0.10)', fg: '#2d5a8a' }, FUTURE_AVAILABILITY: { bg: 'rgba(91,63,138,0.10)', fg: '#5b3f8a' }, }, confidence: { VERY_HIGH: { bg: 'rgba(29,99,66,0.12)', fg: '#1d6342' }, HIGH: { bg: 'rgba(29,99,66,0.09)', fg: '#1d6342' }, MEDIUM: { bg: 'rgba(21,38,66,0.10)', fg: '#152642' }, LOW: { bg: 'rgba(161,98,7,0.12)', fg: '#a16207' }, VERY_LOW: { bg: 'rgba(185,28,28,0.12)', fg: '#b91c1c' }, }, risk: { LOW: { bg: 'rgba(29,99,66,0.10)', fg: '#1d6342' }, MEDIUM: { bg: 'rgba(161,98,7,0.10)', fg: '#a16207' }, HIGH: { bg: 'rgba(185,28,28,0.10)', fg: '#b91c1c' }, CRITICAL: { bg: 'rgba(127,0,0,0.12)', fg: '#7f1d1d' }, }, availability: { AVAILABLE_NOW: { bg: 'rgba(29,99,66,0.10)', fg: '#1d6342' }, AVAILABLE_SOON: { bg: 'rgba(161,98,7,0.10)', fg: '#a16207' }, FUTURE_SIGNAL: { bg: 'rgba(91,63,138,0.10)', fg: '#5b3f8a' }, OCCUPIED: { bg: 'rgba(100,116,139,0.10)', fg: '#475569' }, UNKNOWN: { bg: '#f4f3f0', fg: '#9a9a9a' }, }, freshness: { FRESH: { bg: 'rgba(29,99,66,0.10)', fg: '#1d6342' }, STALE: { bg: 'rgba(161,98,7,0.10)', fg: '#a16207' }, OUTDATED: { bg: 'rgba(185,28,28,0.10)', fg: '#b91c1c' }, }, dataQuality: { HIGH: { bg: 'rgba(29,99,66,0.10)', fg: '#1d6342' }, MEDIUM: { bg: 'rgba(161,98,7,0.10)', fg: '#a16207' }, LOW: { bg: 'rgba(185,28,28,0.10)', fg: '#b91c1c' }, INCOMPLETE: { bg: 'rgba(127,0,0,0.12)', fg: '#7f1d1d' }, }, heat: { VERY_HOT: { bg: '#fef3c7', border: '#fcd34d', icon: '#a16207', text: '#92400e' }, HOT: { bg: '#fff7ed', border: '#fed7aa', icon: '#a16207', text: '#92400e' }, }, futureCard: { controlled: { accent: '#5b3f8a', accentHover: '#4a3070', headerBg: '#faf7ff', border: '#e9d5ff', badgeBg: '#ede9fe', badgeText: '#5b21b6', }, signal: { accent: '#2d5a8a', accentHover: '#1e4068', headerBg: '#f0f6ff', border: '#bfdbfe', badgeBg: '#dbeafe', badgeText: '#1e40af', indicator: '#2d5a8a', }, }, } as const // ── Text color tokens ───────────────────────────────────────────────────────── export const DS_TEXT = { primary: '#141414', secondary: '#5c5c5c', muted: '#9a9a9a', disabled: '#c4c4c4', inverted: '#ffffff', success: '#1d6342', warning: '#a16207', error: '#b91c1c', danger: '#b91c1c', info: '#2d5a8a', brand: '#152642', signal: '#5b3f8a', successDark: '#166534', warningDark: '#92400e', signalDark: '#4c1d95', infoDark: '#0c4a6e', brandDark: '#0e1c30', } as const // ── Background tokens ───────────────────────────────────────────────────────── export const DS_BG = { page: '#f9f8f6', surface: '#ffffff', subtle: '#f4f3f0', muted: '#e8e7e4', } as const // ── Border tokens ───────────────────────────────────────────────────────────── export const DS_BORDER = { default: '#e8e7e4', muted: '#f2f1ee', strong: '#c8c7c4', } as const // ── Surface tokens ──────────────────────────────────────────────────────────── export const DS_SURFACE = { success: { bg: '#f0fdf4', border: '#bbf7d0' }, warning: { bg: '#fffbeb', border: '#fde68a' }, error: { bg: '#fef2f2', border: '#fecaca' }, info: { bg: '#f0f6ff', border: '#bfdbfe' }, indigo: { bg: '#eef2ff', border: '#e0e7ff' }, purple: { bg: '#faf7ff', border: '#e9d5ff' }, orange: { bg: '#fff7ed', border: '#fed7aa' }, blue: { bg: '#f0f6ff', border: '#bfdbfe' }, neutral: { bg: '#f9f8f6', border: '#e8e7e4' }, slate: { bg: '#f4f3f0', border: '#e8e7e4' }, } as const // ── Neutrale Skala ──────────────────────────────────────────────────────────── /** * Die kühle Graustufe, auf der Tabellen, Trennlinien und Nebentexte liegen. * * Sie war über rund 200 Dateien als Hex-Literal verstreut — dieselben zehn * Werte, immer wieder abgetippt. Die Stufen entsprechen exakt den bisher * verwendeten Werten; die Zusammenführung ändert kein einziges Pixel, macht * aber einen späteren Themenwechsel überhaupt erst möglich. * * Abgrenzung zu `DS_BG`/`DS_BORDER`: jene tragen den warmen Grundton der * Anwendung (Papier), diese Skala den kühlen für Datenflächen. */ export const DS_SLATE = { 50: '#f8fafc', 100: '#f1f5f9', 200: '#e2e8f0', 300: '#cbd5e1', 400: '#94a3b8', 500: '#64748b', 600: '#475569', 700: '#334155', 800: '#1e293b', 900: '#0f172a', } as const /** Weitere neutrale Einzelwerte ohne Platz in der Skala. */ export const DS_NEUTRAL = { white: '#ffffff', offWhite: '#fafafa', paper: '#fbfaf8', paperTint: '#f0f4f8', stone: '#b0aead', graphite: '#374151', sidebar: '#0f1923', gold: '#b8975a', } as const // ── Markenfarben ────────────────────────────────────────────────────────────── /** * Das dunkle Blau der Anwendung samt seinen Hover-Stufen. * * `hover` und `hoverAlt` unterscheiden sich um zwei Prozent Helligkeit — sie * sind historisch gewachsen und stehen beide im Code. Sie bleiben getrennt, * damit die Zusammenführung nichts sichtbar verschiebt; wer sie vereinheitlichen * will, tut das ab jetzt an einer Stelle statt an vierzig. */ export const DS_BRAND = { main: '#152642', hover: '#16304d', hoverAlt: '#162d4a', dark: '#0e1c30', darker: '#1a3050', muted: '#5a87a3', light: '#64b5f6', } as const // ── Akzentfarben nach Bedeutung ─────────────────────────────────────────────── /** * Semantische Akzente. Jede Gruppe führt Vorder-, Flächen- und Randfarbe * derselben Bedeutung, damit ein Zustand nicht auf zwei Bildschirmen zwei * verschiedene Grüntöne bekommt. */ export const DS_ACCENT = { success: { main: '#1a7a4a', strong: '#15803d', bright: '#16a34a', emerald: '#10b981', dark: '#155f3a', darkAlt: '#15643c', bg: '#f0fdf4', bgAlt: '#dcfce7', border: '#86efac', }, warning: { main: '#d97706', strong: '#ea580c', amber: '#f59e0b', burnt: '#c2410c', dark: '#b45309', darker: '#854d0e', darkest: '#7a4f00', brown: '#7c3d12', bg: '#fffbeb', bgAlt: '#fff7ed', border: '#fcd34d', borderSoft: '#fef3c7', }, danger: { main: '#c0392b', strong: '#dc2626', bright: '#ef4444', dark: '#a93226', darkest: '#7f1d1d', bg: '#fef2f2', bgAlt: '#fff1f2', border: '#fca5a5', }, violet: { main: '#7c3aed', strong: '#6d28d9', light: '#8b5cf6', dark: '#5b21b6', darkest: '#4c1d95', bg: '#faf5ff', bgAlt: '#f5f3ff', border: '#c4b5fd', borderSoft: '#ddd6fe', tint: '#ede9fe', }, indigo: { main: '#4f46e5', strong: '#4338ca', dark: '#3730a3', light: '#6366f1', bg: '#eef2ff', border: '#e0e7ff', }, blue: { main: '#1d4ed8', strong: '#2563eb', dark: '#1e40af', darkest: '#1e3a8a', bg: '#eff6ff', bgAlt: '#f0f9ff', border: '#bfdbfe', borderSoft: '#dbeafe', }, cyan: { main: '#0891b2', deep: '#0369a1', dark: '#075985', bg: '#e0f2fe', border: '#bae6fd', }, } as const // ── Match tier surface ──────────────────────────────────────────────────────── export const DS_MATCH_TIER = { strong: DS_SURFACE.success, moderate: DS_SURFACE.warning, weak: DS_SURFACE.error, } as const // ── Pre-market & market signal aliases ──────────────────────────────────────── export const DS_PRE_MARKET = DS_COLORS.futureCard.controlled export const DS_MARKET_SIGNAL = DS_COLORS.futureCard.signal // ── Badge color presets ─────────────────────────────────────────────────────── export const BADGE_COLORS = { confidenceHigh: '#1d6342', confidenceMedium: '#a16207', confidenceLow: '#b91c1c', riskHigh: '#b91c1c', riskMedium: '#a16207', riskLow: '#1d6342', preMarket: '#5b3f8a', marketSignal: '#2d5a8a', verified: '#152642', info: '#2d5a8a', muted: '#9a9a9a', gold: '#b8975a', silver: '#7a8a9a', bronze: '#7a6050', } as const // ── Shadow tokens ───────────────────────────────────────────────────────────── export const DS_SHADOW = { card: '0 1px 3px rgba(0,0,0,0.06)', panel: '0 3px 6px rgba(0,0,0,0.07)', dialog: '0 16px 24px rgba(0,0,0,0.10)', } as const // ── Inquiry status metadata ─────────────────────────────────────────────────── export const INQUIRY_STATUS_META: Record = { new: { label: 'Neu', fg: '#b91c1c', bg: '#fef2f2' }, in_progress: { label: 'Aktiv', fg: '#a16207', bg: '#fffbeb' }, answered: { label: 'Beantwortet', fg: '#1d6342', bg: '#f0fdf4' }, archived: { label: 'Archiviert', fg: '#9a9a9a', bg: '#f9f8f6' }, } // ── Score → qualitative level helpers ──────────────────────────────────────── export function scoreToConfidenceLevel(score: number): ConfidenceLevel { if (score >= CONF_HIGH) return 'VERY_HIGH' if (score >= 0.75) return 'HIGH' if (score >= CONF_MEDIUM) return 'MEDIUM' if (score >= 0.35) return 'LOW' return 'VERY_LOW' } export function scoreToDataQualityLevel(score: number): DataQualityLevel { if (score >= DQ_HIGH) return 'HIGH' if (score >= DQ_MEDIUM) return 'MEDIUM' if (score > 0) return 'LOW' return 'INCOMPLETE' } // ── Result type meta ────────────────────────────────────────────────────────── export const RESULT_TYPE_META: Record = { VERIFIED_PORTFOLIO: { label: 'Verifiziertes Objekt', color: '#152642', bg: 'rgba(21,38,66,0.10)' }, MAISON_WORK: { label: 'Maison Work', color: '#2d5a8a', bg: 'rgba(45,90,138,0.10)' }, FUTURE_AVAILABILITY: { label: 'Zukunftssignal', color: '#5b3f8a', bg: 'rgba(91,63,138,0.10)' }, } // ── Kanalherkunft der Leads bei Nora (Runde 5, §12) ────────────────────────── /** * Badge je Kanal. Nach dem Muster von `RESULT_TYPE_META`: Beschriftung und * Farben stehen zusammen, damit derselbe Kanal in Liste, Filter und Detail nie * unterschiedlich aussieht. * * Der Schlüssel ist `LeadChannel` aus `domain/unifiedLead.ts`; hier steht er * bewusst als `string`, damit die Designschicht nicht auf das Domänenmodell * zeigt — die Abhängigkeit läuft immer nur in die andere Richtung. */ export const LEAD_CHANNEL_META: Record = { KI_SIGNAL: { label: 'KI Signal', color: '#5b3f8a', bg: 'rgba(91,63,138,0.10)' }, NETZWERK: { label: 'Netzwerk', color: '#1a7a4a', bg: 'rgba(26,122,74,0.10)' }, CRM: { label: 'CRM', color: '#2d5a8a', bg: 'rgba(45,90,138,0.10)' }, }