diff --git a/CLAUDE.md b/CLAUDE.md index e8c6515..99cf8ea 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -63,7 +63,8 @@ src/: favicon.svg: "AegisSight Logo" css/: "Stylesheets (Dark Theme)" js/: - app.js: "Hauptlogik, Login, Tab-Switching, Dashboard-Render" + app.js: "Hauptlogik, Login, Tab-Switching, Dashboard-Render, ThemeManager (Dark/Light, localStorage portal_theme)" + a11y.js: "Barrierefreiheits-Panel (Kontrast, Focus, Schrift, Animationen). IDENTISCHE Datei wie im Monitor-Repo, bei Aenderungen dort mitziehen" sources.js: "Grundquellen + Kundenquellen Management" source-health.js: "Quellen-Health & KI-Vorschläge" audit.js: "Audit-Log Tab" diff --git a/src/static/css/style.css b/src/static/css/style.css index ecf1ca6..40badd4 100644 --- a/src/static/css/style.css +++ b/src/static/css/style.css @@ -1,32 +1,63 @@ -/* AegisSight Dark Theme - Verwaltungsportal */ +/* AegisSight Design System - Verwaltungsportal (Navy/Gold, Dark = Standard, Light per Umschalter) */ :root { - --bg-primary: #0f172a; - --bg-secondary: #1e293b; - --bg-tertiary: #334155; - --text-primary: #e2e8f0; - --text-secondary: #94a3b8; - --text-muted: #64748b; - --accent: #f0b429; - --accent-hover: #d4a017; - --success: #22c55e; - --warning: #f59e0b; - --danger: #ef4444; - --info: #3b82f6; - --border: #334155; - --radius: 8px; - --radius-lg: 12px; + --bg-primary: #0B1121; + --bg-secondary: #151D2E; + --bg-tertiary: #1A2440; + --bg-hover: #1A2440; + --text-primary: #E8ECF4; + --text-secondary: #8896AB; + --text-muted: #95A3B8; + --accent: #C8A851; + --accent-hover: #B5923E; + --success: #10B981; + --warning: #F59E0B; + --danger: #EF4444; + --info: #7C8DB5; + --border: #1E2D45; + --radius: 6px; + --radius-lg: 8px; + --shadow-lg: 0 12px 40px rgba(0, 0, 0, 0.5); + --font-title: 'Poppins', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; + --font-body: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Arial, sans-serif; + /* Das Navy-Logo liegt im Dark-Theme auf einer hellen Plakette */ + --logo-plaque: rgba(232, 236, 240, 0.9); +} + +/* Light-Theme. Akzent wie im Monitor auf das dunklere Gold abgesenkt, + #C8A851 schafft auf hellem Grund den WCAG-Kontrast nicht. */ +[data-theme="light"] { + --bg-primary: #F4F5F7; + --bg-secondary: #FFFFFF; + --bg-tertiary: #E8EBF0; + --bg-hover: #E8EBF0; + --text-primary: #1A202C; + --text-secondary: #4A5568; + --text-muted: #A0AEC0; + --accent: #96791A; + --accent-hover: #7D6516; + --success: #059669; + --warning: #D97706; + --danger: #DC2626; + --info: #4A5568; + --border: #E2E8F0; + --shadow-lg: 0 8px 32px rgba(0, 0, 0, 0.12); + --logo-plaque: transparent; } * { margin: 0; padding: 0; box-sizing: border-box; } body { - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Inter, sans-serif; + font-family: var(--font-body); background: var(--bg-primary); color: var(--text-primary); line-height: 1.6; min-height: 100vh; } +h1, h2, h3, .logo, .stat-value, .token-stat-value { + font-family: var(--font-title); +} + /* --- Login Page --- */ .login-page { display: flex; @@ -143,7 +174,7 @@ input:focus, select:focus, textarea:focus { color: var(--text-primary); } .btn-secondary:hover:not(:disabled) { - background: #475569; + background: var(--border); } .btn-danger { @@ -189,6 +220,9 @@ input:focus, select:focus, textarea:focus { } .app-header .logo { + display: flex; + align-items: center; + gap: 10px; color: var(--accent); font-size: 18px; font-weight: 700; @@ -198,9 +232,19 @@ input:focus, select:focus, textarea:focus { color: var(--text-secondary); font-weight: 400; font-size: 13px; - margin-left: 8px; + margin-left: 2px; } +/* Navy-Logo bleibt auch im Dark-Theme, liegt dort auf heller Plakette */ +.logo-plaque { + display: flex; + align-items: center; + background: var(--logo-plaque); + border-radius: 8px; + padding: 3px 6px; +} +.logo-plaque img { height: 24px; display: block; } + .header-right { display: flex; align-items: center; @@ -237,7 +281,11 @@ input:focus, select:focus, textarea:focus { border-bottom: 2px solid transparent; margin-bottom: -1px; transition: all 0.2s; + display: inline-flex; + align-items: center; + gap: 7px; } +.nav-tab svg { flex-shrink: 0; } .nav-tab:hover { color: var(--text-primary); @@ -1121,3 +1169,224 @@ input[type="date"].filter-select { padding: 6px 10px; } border-color: var(--accent); } + +/* === Theme-Umschalter (goldener Schiebeschalter, wie im Monitor) === */ +.theme-switch { + display: flex; + align-items: center; + gap: 6px; + cursor: pointer; + user-select: none; + -webkit-user-select: none; +} +.theme-switch-icon { + font-size: 14px; + line-height: 1; + opacity: 0.4; + transition: opacity 0.3s; +} +.theme-switch.dark .theme-switch-moon, +.theme-switch.light .theme-switch-sun { + opacity: 1; +} +.theme-switch-track { + position: relative; + width: 40px; + height: 22px; + border-radius: 11px; + background: var(--bg-tertiary); + border: 1px solid var(--border); + transition: background 0.3s, border-color 0.3s; + flex-shrink: 0; +} +.theme-switch-knob { + position: absolute; + top: 2px; + left: 2px; + width: 16px; + height: 16px; + border-radius: 50%; + background: var(--accent); + box-shadow: 0 0 8px rgba(200, 168, 81, 0.3); + transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1), box-shadow 0.3s; +} +.theme-switch.dark .theme-switch-knob { transform: translateX(18px); } +.theme-switch.light .theme-switch-knob { transform: translateX(0); } +.theme-switch:hover .theme-switch-track { border-color: var(--accent); } +.theme-switch:hover .theme-switch-knob { box-shadow: 0 0 12px rgba(200, 168, 81, 0.5); } + +/* === Kleine Schalter-Optik (fuer das Barrierefreiheits-Panel) === */ +.toggle-switch { + position: relative; + display: inline-block; + width: 34px; + height: 18px; + border-radius: 9px; + background: var(--bg-tertiary); + border: 1px solid var(--border); + transition: background 0.2s ease; +} +.toggle-switch::after { + content: ""; + position: absolute; + top: 2px; + left: 2px; + width: 12px; + height: 12px; + border-radius: 50%; + background: var(--text-secondary); + transition: transform 0.2s ease, background 0.2s ease; +} + +/* === Barrierefreiheits-Panel (a11y.js haengt sich in .header-right ein) === */ +.a11y-center { position: relative; } +.a11y-btn { + background: none; + border: none; + color: var(--text-secondary); + cursor: pointer; + padding: 6px 8px; + border-radius: var(--radius); + display: flex; + align-items: center; + justify-content: center; + transition: color 0.2s ease, background 0.2s ease; + width: 36px; + height: 36px; +} +.a11y-btn:hover { color: var(--accent); background: var(--bg-hover); } +.a11y-panel { + position: absolute; + top: calc(100% + 8px); + right: 0; + width: 240px; + background: var(--bg-secondary); + border: 1px solid var(--border); + border-radius: var(--radius-lg); + box-shadow: var(--shadow-lg); + z-index: 200; + padding: 16px; +} +.a11y-panel-title { + font-size: 12px; + font-weight: 600; + color: var(--text-secondary); + letter-spacing: 0.5px; + margin-bottom: 12px; +} +.a11y-option { + display: flex; + align-items: center; + gap: 8px; + padding: 6px 0; + cursor: pointer; + font-size: 13px; + color: var(--text-primary); + user-select: none; +} +.a11y-option input[type="checkbox"] { + position: absolute; + width: 1px; + height: 1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border: 0; +} +.a11y-option .toggle-switch { flex-shrink: 0; } +.a11y-option input:focus-visible + .toggle-switch { + outline: 2px solid var(--accent); + outline-offset: 2px; +} +.a11y-option input:checked + .toggle-switch { background: var(--accent); } +.a11y-option input:checked + .toggle-switch::after { + transform: translateX(16px); + background: var(--bg-primary); +} + +/* === Barrierefreiheits-Modi === */ +[data-a11y-contrast="true"] { + --text-muted: #B0BDD0; + --border: #3A4A66; +} +[data-a11y-contrast="true"] .btn-primary { color: #1A1A1A; } +[data-a11y-contrast="true"][data-theme="light"] { + --accent: #6B5714; + --accent-hover: #5A4A11; + --text-muted: #718096; + --border: #94A3B8; +} +[data-a11y-focus="true"] a:focus-visible, +[data-a11y-focus="true"] button:focus-visible, +[data-a11y-focus="true"] input:focus-visible, +[data-a11y-focus="true"] select:focus-visible, +[data-a11y-focus="true"] textarea:focus-visible, +[data-a11y-focus="true"] [tabindex]:focus-visible, +[data-a11y-focus="true"] [role="button"]:focus-visible { + outline: 3px solid var(--accent) !important; + outline-offset: 2px !important; + box-shadow: 0 0 0 4px rgba(200, 168, 81, 0.3) !important; +} +[data-a11y-fontsize="true"] body { zoom: 1.15; } +[data-a11y-motion="true"] *, +[data-a11y-motion="true"] *::before, +[data-a11y-motion="true"] *::after { + animation-duration: 0.01ms !important; + animation-iteration-count: 1 !important; + transition-duration: 0.01ms !important; + scroll-behavior: auto !important; +} + +/* === Icon-Ausrichtung in Knoepfen === */ +.btn { display: inline-flex; align-items: center; justify-content: center; gap: 7px; } +.btn svg { flex-shrink: 0; } + +/* === Aufklappbarer Bereich (z.B. "Erweitert" im Verbrauchs-Formular) === */ +details.adv-section { grid-column: 1 / -1; border-top: 1px solid var(--border); padding-top: 10px; } +details.adv-section summary { + cursor: pointer; + color: var(--text-secondary); + font-size: 13px; + user-select: none; + display: flex; + align-items: center; + gap: 6px; +} +details.adv-section summary:hover { color: var(--text-primary); } +details.adv-section[open] summary { margin-bottom: 10px; } +details.adv-section .adv-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; } +details.adv-section .adv-hint { grid-column: 1 / -1; font-size: 12px; color: var(--text-muted); margin: 0; } + +/* === Light-Theme: dunklere Text-Farben fuer Badges/Status === + (Die Dark-Pastelltoene sind auf hellem Grund unlesbar. Automatisch + abgeleitete Gegenstuecke, je Original-Farbton eine dunkle Variante.) */ +[data-theme="light"] .error-msg { color: #B91C1C; } +[data-theme="light"] .btn-danger { color: #B91C1C; } +[data-theme="light"] .btn-success { color: #047857; } +[data-theme="light"] .badge-active { color: #047857; } +[data-theme="light"] .badge-inactive { color: #B91C1C; } +[data-theme="light"] .badge-trial { color: #1D4ED8; } +[data-theme="light"] .badge-annual { color: #7E22CE; } +[data-theme="light"] .badge-permanent { color: #B45309; } +[data-theme="light"] .badge-expired { color: #B91C1C; } +[data-theme="light"] .badge-revoked { color: #475569; } +[data-theme="light"] .badge-none { color: #475569; } +[data-theme="light"] .activity-icon.org { color: #1D4ED8; } +[data-theme="light"] .activity-icon.user { color: #047857; } +[data-theme="light"] /* --- Health & Suggestion Badges --- */ +.badge-health-error { color: #B91C1C; } +[data-theme="light"] .badge-health-warning { color: #B45309; } +[data-theme="light"] .badge-health-ok { color: #047857; } +[data-theme="light"] .badge-suggestion-add_source { color: #1D4ED8; } +[data-theme="light"] .badge-suggestion-deactivate_source { color: #B45309; } +[data-theme="light"] .badge-suggestion-remove_source { color: #B91C1C; } +[data-theme="light"] .badge-suggestion-fix_url { color: #7E22CE; } +[data-theme="light"] .badge-priority-high { color: #B91C1C; } +[data-theme="light"] .badge-priority-medium { color: #B45309; } +[data-theme="light"] .badge-priority-low { color: #475569; } +[data-theme="light"] .sources-stat-item { color: #475569; } +[data-theme="light"] .health-badge-unknown { color: #475569; } +[data-theme="light"] .audit-entry-meta { color: #475569; } +[data-theme="light"] .audit-entry-detail summary { color: #475569; } +[data-theme="light"] /* === Verwendungs-Sicht (Phase 6) === */ +.activity-cell { color: #475569; } diff --git a/src/static/dashboard.html b/src/static/dashboard.html index 302a2ac..2dfa3b7 100644 --- a/src/static/dashboard.html +++ b/src/static/dashboard.html @@ -6,32 +6,63 @@ AegisSight Monitor-Verwaltung - + +
- +
+
+ ☀︎ +
+
+
+ +
- +
- + @@ -93,7 +124,7 @@
- +
@@ -123,14 +154,14 @@ - +
- +
@@ -155,7 +186,7 @@
- +
@@ -211,34 +242,46 @@
+ +

Kundensicht (Credits)

-
Verbrauchte Credits
+
Verbrauchte Credits (Periode)
-
Verbleibend
-
-
-
Budget (USD)
-
-
-
-
-
Kosten (USD)
-
-
-
-
- Budget-Auslastung + Kontingent-Auslastung (laufende Periode) 0%
+

+ + Zur Einordnung. Ein Live-Lauf kostet 45 Credits, das Anlegen einer Recherche 120 (drei Durchläufe), jede Vertiefung 40, Chat und Beschreibungs-Assistent je 1 Credit. + Verbrauchsrechner öffnen +

+ + +

Interne Kosten (Einkauf, USD)

+
+
+
API-Kosten aktueller Monat
+
-
+
+
+
Budget-Limit (USD, Altmodus)
+
-
+
+
+

Monatlicher Verlauf

@@ -255,11 +298,11 @@
-

Budget bearbeiten

+

Credits-Kontingent bearbeiten

-
+
-
- - -
-
- - -
-
- - -
+
+ + + Erweitert (Altmodus und Korrektur) + +

+ Die beiden USD-Felder gehören zum alten Abrechnungsmodus (BILLING_MODE=actual) + und haben im heutigen Pauschalmodus keine Wirkung auf den Kunden. Das + Korrektur-Feld überschreibt den Verbrauch der laufenden Periode direkt, + nur für bewusste Eingriffe gedacht. +

+
+
+ + +
+
+ + +
+
+ + +
+
+
- +
@@ -786,6 +846,30 @@
+ + + - + + diff --git a/src/static/index.html b/src/static/index.html index 97272b2..37a334f 100644 --- a/src/static/index.html +++ b/src/static/index.html @@ -7,12 +7,14 @@ AegisSight Monitor-Verwaltung - Anmeldung - + + @@ -54,13 +56,13 @@