diff --git a/drohnenfuehrer/frontend/index.html b/drohnenfuehrer/frontend/index.html index 76ad2b5..d2fa19d 100644 --- a/drohnenfuehrer/frontend/index.html +++ b/drohnenfuehrer/frontend/index.html @@ -5,7 +5,7 @@ - + diff --git a/drohnenfuehrer/frontend/public/logo-fallingbostel.png b/drohnenfuehrer/frontend/public/logo-fallingbostel.png deleted file mode 100644 index bf3e426..0000000 Binary files a/drohnenfuehrer/frontend/public/logo-fallingbostel.png and /dev/null differ diff --git a/drohnenfuehrer/frontend/public/logo-ljn.png b/drohnenfuehrer/frontend/public/logo-ljn.png deleted file mode 100644 index a1a6ce9..0000000 Binary files a/drohnenfuehrer/frontend/public/logo-ljn.png and /dev/null differ diff --git a/drohnenfuehrer/frontend/public/manifest.json b/drohnenfuehrer/frontend/public/manifest.json index 3ea9347..3cf8f09 100644 --- a/drohnenfuehrer/frontend/public/manifest.json +++ b/drohnenfuehrer/frontend/public/manifest.json @@ -19,7 +19,7 @@ "scope": "/drohnenfuehrer/", "display": "standalone", "orientation": "portrait", - "theme_color": "#2d6a2d", - "background_color": "#ffffff", + "theme_color": "#1a3d1a", + "background_color": "#e8e8e2", "description": "Drohnenführer Heidekreis – Übersicht der Drohnenführer" } diff --git a/drohnenfuehrer/frontend/public/offline.html b/drohnenfuehrer/frontend/public/offline.html index c069be4..b1c4d55 100644 --- a/drohnenfuehrer/frontend/public/offline.html +++ b/drohnenfuehrer/frontend/public/offline.html @@ -1,16 +1,93 @@ - + - - - Offline - Drohnenführer - + + + + Offline – Jagd Apps Heidekreis + -

Du bist offline

-

Die App ist derzeit nicht verfügbar. Bitte überprüfe deine Internetverbindung.

+
+ +

Keine Verbindung

+

+ Im Funkloch sind die zuletzt geladenen Daten nicht verfügbar. + Sobald wieder Empfang besteht, lädt die Seite normal. +

+ +
- \ No newline at end of file + diff --git a/drohnenfuehrer/frontend/src/App.css b/drohnenfuehrer/frontend/src/App.css index b8f3ffe..b3a77b8 100644 --- a/drohnenfuehrer/frontend/src/App.css +++ b/drohnenfuehrer/frontend/src/App.css @@ -2,43 +2,203 @@ box-sizing: border-box; } +/* ────────────────────────────────────────────────────────────────────────── + Design-Tokens — einzige Farbquelle der App. + Palette und Formensprache folgen dem Portal (portal/index.html), damit der + Wechsel vom Portal in eine App nicht wie ein Produktwechsel wirkt. + Schriftmodell wie im Portal: Serif für die Marken-/Überschriftenebene, + Sans für funktionale UI-Texte (auf kleinen Displays besser lesbar). + + Alle Textpaare erfüllen WCAG AA (>= 4.5:1), funktionale Rahmen >= 3.0:1 — + in beiden Varianten nachgerechnet. + ────────────────────────────────────────────────────────────────────────── */ :root { - --color-primary: #2e8b2e; - --color-primary-dark: #1e6b1e; - --color-primary-accent: #8B0D12; - --color-secondary: #6c757d; - --color-secondary-dark: #5a6268; - --color-success: #28a745; - --color-success-dark: #218838; - --color-danger: #dc3545; - --color-danger-dark: #c82333; - --color-bg: #f5f5f0; - --color-surface: #ffffff; + --font-display: Georgia, 'Times New Roman', serif; + --font-ui: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', + 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif; + --font-mono: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', monospace; + + /* Flächen */ + --color-bg: #e8e8e2; + --color-surface: #f4f4ee; + --color-surface-alt: #dedcd2; + --color-muted-bg: #dedcd2; + + /* Text */ --color-text: #1a1a1a; - --color-text-muted: #555; - --color-border: #b8d4b8; - --color-border-strong: #88b888; - --color-focus: rgba(46, 139, 46, 0.2); - --color-muted-bg: #f5f5f0; - --shadow-sm: 0 2px 4px rgba(0, 0, 0, 0.1); - --shadow-md: 0 4px 8px rgba(0, 0, 0, 0.2); - --radius-sm: 4px; - --radius-md: 8px; - --radius-pill: 12px; + --color-text-muted: #55554c; + + /* Rahmen: -border ist dekorativ (Trennlinien, Karten), + -border-strong begrenzt Bedienelemente und erfüllt die 3:1-Anforderung. */ + --color-border: #c9c9b8; + --color-border-strong: #7d7d68; + + /* Aktionsfarben – jeweils mit der zugehörigen Textfarbe, damit die + Dunkelvariante nicht auf weißem Text auf hellem Grund landet. */ + --color-primary: #2d5a2d; + --color-primary-dark: #1a3d1a; + --color-on-primary: #ffffff; + --color-secondary: #5c5c50; + --color-secondary-dark: #46463c; + --color-on-secondary: #ffffff; + --color-success: #1f6b34; + --color-success-dark: #175128; + --color-on-success: #ffffff; + --color-danger: #a32020; + --color-danger-dark: #821919; + --color-on-danger: #ffffff; + --color-warning: #7a5200; + --color-on-warning: #ffffff; + --color-accent: #8b0d12; + --color-on-accent: #ffffff; + /* Altname, wird von RulesDisplay noch benutzt */ + --color-primary-accent: #8b0d12; + + /* Getönte Status-Flächen (Meldungen, Badges, Zustands-Karten). + Der Block wird durch seine Füllung erkannt, der Rahmen ist Zierde. */ + --color-success-bg: #dfeedd; + --color-success-border: #a9cba4; + --color-success-text: #1a4a24; + --color-danger-bg: #f6e0e0; + --color-danger-border: #d9a9a9; + --color-danger-text: #7d1a1a; + --color-warning-bg: #f7edd4; + --color-warning-border: #d9c48a; + --color-warning-text: #5c3d00; + --color-info: #24608f; + --color-info-dark: #1b4a6e; + --color-on-info: #ffffff; + --color-info-bg: #dde8f1; + --color-info-border: #a5bfd4; + --color-info-text: #14405f; + + /* Als RGB-Tripel fuer rgba()-Anwendungen (Puls-Animation im Admin-Panel) */ + --color-primary-rgb: 45, 90, 45; + + --color-focus: rgba(45, 90, 45, 0.35); + + --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.15); + --shadow-md: 0 2px 6px rgba(0, 0, 0, 0.2); + + /* Kantige Ecken wie im Portal */ + --radius-sm: 2px; + --radius-md: 2px; + --radius-pill: 2px; + --space-1: 0.5rem; --space-2: 1rem; --space-3: 1.5rem; --space-4: 2rem; + + /* Mindestgröße für Bedienelemente auf Touchgeräten */ + --touch-target: 44px; } +/* Nachtvariante. Nachsuchen laufen in der Dämmerung und nachts — ein weißes + Vollbild blendet dann und kostet die Dunkeladaption der Augen. Warme, sehr + dunkle Grüntöne statt reinem Schwarz. */ +@media (prefers-color-scheme: dark) { + :root { + --color-bg: #14180f; + --color-surface: #1e241a; + --color-surface-alt: #2a3124; + --color-muted-bg: #2a3124; + + --color-text: #e9e7dd; + --color-text-muted: #a6a698; + + --color-border: #333b28; + --color-border-strong: #758566; + + --color-primary: #7fb36f; + --color-primary-dark: #9ccb8c; + --color-on-primary: #10140c; + --color-secondary: #8d8d80; + --color-secondary-dark: #a3a396; + --color-on-secondary: #10140c; + --color-success: #79c48c; + --color-success-dark: #93d3a3; + --color-on-success: #10140c; + --color-danger: #ea8b8b; + --color-danger-dark: #f2a5a5; + --color-on-danger: #10140c; + --color-warning: #d6b25f; + --color-on-warning: #10140c; + --color-accent: #e88a8f; + --color-on-accent: #10140c; + --color-primary-accent: #e88a8f; + + --color-success-bg: #1d2c20; + --color-success-border: #3d5c43; + --color-success-text: #93d3a3; + --color-danger-bg: #33201f; + --color-danger-border: #6b4040; + --color-danger-text: #f2a5a5; + --color-warning-bg: #322a15; + --color-warning-border: #63552c; + --color-warning-text: #e0c37c; + --color-info: #7fb0dc; + --color-info-dark: #9cc4e8; + --color-on-info: #10140c; + --color-info-bg: #1a2530; + --color-info-border: #3d5468; + --color-info-text: #9cc4e8; + + --color-primary-rgb: 127, 179, 111; + --color-focus: rgba(127, 179, 111, 0.45); + + --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.5); + --shadow-md: 0 2px 6px rgba(0, 0, 0, 0.6); + } +} + +body { + margin: 0; + font-family: var(--font-ui); + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + background: var(--color-bg); + color: var(--color-text); + /* Damit auch vom Browser gestellte Bedienelemente (Bildlaufleisten, + Datumsauswahl, Autofill) der gewählten Ansicht folgen. */ + color-scheme: light dark; +} + +/* Formularfelder brauchen ausdrücklich Farben: ohne sie nimmt der Browser + seinen Standard (weiß) — in der Nachtansicht leuchtet dann jedes Eingabefeld. */ +input:not([type='checkbox']):not([type='radio']):not([type='range']):not([type='file']), +select, +textarea { + background: var(--color-surface); + color: var(--color-text); +} + +input::placeholder, +textarea::placeholder { + color: var(--color-text-muted); + opacity: 1; +} + +h1, h2, h3 { + font-family: var(--font-display); +} + +code { + font-family: var(--font-mono); +} + +/* ── Bedienelemente ─────────────────────────────────────────────────────── */ + .btn { display: inline-flex; align-items: center; justify-content: center; gap: var(--space-1); + min-height: var(--touch-target); padding: 0.5rem 1rem; border: none; border-radius: var(--radius-sm); + font-family: var(--font-ui); font-size: 0.9rem; font-weight: 600; cursor: pointer; @@ -46,15 +206,24 @@ } .btn:disabled { - background: var(--color-border); + background: var(--color-surface-alt); color: var(--color-text-muted); cursor: not-allowed; box-shadow: none; } +/* Sichtbarer Tastaturfokus. Ohne das war die Tastaturbedienung unsichtbar — + Buttons hatten nur einen :hover-Stil. */ +.btn:focus-visible, +.nav-button:focus-visible, +a:focus-visible { + outline: 2px solid var(--color-primary); + outline-offset: 2px; +} + .btn-primary { background: var(--color-primary); - color: white; + color: var(--color-on-primary); } .btn-primary:hover:not(:disabled) { @@ -64,7 +233,7 @@ .btn-secondary { background: var(--color-secondary); - color: white; + color: var(--color-on-secondary); } .btn-secondary:hover:not(:disabled) { @@ -72,19 +241,9 @@ transform: translateY(-1px); } -.btn-success { - background: var(--color-success); - color: white; -} - -.btn-success:hover:not(:disabled) { - background: var(--color-success-dark); - transform: translateY(-1px); -} - .btn-danger { background: var(--color-danger); - color: white; + color: var(--color-on-danger); } .btn-danger:hover:not(:disabled) { @@ -96,9 +255,13 @@ .select, .textarea { width: 100%; + min-height: var(--touch-target); padding: 0.75rem 1rem; + background: var(--color-surface); + color: var(--color-text); border: 1px solid var(--color-border-strong); border-radius: var(--radius-sm); + font-family: var(--font-ui); font-size: 1rem; box-sizing: border-box; } @@ -111,33 +274,19 @@ box-shadow: 0 0 0 3px var(--color-focus); } -.panel { - background: var(--color-surface); - border: 1px solid var(--color-border); - border-radius: var(--radius-md); - padding: var(--space-3); - box-shadow: var(--shadow-sm); -} - .panel-title { margin: 0 0 var(--space-2); + font-family: var(--font-display); font-size: 1.1rem; color: var(--color-text); } -body { - margin: 0; - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', - 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', - sans-serif; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - background: var(--color-bg); - color: var(--color-text); -} +/* ── Grundgerüst ────────────────────────────────────────────────────────── */ .App { - min-height: 100vh; + /* dvh statt vh: mit ein- und ausblendender Adressleiste auf Mobilgeräten + entsteht mit vh sonst Überlauf. */ + min-height: 100dvh; display: flex; flex-direction: column; } @@ -151,44 +300,26 @@ body { display: flex; justify-content: center; align-items: center; - min-height: 100vh; + min-height: 100dvh; font-size: 1.2rem; color: var(--color-text-muted); } -.login-prompt { - position: fixed; - bottom: 20px; - right: 20px; -} - -.login-button-header { - padding: 0.75rem 1.5rem; - background: var(--color-primary); - color: white; - border: none; - border-radius: 4px; - font-size: 1rem; - font-weight: 600; - cursor: pointer; - box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2); - transition: all 0.2s; -} - -.login-button-header:hover { - background: var(--color-primary-dark); - transform: translateY(-2px); - box-shadow: 0 6px 12px rgba(0, 0, 0, 0.3); -} - -@media (max-width: 768px) { - .login-prompt { - bottom: 10px; - right: 10px; +/* Wer Bewegung reduziert haben möchte, bekommt keine Animationen. */ +@media (prefers-reduced-motion: reduce) { + *, + *::before, + *::after { + animation-duration: 0.01ms !important; + animation-iteration-count: 1 !important; + transition-duration: 0.01ms !important; + scroll-behavior: auto !important; } - .login-button-header { - padding: 0.6rem 1.2rem; - font-size: 0.9rem; + .btn:hover:not(:disabled), + .btn-primary:hover:not(:disabled), + .btn-secondary:hover:not(:disabled), + .btn-danger:hover:not(:disabled) { + transform: none; } } diff --git a/drohnenfuehrer/frontend/src/components/admin/AdminPanel.css b/drohnenfuehrer/frontend/src/components/admin/AdminPanel.css index 12ce644..16e6fa0 100644 --- a/drohnenfuehrer/frontend/src/components/admin/AdminPanel.css +++ b/drohnenfuehrer/frontend/src/components/admin/AdminPanel.css @@ -25,7 +25,7 @@ .tab-button.active { background: var(--color-primary); - color: white; + color: var(--color-on-primary); } .settings-panel { @@ -59,9 +59,9 @@ .unsaved-badge { display: inline-block; - background: #fff3cd; - color: #856404; - border: 1px solid #ffc107; + background: var(--color-warning-bg); + color: var(--color-warning-text); + border: 1px solid var(--color-warning); border-radius: var(--radius-sm); padding: 0.2rem 0.6rem; font-size: 0.8rem; @@ -102,7 +102,7 @@ display: flex; align-items: center; gap: 0.5rem; - background: var(--color-muted-bg, #f5f5f0); + background: var(--color-muted-bg, var(--color-surface-alt)); border: none; padding: 0.75rem var(--space-2); cursor: pointer; @@ -111,7 +111,7 @@ } .settings-section-header:hover { - background: var(--color-focus, #eef2e6); + background: var(--color-focus, var(--color-success-bg)); } .settings-section-header .settings-heading { @@ -193,7 +193,7 @@ .skeleton-line { height: 1rem; border-radius: var(--radius-sm); - background: linear-gradient(90deg, #e8e8e4 25%, #f0f0ec 50%, #e8e8e4 75%); + background: linear-gradient(90deg, var(--color-surface-alt) 25%, var(--color-surface-alt) 50%, var(--color-surface-alt) 75%); background-size: 200% 100%; animation: skeleton-shimmer 1.4s infinite; margin-bottom: 0.75rem; @@ -323,17 +323,17 @@ .notification.success { background: var(--color-success); - color: white; + color: var(--color-on-success); } .notification.error { background: var(--color-danger); - color: white; + color: var(--color-on-danger); } .notification.warning { - background: #e67e00; - color: white; + background: var(--color-warning); + color: var(--color-on-warning); } @keyframes slideIn { diff --git a/drohnenfuehrer/frontend/src/components/admin/AuditLogs.css b/drohnenfuehrer/frontend/src/components/admin/AuditLogs.css index 433cfc4..0f2d27a 100644 --- a/drohnenfuehrer/frontend/src/components/admin/AuditLogs.css +++ b/drohnenfuehrer/frontend/src/components/admin/AuditLogs.css @@ -13,8 +13,8 @@ gap: 12px; flex-wrap: wrap; } -.audit-header h2 { margin: 0 0 4px 0; color: #333; font-size: 26px; } -.audit-description { margin: 0; color: #666; font-size: 13px; } +.audit-header h2 { margin: 0 0 4px 0; color: var(--color-text); font-size: 26px; } +.audit-description { margin: 0; color: var(--color-text-muted); font-size: 13px; } .audit-header-actions { display: flex; @@ -32,24 +32,24 @@ } .btn-stats-toggle { padding: 6px 14px; - background: #f0f4f8; - border: 1px solid #d0d7de; + background: var(--color-surface-alt); + border: 1px solid var(--color-border); border-radius: 6px; cursor: pointer; font-size: 13px; - color: #444; + color: var(--color-text-muted); } -.btn-stats-toggle:hover { background: #e2e8f0; } +.btn-stats-toggle:hover { background: var(--color-surface-alt); } .stats-days-select { font-size: 13px; } .audit-stats { - background: #f8fafc; - border: 1px solid #e2e8f0; + background: var(--color-surface-alt); + border: 1px solid var(--color-border); border-radius: 10px; padding: 16px; margin-bottom: 16px; } -.stats-loading { color: #888; font-size: 13px; padding: 8px 0; } +.stats-loading { color: var(--color-text-muted); font-size: 13px; padding: 8px 0; } .stats-row { display: flex; @@ -60,18 +60,18 @@ .stat-card { flex: 1; min-width: 100px; - background: white; + background: var(--color-surface); border-radius: 8px; padding: 12px 16px; text-align: center; - border: 1px solid #e2e8f0; + border: 1px solid var(--color-border); } .stat-number { font-size: 28px; font-weight: 700; line-height: 1; } -.stat-label { font-size: 11px; color: #666; margin-top: 4px; text-transform: uppercase; letter-spacing: 0.5px; } -.stat-total .stat-number { color: #1976d2; } -.stat-failed .stat-number { color: #c62828; } -.stat-success .stat-number { color: #2e7d32; } -.stat-period .stat-number { color: #555; font-size: 20px; } +.stat-label { font-size: 11px; color: var(--color-text-muted); margin-top: 4px; text-transform: uppercase; letter-spacing: 0.5px; } +.stat-total .stat-number { color: var(--color-info-text); } +.stat-failed .stat-number { color: var(--color-danger-text); } +.stat-success .stat-number { color: var(--color-success-text); } +.stat-period .stat-number { color: var(--color-text-muted); font-size: 20px; } .stats-details { display: flex; @@ -79,7 +79,7 @@ flex-wrap: wrap; } .stats-col { flex: 1; min-width: 180px; } -.stats-col h4 { margin: 0 0 8px 0; font-size: 12px; text-transform: uppercase; color: #888; letter-spacing: 0.5px; } +.stats-col h4 { margin: 0 0 8px 0; font-size: 12px; text-transform: uppercase; color: var(--color-text-muted); letter-spacing: 0.5px; } .stat-bar-row { display: flex; @@ -88,8 +88,8 @@ gap: 8px; margin-bottom: 5px; } -.stat-bar-label { font-size: 13px; color: #444; } -.stat-bar-count { font-size: 13px; font-weight: 600; color: #333; flex-shrink: 0; } +.stat-bar-label { font-size: 13px; color: var(--color-text-muted); } +.stat-bar-count { font-size: 13px; font-weight: 600; color: var(--color-text); flex-shrink: 0; } /* Mini bar chart */ .stats-chart-col { flex: 2; min-width: 220px; } @@ -98,7 +98,7 @@ align-items: flex-end; gap: 3px; height: 80px; - background: #f0f4f8; + background: var(--color-surface-alt); border-radius: 6px; padding: 6px 6px 0; } @@ -110,7 +110,7 @@ } .chart-bar { width: 100%; - background: #1976d2; + background: var(--color-info); border-radius: 2px 2px 0 0; position: relative; min-height: 4px; @@ -121,7 +121,7 @@ bottom: 0; left: 0; width: 100%; - background: #e53935; + background: var(--color-danger); } /* ── Filters ─────────────────────────────────────────────────────── */ @@ -134,52 +134,52 @@ } .filter-select { padding: 8px 12px; - border: 1.5px solid #d0d7de; + border: 1.5px solid var(--color-border); border-radius: 6px; font-size: 13px; - background: white; + background: var(--color-surface); cursor: pointer; } -.filter-select:focus { outline: none; border-color: #1976d2; } +.filter-select:focus { outline: none; border-color: var(--color-primary); } .filter-input { padding: 8px 12px; - border: 1.5px solid #d0d7de; + border: 1.5px solid var(--color-border); border-radius: 6px; font-size: 13px; - background: white; + background: var(--color-surface); min-width: 140px; } -.filter-input:focus { outline: none; border-color: #1976d2; } +.filter-input:focus { outline: none; border-color: var(--color-primary); } .filter-date { min-width: 130px; } .btn-refresh { padding: 8px 14px; - background: #1976d2; - color: white; + background: var(--color-info); + color: var(--color-on-info); border: none; border-radius: 6px; cursor: pointer; font-size: 13px; font-weight: 500; } -.btn-refresh:hover:not(:disabled) { background: #1565c0; } -.btn-refresh:disabled { background: #bdbdbd; cursor: not-allowed; } +.btn-refresh:hover:not(:disabled) { background: var(--color-info-dark); } +.btn-refresh:disabled { background: var(--color-surface-alt); color: var(--color-text-muted); cursor: not-allowed; } .btn-reset { padding: 8px 12px; - background: white; - color: #666; - border: 1.5px solid #d0d7de; + background: var(--color-surface); + color: var(--color-text-muted); + border: 1.5px solid var(--color-border); border-radius: 6px; cursor: pointer; font-size: 13px; } -.btn-reset:hover { background: #f5f5f5; } +.btn-reset:hover { background: var(--color-surface-alt); } .btn-export { padding: 8px 16px; - background: #2e7d32; - color: white; + background: var(--color-success); + color: var(--color-on-success); border: none; border-radius: 6px; cursor: pointer; @@ -187,15 +187,15 @@ font-weight: 500; white-space: nowrap; } -.btn-export:hover:not(:disabled) { background: #1b5e20; } -.btn-export:disabled { background: #bdbdbd; cursor: not-allowed; } +.btn-export:hover:not(:disabled) { background: var(--color-success-dark); } +.btn-export:disabled { background: var(--color-surface-alt); color: var(--color-text-muted); cursor: not-allowed; } .auto-refresh-toggle { display: flex; align-items: center; gap: 6px; font-size: 13px; - color: #555; + color: var(--color-text-muted); cursor: pointer; white-space: nowrap; } @@ -206,7 +206,7 @@ justify-content: space-between; align-items: center; font-size: 13px; - color: #666; + color: var(--color-text-muted); margin-bottom: 10px; } .limit-select { padding: 4px 8px; font-size: 13px; } @@ -224,16 +224,16 @@ } .badge-create { background: #e8f5e9; color: #2e7d32; } .badge-update { background: #e3f2fd; color: #1565c0; } -.badge-delete { background: #ffebee; color: #c62828; } -.badge-restore { background: #fff3e0; color: #e65100; } +.badge-delete { background: #ffebee; color: var(--color-danger-text); } +.badge-restore { background: #fff3e0; color: #a83a00; } .badge-login { background: #f3e5f5; color: #6a1b9a; } .badge-logout { background: #fce4ec; color: #880e4f; } .badge-login-failed { background: #ffcdd2; color: #b71c1c; font-weight: 700; } .badge-import { background: #e0f7fa; color: #00695c; } .badge-export { background: #e8f5e9; color: #1b5e20; } -.badge-bulk-update { background: #e8eaf6; color: #283593; } +.badge-bulk-update { background: var(--color-surface-alt); color: #283593; } .badge-bulk-delete { background: #fbe9e7; color: #bf360c; } -.badge-password { background: #fff8e1; color: #f57f17; } +.badge-password { background: #fff8e1; color: #9c4e00; } .badge-default { background: #f5f5f5; color: #616161; } .status-code { @@ -244,16 +244,16 @@ font-family: monospace; } .status-ok { background: #e8f5e9; color: #2e7d32; } -.status-redirect { background: #fff3e0; color: #e65100; } -.status-error { background: #ffebee; color: #c62828; } +.status-redirect { background: #fff3e0; color: #a83a00; } +.status-error { background: #ffebee; color: var(--color-danger-text); } .status-server-error { background: #f3e5f5; color: #6a1b9a; } .duration-badge { padding: 2px 8px; border-radius: 4px; font-size: 11px; - background: #f5f5f5; - color: #777; + background: var(--color-surface-alt); + color: var(--color-text-muted); font-family: monospace; } @@ -261,24 +261,24 @@ .audit-empty { text-align: center; padding: 40px; - background: #f9f9f9; + background: var(--color-surface-alt); border-radius: 8px; - color: #888; + color: var(--color-text-muted); } .audit-error { text-align: center; padding: 20px; } -.audit-error p { color: #d32f2f; margin: 0; } +.audit-error p { color: var(--color-danger-text); margin: 0; } .audit-list { display: flex; flex-direction: column; gap: 8px; } .audit-item { - background: white; - border: 1px solid #e0e0e0; + background: var(--color-surface); + border: 1px solid var(--color-border); border-radius: 8px; overflow: hidden; transition: box-shadow 0.15s; } .audit-item:hover { box-shadow: 0 2px 8px rgba(0,0,0,0.08); } -.audit-item-failed { border-left: 4px solid #e53935; } +.audit-item-failed { border-left: 4px solid var(--color-danger); } .audit-item-header { display: flex; @@ -286,18 +286,18 @@ gap: 8px; padding: 10px 14px; flex-wrap: wrap; - background: #fafafa; - border-bottom: 1px solid #f0f0f0; + background: var(--color-surface-alt); + border-bottom: 1px solid var(--color-border); } -.audit-time { margin-left: auto; color: #999; font-size: 12px; white-space: nowrap; } -.expand-toggle { color: #aaa; font-size: 11px; cursor: pointer; padding: 0 4px; } +.audit-time { margin-left: auto; color: var(--color-text-muted); font-size: 12px; white-space: nowrap; } +.expand-toggle { color: var(--color-text-muted); font-size: 11px; cursor: pointer; padding: 0 4px; } .audit-resource { padding: 3px 8px; - background: #f0f0f0; + background: var(--color-surface-alt); border-radius: 4px; font-size: 12px; - color: #555; + color: var(--color-text-muted); } .audit-item-body { @@ -308,16 +308,16 @@ font-size: 13px; align-items: center; } -.audit-admin { color: #333; } -.audit-resource-name { color: #555; } -.audit-ip { color: #999; font-family: monospace; font-size: 12px; } -.audit-failed-badge { color: #c62828; font-weight: 600; font-size: 12px; } +.audit-admin { color: var(--color-text); } +.audit-resource-name { color: var(--color-text-muted); } +.audit-ip { color: var(--color-text-muted); font-family: monospace; font-size: 12px; } +.audit-failed-badge { color: var(--color-danger-text); font-weight: 600; font-size: 12px; } /* ── Expanded detail ─────────────────────────────────────────────── */ .audit-item-detail { padding: 10px 14px 14px; - border-top: 1px dashed #e0e0e0; - background: #fefefe; + border-top: 1px dashed var(--color-border); + background: var(--color-surface); display: flex; flex-direction: column; gap: 8px; @@ -330,7 +330,7 @@ } .detail-label { font-weight: 600; - color: #888; + color: var(--color-text-muted); font-size: 11px; text-transform: uppercase; min-width: 70px; @@ -338,23 +338,23 @@ } .detail-row code { font-family: monospace; - background: #f0f0f0; + background: var(--color-surface-alt); padding: 2px 6px; border-radius: 3px; font-size: 12px; } .detail-ua-full { - color: #aaa; + color: var(--color-text-muted); cursor: help; font-size: 12px; } -.detail-error { color: #c62828; } -.detail-error .detail-label { color: #c62828; } +.detail-error { color: var(--color-danger-text); } +.detail-error .detail-label { color: var(--color-danger-text); } .meta-tag { display: inline-block; - background: #e8eaf6; - color: #283593; + background: var(--color-surface-alt); + color: var(--color-info-text); border-radius: 4px; padding: 2px 8px; font-size: 12px; @@ -370,17 +370,17 @@ margin-top: 6px; } .diff-table th { - background: #f0f0f0; + background: var(--color-surface-alt); padding: 5px 10px; text-align: left; font-size: 11px; text-transform: uppercase; - color: #666; - border: 1px solid #e0e0e0; + color: var(--color-text-muted); + border: 1px solid var(--color-border); } -.diff-table td { padding: 5px 10px; border: 1px solid #e8e8e8; vertical-align: top; } -.diff-field { font-weight: 600; color: #444; font-family: monospace; white-space: nowrap; background: #fafafa; } -.diff-before { color: #c62828; background: #fff5f5; font-family: monospace; word-break: break-all; } +.diff-table td { padding: 5px 10px; border: 1px solid var(--color-border); vertical-align: top; } +.diff-field { font-weight: 600; color: var(--color-text-muted); font-family: monospace; white-space: nowrap; background: var(--color-surface-alt); } +.diff-before { color: var(--color-danger-text); background: #fff5f5; font-family: monospace; word-break: break-all; } .diff-after { color: #2e7d32; background: #f5fff5; font-family: monospace; word-break: break-all; } /* ── Pagination ──────────────────────────────────────────────────── */ @@ -393,16 +393,16 @@ } .btn-page { padding: 7px 14px; - border: 1.5px solid #d0d7de; + border: 1.5px solid var(--color-border); border-radius: 6px; - background: white; + background: var(--color-surface); cursor: pointer; font-size: 13px; - color: #333; + color: var(--color-text); } -.btn-page:hover:not(:disabled) { background: #f0f4f8; border-color: #1976d2; } -.btn-page:disabled { color: #bbb; cursor: not-allowed; border-color: #eee; } -.page-info { font-size: 13px; color: #666; padding: 0 8px; } +.btn-page:hover:not(:disabled) { background: var(--color-surface-alt); border-color: var(--color-primary); } +.btn-page:disabled { color: var(--color-text-muted); cursor: not-allowed; border-color: var(--color-border); } +.page-info { font-size: 13px; color: var(--color-text-muted); padding: 0 8px; } .audit-header { @@ -411,13 +411,13 @@ .audit-header h2 { margin: 0 0 8px 0; - color: #333; + color: var(--color-text); font-size: 28px; } .audit-description { margin: 0; - color: #666; + color: var(--color-text-muted); font-size: 14px; } @@ -428,7 +428,7 @@ } .audit-error p { - color: #d32f2f; + color: var(--color-danger-text); margin: 0; } @@ -441,23 +441,23 @@ .filter-select { padding: 10px 14px; - border: 2px solid #e0e0e0; + border: 2px solid var(--color-border); border-radius: 6px; font-size: 14px; - background: white; + background: var(--color-surface); cursor: pointer; transition: border-color 0.2s; } .filter-select:focus { outline: none; - border-color: #1976d2; + border-color: var(--color-primary); } .btn-refresh { padding: 10px 16px; - background: #1976d2; - color: white; + background: var(--color-info); + color: var(--color-on-info); border: none; border-radius: 6px; cursor: pointer; @@ -467,20 +467,21 @@ } .btn-refresh:hover:not(:disabled) { - background: #1565c0; + background: var(--color-info-dark); } .btn-refresh:disabled { - background: #bdbdbd; + background: var(--color-surface-alt); + color: var(--color-text-muted); cursor: not-allowed; } .audit-empty { text-align: center; padding: 40px; - background: #f5f5f5; + background: var(--color-surface-alt); border-radius: 8px; - color: #666; + color: var(--color-text-muted); } .audit-list { @@ -490,8 +491,8 @@ } .audit-item { - background: white; - border: 1px solid #e0e0e0; + background: var(--color-surface); + border: 1px solid var(--color-border); border-radius: 8px; padding: 16px; transition: box-shadow 0.2s; @@ -519,58 +520,18 @@ gap: 4px; } -.badge-create { - background: #e8f5e9; - color: #2e7d32; -} - -.badge-update { - background: #e3f2fd; - color: #1565c0; -} - -.badge-delete { - background: #ffebee; - color: #c62828; -} - -.badge-restore { - background: #fff3e0; - color: #e65100; -} - -.badge-login { - background: #f3e5f5; - color: #6a1b9a; -} - -.badge-logout { - background: #fce4ec; - color: #880e4f; -} - -.badge-login-failed { - background: #ffcdd2; - color: #b71c1c; - font-weight: 700; -} - -.badge-default { - background: #f5f5f5; - color: #616161; -} .audit-resource { padding: 4px 10px; - background: #f5f5f5; + background: var(--color-surface-alt); border-radius: 4px; font-size: 13px; - color: #666; + color: var(--color-text-muted); } .audit-time { margin-left: auto; - color: #999; + color: var(--color-text-muted); font-size: 13px; } @@ -582,23 +543,19 @@ } .audit-admin { - color: #333; + color: var(--color-text); } .audit-resource-name { - color: #666; + color: var(--color-text-muted); } .audit-ip { - color: #888; + color: var(--color-text-muted); font-family: monospace; font-size: 13px; } -.audit-error-message { - color: #d32f2f; - font-weight: 500; -} .audit-pagination { display: flex; @@ -607,15 +564,15 @@ gap: 16px; margin-top: 24px; padding: 16px; - background: white; + background: var(--color-surface); border-radius: 8px; - border: 1px solid #e0e0e0; + border: 1px solid var(--color-border); } .btn-page { padding: 8px 16px; - background: #1976d2; - color: white; + background: var(--color-info); + color: var(--color-on-info); border: none; border-radius: 6px; cursor: pointer; @@ -624,16 +581,17 @@ } .btn-page:hover:not(:disabled) { - background: #1565c0; + background: var(--color-info-dark); } .btn-page:disabled { - background: #bdbdbd; + background: var(--color-surface-alt); + color: var(--color-text-muted); cursor: not-allowed; } .page-info { - color: #666; + color: var(--color-text-muted); font-size: 14px; } @@ -656,3 +614,33 @@ width: 100%; } } + +/* ── Nachtvariante ─────────────────────────────────────────────────────── + Die Badges kodieren die Aktionsart über den Farbton – der bleibt erhalten, + nur Helligkeit und Sättigung drehen sich um. Alle Paare >= 6.4:1. */ +@media (prefers-color-scheme: dark) { + .badge-create { background: #162d17; color: #97d99a; } + .badge-update { background: #16202d; color: #89b5e6; } + .badge-delete { background: #2d1616; color: #e68989; } + .badge-restore { background: #2d1e16; color: #e6aa89; } + .badge-login { background: #24162d; color: #c389e6; } + .badge-logout { background: #2d1622; color: #e689bb; } + .badge-login-failed { background: #2d1616; color: #e68989; } + .badge-import { background: #162d2a; color: #89e6db; } + .badge-export { background: #162d17; color: #90df96; } + .badge-bulk-update { background: #16182d; color: #8f99e0; } + .badge-bulk-delete { background: #2d1b16; color: #e69f89; } + .badge-password { background: #2d2016; color: #e6b589; } + .badge-default { background: var(--color-surface-alt); color: var(--color-text-muted); } + + .status-ok { background: #162d17; color: #97d99a; } + .status-redirect { background: #2d1e16; color: #e6aa89; } + .status-error { background: #2d1616; color: #e68989; } + .status-server-error { background: #24162d; color: #c389e6; } + + /* Diff-Tabelle: die roten/gruenen Vorher-Nachher-Felder */ + .diff-table th { background: var(--color-surface-alt); } + .diff-before { color: #e68989; background: #2d1616; } + .diff-after { color: #97d99a; background: #162d17; } + .diff-field { background: var(--color-surface-alt); color: var(--color-text); } +} diff --git a/drohnenfuehrer/frontend/src/components/admin/ExportButton.css b/drohnenfuehrer/frontend/src/components/admin/ExportButton.css index 83981da..c231346 100644 --- a/drohnenfuehrer/frontend/src/components/admin/ExportButton.css +++ b/drohnenfuehrer/frontend/src/components/admin/ExportButton.css @@ -14,7 +14,7 @@ .export-button { padding: 0.5rem 1rem; background: var(--color-success); - color: white; + color: var(--color-on-success); border: none; border-radius: var(--radius-sm); cursor: pointer; @@ -41,8 +41,8 @@ .import-button { padding: 0.5rem 1rem; - background: var(--color-primary, #2563eb); - color: white; + background: var(--color-primary, var(--color-info)); + color: var(--color-on-primary); border: none; border-radius: var(--radius-sm); cursor: pointer; @@ -52,7 +52,7 @@ } .import-button:hover:not(:disabled) { - background: var(--color-primary-dark, #1d4ed8); + background: var(--color-primary-dark, var(--color-info-dark)); } .import-button:disabled { @@ -65,7 +65,7 @@ align-items: center; gap: 0.4rem; font-size: 0.85rem; - color: var(--color-text-muted, #6b7280); + color: var(--color-text-muted); cursor: pointer; white-space: nowrap; } diff --git a/drohnenfuehrer/frontend/src/components/admin/Trash.css b/drohnenfuehrer/frontend/src/components/admin/Trash.css index 200c68a..e70ac72 100644 --- a/drohnenfuehrer/frontend/src/components/admin/Trash.css +++ b/drohnenfuehrer/frontend/src/components/admin/Trash.css @@ -10,13 +10,13 @@ .trash-header h2 { margin: 0 0 8px 0; - color: #333; + color: var(--color-text); font-size: 28px; } .trash-description { margin: 0; - color: #666; + color: var(--color-text-muted); font-size: 14px; } @@ -27,14 +27,14 @@ } .trash-error h3 { - color: #d32f2f; + color: var(--color-danger-text); margin-bottom: 12px; } .btn-retry { padding: 10px 20px; - background: #1976d2; - color: white; + background: var(--color-info); + color: var(--color-on-info); border: none; border-radius: 6px; cursor: pointer; @@ -43,13 +43,13 @@ } .btn-retry:hover { - background: #1565c0; + background: var(--color-info-dark); } .trash-empty { text-align: center; padding: 60px 20px; - background: #f5f5f5; + background: var(--color-surface-alt); border-radius: 12px; } @@ -60,7 +60,7 @@ } .trash-empty p { - color: #666; + color: var(--color-text-muted); font-size: 16px; margin: 0; } @@ -72,8 +72,8 @@ } .trash-item { - background: #fff; - border: 2px solid #e0e0e0; + background: var(--color-surface); + border: 2px solid var(--color-border); border-radius: 8px; padding: 16px 20px; display: flex; @@ -84,7 +84,7 @@ .trash-item:hover { box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); - border-color: #bdbdbd; + border-color: var(--color-border); } .trash-item-info { @@ -93,7 +93,7 @@ .trash-item-info h3 { margin: 0 0 8px 0; - color: #333; + color: var(--color-text); font-size: 18px; font-weight: 600; } @@ -106,8 +106,8 @@ } .trash-item-type { - background: #e3f2fd; - color: #1976d2; + background: var(--color-info-bg); + color: var(--color-info-text); padding: 4px 10px; border-radius: 4px; font-size: 13px; @@ -116,12 +116,12 @@ .trash-item-address, .trash-item-phone { - color: #666; + color: var(--color-text-muted); font-size: 14px; } .trash-item-meta { - color: #999; + color: var(--color-text-muted); font-size: 13px; } @@ -140,8 +140,8 @@ align-items: center; gap: 6px; padding: 10px 16px; - background: #4caf50; - color: white; + background: var(--color-success); + color: var(--color-on-success); border: none; border-radius: 6px; cursor: pointer; @@ -151,7 +151,7 @@ } .btn-restore:hover:not(:disabled) { - background: #45a049; + background: var(--color-success-dark); transform: translateY(-1px); } @@ -160,7 +160,7 @@ } .btn-restore:disabled { - background: #bdbdbd; + background: var(--color-border-strong); cursor: not-allowed; } diff --git a/drohnenfuehrer/frontend/src/components/auth/LoginForm.css b/drohnenfuehrer/frontend/src/components/auth/LoginForm.css index 1a38755..56024ab 100644 --- a/drohnenfuehrer/frontend/src/components/auth/LoginForm.css +++ b/drohnenfuehrer/frontend/src/components/auth/LoginForm.css @@ -56,7 +56,7 @@ width: 100%; padding: 0.75rem; background: var(--color-primary); - color: white; + color: var(--color-on-primary); border: none; border-radius: var(--radius-sm); font-size: 1rem; @@ -76,8 +76,8 @@ .login-error { padding: 0.75rem; - background: #ffebee; - border: 1px solid #ffcdd2; + background: var(--color-danger-bg); + border: 1px solid var(--color-danger-border); border-radius: var(--radius-sm); color: var(--color-danger); margin-bottom: 1rem; diff --git a/drohnenfuehrer/frontend/src/components/auth/PasswordReset.css b/drohnenfuehrer/frontend/src/components/auth/PasswordReset.css index cd3c067..4ee08d1 100644 --- a/drohnenfuehrer/frontend/src/components/auth/PasswordReset.css +++ b/drohnenfuehrer/frontend/src/components/auth/PasswordReset.css @@ -1,5 +1,6 @@ .password-reset-container { - min-height: 100vh; + /* dvh: mit ein- und ausblendender Adressleiste entsteht mit vh Überlauf. */ + min-height: 100dvh; display: flex; justify-content: center; align-items: center; @@ -8,7 +9,7 @@ } .password-reset-card { - background: white; + background: var(--color-surface); border-radius: 12px; box-shadow: 0 10px 40px rgba(0, 0, 0, 0.1); padding: 40px; @@ -18,7 +19,7 @@ .password-reset-card h2 { margin: 0 0 24px 0; - color: #333; + color: var(--color-text); font-size: 28px; text-align: center; } @@ -32,15 +33,15 @@ } .message.success { - background-color: #d4edda; - color: #155724; - border: 1px solid #c3e6cb; + background-color: var(--color-success-bg); + color: var(--color-success-text); + border: 1px solid var(--color-success-border); } .message.error { - background-color: #f8d7da; - color: #721c24; - border: 1px solid #f5c6cb; + background-color: var(--color-danger-bg); + color: var(--color-danger-text); + border: 1px solid var(--color-danger-border); } .form-group { @@ -50,7 +51,7 @@ .form-group label { display: block; margin-bottom: 8px; - color: #555; + color: var(--color-text-muted); font-weight: 500; font-size: 14px; } @@ -58,7 +59,7 @@ .form-group input { width: 100%; padding: 12px 16px; - border: 2px solid #e0e0e0; + border: 2px solid var(--color-border); border-radius: 8px; font-size: 15px; transition: border-color 0.3s; @@ -71,14 +72,14 @@ } .form-group input:disabled { - background-color: #f5f5f5; + background-color: var(--color-surface-alt); cursor: not-allowed; } .form-group small { display: block; margin-top: 6px; - color: #888; + color: var(--color-text-muted); font-size: 13px; } @@ -86,7 +87,7 @@ width: 100%; padding: 14px; background: var(--color-primary); - color: white; + color: var(--color-on-primary); border: none; border-radius: 8px; font-size: 16px; diff --git a/drohnenfuehrer/frontend/src/components/common/ErrorMessage.css b/drohnenfuehrer/frontend/src/components/common/ErrorMessage.css index 38733d8..efba2ba 100644 --- a/drohnenfuehrer/frontend/src/components/common/ErrorMessage.css +++ b/drohnenfuehrer/frontend/src/components/common/ErrorMessage.css @@ -4,10 +4,10 @@ gap: 0.5rem; padding: 1rem; margin: 1rem 0; - background-color: #fee; - border: 1px solid #fcc; + background-color: var(--color-danger-bg); + border: 1px solid var(--color-danger-border); border-radius: 4px; - color: #c33; + color: var(--color-danger-text); } .error-icon { @@ -22,7 +22,7 @@ background: none; border: none; font-size: 1.5rem; - color: #c33; + color: var(--color-danger-text); cursor: pointer; padding: 0; width: 24px; @@ -34,5 +34,5 @@ } .error-close:hover { - color: #a22; + color: var(--color-danger-text); } diff --git a/drohnenfuehrer/frontend/src/components/common/Header.css b/drohnenfuehrer/frontend/src/components/common/Header.css index 69a023f..dd3e83d 100644 --- a/drohnenfuehrer/frontend/src/components/common/Header.css +++ b/drohnenfuehrer/frontend/src/components/common/Header.css @@ -1,6 +1,6 @@ .app-header { - background: #ffffff; - border-bottom: 1px solid #e5e5e5; + background: var(--color-surface); + border-bottom: 1px solid var(--color-border); padding: 0.75rem 2rem; display: flex; align-items: center; @@ -27,7 +27,7 @@ .portal-back-link:hover { background: var(--color-primary); - color: #fff; + color: var(--color-on-primary); } .app-brand { @@ -40,18 +40,18 @@ height: 52px; width: auto; object-fit: contain; -} - -.app-logo-ljn { - height: 44px; + flex-shrink: 0; } .app-title { margin: 0; + font-family: var(--font-display); font-size: 1.05rem; font-weight: 700; color: var(--color-text); - white-space: nowrap; + /* Kein nowrap: lange App-Namen haben die Kopfzeile sonst über die + Bildschirmbreite hinaus geschoben. */ + overflow-wrap: anywhere; } .app-nav { @@ -61,11 +61,14 @@ } .nav-button { + display: inline-flex; + align-items: center; + min-height: var(--touch-target); padding: 0.5rem 0.875rem; background: none; border: none; border-radius: var(--radius-sm); - color: #333; + color: var(--color-text); cursor: pointer; font-size: 0.9rem; font-weight: 500; @@ -97,12 +100,19 @@ .app-header { flex-direction: column; align-items: flex-start; - padding: 0.75rem 1rem; - gap: 0.5rem; + padding: 0.5rem 1rem; + gap: 0.4rem; + /* Auf schmalen Geräten nimmt die umgebrochene Kopfzeile viel Höhe ein. + Klebrig bleibt sie nur dort, wo genug Platz ist. */ + position: static; } .app-title { - font-size: 0.9rem; + font-size: 0.95rem; + } + + .app-logo { + height: 36px; } .app-nav { @@ -111,7 +121,31 @@ } .nav-button { - font-size: 0.85rem; + font-size: 0.9rem; padding: 0.4rem 0.7rem; } } + +@media (max-width: 480px) { + .app-header { + padding: 0.5rem 0.75rem; + } + + .app-brand { + gap: 0.5rem; + } + + .app-logo { + height: 30px; + } + + .app-nav { + width: 100%; + } + + .nav-button { + flex: 1 1 45%; + justify-content: center; + padding: 0.4rem 0.5rem; + } +} diff --git a/drohnenfuehrer/frontend/src/components/common/InstallBanner.css b/drohnenfuehrer/frontend/src/components/common/InstallBanner.css index f5b248d..0ab554a 100644 --- a/drohnenfuehrer/frontend/src/components/common/InstallBanner.css +++ b/drohnenfuehrer/frontend/src/components/common/InstallBanner.css @@ -2,8 +2,8 @@ position: sticky; top: 0; z-index: 1000; - background-color: #2d6a2d; - color: #fff; + background-color: var(--color-primary); + color: var(--color-on-primary); box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3); } @@ -22,8 +22,8 @@ } .install-banner__btn { - background: #fff; - color: #2d6a2d; + background: var(--color-surface); + color: var(--color-primary); border: none; border-radius: 4px; padding: 0.35rem 0.85rem; @@ -34,7 +34,7 @@ } .install-banner__btn:hover { - background: #e8f5e9; + background: var(--color-success-bg); } .install-banner__close { @@ -49,7 +49,7 @@ } .install-banner__close:hover { - color: #fff; + color: var(--color-on-primary); } .install-banner__share-icon { diff --git a/drohnenfuehrer/frontend/src/components/common/Loading.css b/drohnenfuehrer/frontend/src/components/common/Loading.css index ec8df60..e1dbe74 100644 --- a/drohnenfuehrer/frontend/src/components/common/Loading.css +++ b/drohnenfuehrer/frontend/src/components/common/Loading.css @@ -8,8 +8,8 @@ } .spinner { - border: 4px solid #f3f3f3; - border-top: 4px solid #3498db; + border: 4px solid var(--color-border); + border-top: 4px solid var(--color-primary); border-radius: 50%; width: 50px; height: 50px; @@ -23,6 +23,6 @@ .loading-message { margin-top: 1rem; - color: #666; + color: var(--color-text-muted); font-size: 0.9rem; } diff --git a/drohnenfuehrer/frontend/src/components/drohnenfuehrer/DrohnenfuehrerDashboard.css b/drohnenfuehrer/frontend/src/components/drohnenfuehrer/DrohnenfuehrerDashboard.css index 5a312bb..3109209 100644 --- a/drohnenfuehrer/frontend/src/components/drohnenfuehrer/DrohnenfuehrerDashboard.css +++ b/drohnenfuehrer/frontend/src/components/drohnenfuehrer/DrohnenfuehrerDashboard.css @@ -5,7 +5,7 @@ } .drohnenfuehrer-dashboard-card { - background: white; + background: var(--color-surface); border-radius: 10px; padding: 2rem; width: 100%; @@ -46,7 +46,7 @@ .btn-drohnenfuehrer-logout:hover { background: var(--color-danger); - color: white; + color: var(--color-on-danger); } .drohnenfuehrer-message { @@ -56,8 +56,8 @@ font-size: 0.9rem; } -.drohnenfuehrer-message-success { background: #dcfce7; color: #166534; } -.drohnenfuehrer-message-error { background: #fee2e2; color: #b91c1c; } +.drohnenfuehrer-message-success { background: var(--color-success-bg); color: var(--color-success-text); } +.drohnenfuehrer-message-error { background: var(--color-danger-bg); color: var(--color-danger-text); } .drohnenfuehrer-availability-section { background: var(--color-muted-bg); @@ -92,15 +92,15 @@ .availability-big-btn:disabled { opacity: 0.6; cursor: not-allowed; } .btn-green { - background: #dcfce7; - color: #15803d; - border-color: #86efac; + background: var(--color-success-bg); + color: var(--color-success-text); + border-color: var(--color-success-border); } .btn-red { - background: #fee2e2; - color: #b91c1c; - border-color: #fca5a5; + background: var(--color-danger-bg); + color: var(--color-danger-text); + border-color: var(--color-danger-border); } .status-dot-lg { @@ -110,8 +110,8 @@ flex-shrink: 0; } -.dot-green { background: #22c55e; } -.dot-red { background: #ef4444; } +.dot-green { background: var(--color-success); } +.dot-red { background: var(--color-danger); } .availability-hint { font-size: 0.82rem; @@ -147,7 +147,7 @@ font-size: 0.9rem; } -.btn-drohnenfuehrer-edit:hover { background: var(--color-primary); color: white; } +.btn-drohnenfuehrer-edit:hover { background: var(--color-primary); color: var(--color-on-primary); } .drohnenfuehrer-info-list { display: flex; flex-direction: column; gap: 0.6rem; } @@ -206,7 +206,7 @@ flex: 1; padding: 0.65rem; background: var(--color-primary); - color: white; + color: var(--color-on-primary); border: none; border-radius: 6px; font-size: 0.95rem; diff --git a/drohnenfuehrer/frontend/src/components/drohnenfuehrer/DrohnenfuehrerLogin.css b/drohnenfuehrer/frontend/src/components/drohnenfuehrer/DrohnenfuehrerLogin.css index abca037..f7e71b9 100644 --- a/drohnenfuehrer/frontend/src/components/drohnenfuehrer/DrohnenfuehrerLogin.css +++ b/drohnenfuehrer/frontend/src/components/drohnenfuehrer/DrohnenfuehrerLogin.css @@ -6,7 +6,7 @@ } .drohnenfuehrer-login-card { - background: white; + background: var(--color-surface); border-radius: 10px; padding: 2rem; width: 100%; @@ -48,7 +48,7 @@ .drohnenfuehrer-mode-toggle button.active { background: var(--color-primary); - color: white; + color: var(--color-on-primary); font-weight: 600; } @@ -82,7 +82,7 @@ width: 100%; padding: 0.75rem; background: var(--color-primary); - color: white; + color: var(--color-on-primary); border: none; border-radius: 6px; font-size: 1rem; @@ -102,8 +102,8 @@ } .drohnenfuehrer-error { - background: #fee2e2; - color: #b91c1c; + background: var(--color-danger-bg); + color: var(--color-danger-text); border-radius: 4px; padding: 0.6rem 0.9rem; margin-bottom: 1rem; @@ -111,8 +111,8 @@ } .drohnenfuehrer-success { - background: #dcfce7; - color: #166534; + background: var(--color-success-bg); + color: var(--color-success-text); border-radius: 4px; padding: 0.6rem 0.9rem; margin-bottom: 1rem; diff --git a/drohnenfuehrer/frontend/src/components/map/MapView.css b/drohnenfuehrer/frontend/src/components/map/MapView.css index bfb9cff..6e82ee3 100644 --- a/drohnenfuehrer/frontend/src/components/map/MapView.css +++ b/drohnenfuehrer/frontend/src/components/map/MapView.css @@ -13,32 +13,32 @@ left: 12px; z-index: 500; background: rgba(255, 255, 255, 0.95); - color: #444; + color: var(--color-text-muted); padding: 0.45rem 0.7rem; border-radius: 6px; font-size: 0.85rem; - border: 1px solid #dcdcdc; + border: 1px solid var(--color-border); } .map-no-data { padding: 3rem; text-align: center; - color: #666; - background: white; + color: var(--color-text-muted); + background: var(--color-surface); border-radius: 8px; margin: 1rem 0; } .map-popup h3 { margin: 0 0 0.5rem 0; - color: #333; + color: var(--color-text); font-size: 1rem; } .map-popup p { margin: 0.25rem 0; font-size: 0.85rem; - color: #666; + color: var(--color-text-muted); } .map-popup a { @@ -54,8 +54,40 @@ display: inline-block; padding: 0.2rem 0.5rem; background: var(--color-primary); - color: white; + color: var(--color-on-primary); border-radius: 4px; font-size: 0.75rem; margin-top: 0.5rem; } + +/* ── Nachtansicht ──────────────────────────────────────────────────────── + Die OSM-Kacheln sind immer taghell. In der Dämmerung ist die Karte damit + die mit Abstand hellste Fläche der App und blendet — genau die Situation, + in der Nachsuchen stattfinden. Die Kacheln werden deshalb abgedunkelt; + Marker und Bedienelemente bleiben unangetastet, damit sie lesbar sind. */ +@media (prefers-color-scheme: dark) { + .leaflet-tile-pane { + filter: brightness(0.62) saturate(0.75) contrast(1.05); + } + + .leaflet-container { + background: var(--color-surface-alt); + } + + /* Hoehere Spezifitaet als Leaflets eigene Regeln, die spaeter geladen werden */ + .leaflet-container .leaflet-control-zoom a, + .leaflet-container .leaflet-control-attribution { + background: var(--color-surface); + color: var(--color-text); + } + + .leaflet-container .leaflet-control-attribution a { + color: var(--color-primary); + } + + .leaflet-popup-content-wrapper, + .leaflet-popup-tip { + background: var(--color-surface); + color: var(--color-text); + } +} diff --git a/drohnenfuehrer/frontend/src/components/public/PublicUserList.css b/drohnenfuehrer/frontend/src/components/public/PublicUserList.css index c24d538..eb2084f 100644 --- a/drohnenfuehrer/frontend/src/components/public/PublicUserList.css +++ b/drohnenfuehrer/frontend/src/components/public/PublicUserList.css @@ -14,7 +14,7 @@ } .public-user-list h2 { - color: #1a1a1a; + color: var(--color-text); margin: 0; font-size: 1.5rem; font-weight: 700; @@ -23,7 +23,7 @@ .toggle-map-button { padding: 0.5rem 1rem; background: var(--color-primary); - color: white; + color: var(--color-on-primary); border: none; border-radius: 4px; cursor: pointer; @@ -44,8 +44,8 @@ .filter-toggle-button { padding: 0.5rem 1rem; - background: #6c757d; - color: white; + background: var(--color-secondary); + color: var(--color-on-secondary); border: none; border-radius: 4px; cursor: pointer; @@ -55,12 +55,12 @@ } .filter-toggle-button:hover { - background: #5a6268; + background: var(--color-secondary-dark); } .location-panel { - background: white; - border: 1px solid #e5e5e5; + background: var(--color-surface); + border: 1px solid var(--color-border); border-radius: 8px; padding: 1rem 1.5rem; margin-bottom: 1.5rem; @@ -78,7 +78,7 @@ .location-button { padding: 0.5rem 1rem; background: var(--color-primary); - color: white; + color: var(--color-on-primary); border: none; border-radius: 4px; cursor: pointer; @@ -92,7 +92,7 @@ } .location-button:disabled { - background: #b6b6b6; + background: var(--color-border-strong); cursor: not-allowed; } @@ -103,13 +103,13 @@ } .location-status.success { - background: #e8f5e9; - color: var(--color-primary-dark); + background: var(--color-success-bg); + color: var(--color-success-text); } .location-status.error { - background: #ffebee; - color: #c62828; + background: var(--color-danger-bg); + color: var(--color-danger-text); } .postal-search { @@ -120,21 +120,21 @@ .postal-search input[type="text"] { padding: 0.5rem; - border: 1px solid #ddd; + border: 1px solid var(--color-border); border-radius: 4px; font-size: 0.9rem; width: 150px; } .postal-search input[type="text"]:disabled { - background: #f5f5f5; + background: var(--color-surface-alt); cursor: not-allowed; } .postal-search button { padding: 0.5rem 1rem; background: var(--color-primary); - color: white; + color: var(--color-on-primary); border: none; border-radius: 4px; cursor: pointer; @@ -148,14 +148,14 @@ } .postal-search button:disabled { - background: #b6b6b6; + background: var(--color-border-strong); cursor: not-allowed; } .radius-filter label { display: block; font-size: 0.9rem; - color: #555; + color: var(--color-text-muted); margin-bottom: 0.5rem; font-weight: 500; } @@ -174,26 +174,26 @@ .radius-inputs input[type="number"] { width: 80px; padding: 0.4rem 0.5rem; - border: 1px solid #ddd; + border: 1px solid var(--color-border); border-radius: 4px; font-size: 0.9rem; } .radius-inputs input:disabled { - background: #f5f5f5; + background: var(--color-surface-alt); cursor: not-allowed; } .radius-hint { font-size: 0.85rem; - color: #777; + color: var(--color-text-muted); margin-top: 0.5rem; } .gps-hint { margin-top: 0.5rem; font-size: 0.85rem; - color: #777; + color: var(--color-text-muted); } .user-grid { @@ -205,8 +205,8 @@ /* Jägerschaft-style card */ .user-card { - background: white; - border: 1px solid #e5e5e5; + background: var(--color-surface); + border: 1px solid var(--color-border); border-radius: 8px; padding: 1.5rem; box-shadow: 0 2px 6px rgba(0, 0, 0, 0.06); @@ -232,9 +232,9 @@ box-shadow: 0 6px 16px rgba(0, 0, 0, 0.1); } -.user-name { +.public-user-list .user-name { margin: 0 0 0.2rem; - color: #1a1a1a; + color: var(--color-text); font-size: 1rem; font-weight: 700; text-transform: uppercase; @@ -250,15 +250,15 @@ color: var(--color-primary); } -.user-info { +.public-user-list .user-info { display: flex; flex-direction: column; gap: 0.375rem; } -.user-address { +.public-user-list .user-address { margin: 0; - color: #666; + color: var(--color-text-muted); font-size: 0.9rem; } @@ -266,72 +266,80 @@ margin: 0.5rem 0 0; } -.type-badge { +.public-user-list .type-badge { display: inline-block; padding: 0.2rem 0.6rem; - background: #f0f0f0; - color: #444; + background: var(--color-surface-alt); + color: var(--color-text-muted); border-radius: 4px; font-size: 0.8rem; font-weight: 600; letter-spacing: 0.03em; } +/* Der Anruf beim Drohnenführer ist der Zweck dieser Liste und wird fast + immer mit dem Daumen auf dem Handy ausgelöst. Vorher war das ein 14 px hoher + Textlink; jetzt ein vollwertiges Ziel mit der empfohlenen Mindesthöhe. */ .user-phone { + display: flex; + align-items: center; + gap: 0.5rem; + min-height: var(--touch-target); + margin: 0.15rem 0; + padding: 0.35rem 0.6rem; + background: var(--color-surface-alt); + border: 1px solid var(--color-border); + border-radius: var(--radius-sm); color: var(--color-primary); text-decoration: none; - font-weight: 500; - font-size: 0.9rem; + font-weight: 600; + font-size: 1rem; } -.user-phone:hover { +.public-user-list .user-phone:hover, +.public-user-list .user-phone:focus-visible { + background: var(--color-surface); + border-color: var(--color-border-strong); text-decoration: underline; } -.user-gps { - margin-top: 1rem; - padding-top: 1rem; - border-top: 1px solid #e5e5e5; - font-size: 0.85rem; - color: #888; -} .user-distance { margin-top: 0.75rem; padding-top: 0.75rem; - border-top: 1px solid #e5e5e5; + border-top: 1px solid var(--color-border); font-size: 0.85rem; - color: #555; + color: var(--color-text-muted); font-weight: 500; } .no-users { text-align: center; padding: 3rem; - color: #666; + color: var(--color-text-muted); } .loading { text-align: center; padding: 3rem; - color: #666; + color: var(--color-text-muted); } @media (max-width: 768px) { - .user-grid { +.user-grid { grid-template-columns: 1fr; } - .public-user-list { +.public-user-list { padding: 1rem; } - .radius-inputs { +.radius-inputs { flex-direction: column; align-items: stretch; } - .radius-inputs input[type="number"] { +.radius-inputs input[type="number"] { width: 100%; } } diff --git a/drohnenfuehrer/frontend/src/components/public/RulesDisplay.css b/drohnenfuehrer/frontend/src/components/public/RulesDisplay.css index 32be9b6..4ec7a73 100644 --- a/drohnenfuehrer/frontend/src/components/public/RulesDisplay.css +++ b/drohnenfuehrer/frontend/src/components/public/RulesDisplay.css @@ -33,7 +33,7 @@ } .allgemeines-tab-btn.active { - background: white; + background: var(--color-surface); color: var(--color-primary); font-weight: 700; border-color: var(--color-primary); @@ -41,7 +41,7 @@ } .allgemeines-content { - background: white; + background: var(--color-surface); border: 1px solid var(--color-primary); border-top: none; border-radius: 0 0 8px 8px; diff --git a/drohnenfuehrer/frontend/src/components/users/UserCard.css b/drohnenfuehrer/frontend/src/components/users/UserCard.css index a6f6bb7..2c62fa9 100644 --- a/drohnenfuehrer/frontend/src/components/users/UserCard.css +++ b/drohnenfuehrer/frontend/src/components/users/UserCard.css @@ -25,7 +25,7 @@ border-bottom: 1px solid var(--color-border); } -.user-name-row { +.user-card-admin .user-name-row { display: flex; align-items: center; gap: 0.5rem; @@ -39,10 +39,10 @@ box-shadow: 0 0 4px rgba(0,0,0,0.2); } -.dot-green { background: #22c55e; } -.dot-red { background: #ef4444; } +.dot-green { background: var(--color-success); } +.dot-red { background: var(--color-danger); } -.user-name { +.user-card-admin .user-name { margin: 0; color: var(--color-text); font-size: 1.2rem; @@ -67,40 +67,40 @@ font-weight: 600; } -.label-green { color: #16a34a; } -.label-red { color: var(--color-danger); } +.label-green { color: var(--color-success); } +.label-red { color: var(--color-danger); } -.user-info { +.user-card-admin .user-info { display: flex; flex-direction: column; gap: 0.5rem; margin-bottom: 1rem; } -.user-address { +.user-card-admin .user-address { margin: 0; color: var(--color-text-muted); font-size: 0.9rem; } -.type-badge { +.user-card-admin .type-badge { display: inline-block; padding: 0.25rem 0.75rem; background: var(--color-primary); - color: white; + color: var(--color-on-primary); border-radius: var(--radius-pill); font-size: 0.85rem; font-weight: 500; } -.user-phone { +.user-card-admin .user-phone { color: var(--color-primary); text-decoration: none; font-weight: 500; font-size: 1rem; } -.user-phone:hover { +.user-card-admin .user-phone:hover { text-decoration: underline; } @@ -183,7 +183,7 @@ .edit-gps-button { padding: 0.25rem 0.75rem; background: var(--color-primary); - color: white; + color: var(--color-on-primary); border: none; border-radius: var(--radius-sm); cursor: pointer; @@ -229,7 +229,7 @@ .save-gps-button { background: var(--color-success); - color: white; + color: var(--color-on-success); } .save-gps-button:hover:not(:disabled) { @@ -243,7 +243,7 @@ .cancel-gps-button { background: var(--color-secondary); - color: white; + color: var(--color-on-secondary); } .cancel-gps-button:hover { @@ -272,7 +272,7 @@ .edit-button { background: var(--color-primary); - color: white; + color: var(--color-on-primary); } .edit-button:hover { @@ -281,7 +281,7 @@ .delete-button { background: var(--color-danger); - color: white; + color: var(--color-on-danger); } .delete-button:hover { @@ -289,17 +289,17 @@ } @media (max-width: 768px) { - .user-header { +.user-header { flex-direction: column; align-items: flex-start; gap: 0.5rem; } - .gps-inputs { +.gps-inputs { flex-direction: column; } - .card-actions { +.card-actions { flex-direction: column; } } @@ -322,7 +322,7 @@ display: block; margin-top: 0.35rem; padding: 0.4rem 0.5rem; - background: var(--color-bg-muted, #f2f2ec); + background: var(--color-surface-alt); border: 1px solid var(--color-border); border-radius: 2px; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; diff --git a/drohnenfuehrer/frontend/src/components/users/UserForm.css b/drohnenfuehrer/frontend/src/components/users/UserForm.css index 474c2a3..e3e62df 100644 --- a/drohnenfuehrer/frontend/src/components/users/UserForm.css +++ b/drohnenfuehrer/frontend/src/components/users/UserForm.css @@ -91,7 +91,7 @@ top: 100%; left: 0; right: 0; - background: white; + background: var(--color-surface); border: 1px solid var(--color-border-strong); border-top: none; border-radius: 0 0 var(--radius-sm) var(--radius-sm); @@ -163,7 +163,7 @@ .btn-primary { background: var(--color-primary); - color: white; + color: var(--color-on-primary); } .btn-primary:hover { @@ -172,7 +172,7 @@ .btn-secondary { background: var(--color-secondary); - color: white; + color: var(--color-on-secondary); } .btn-secondary:hover { diff --git a/drohnenfuehrer/frontend/src/components/users/UserList.css b/drohnenfuehrer/frontend/src/components/users/UserList.css index 4dd50f4..03ceb1a 100644 --- a/drohnenfuehrer/frontend/src/components/users/UserList.css +++ b/drohnenfuehrer/frontend/src/components/users/UserList.css @@ -34,7 +34,7 @@ .create-button { padding: 0.5rem 1rem; background: var(--color-success); - color: white; + color: var(--color-on-success); border: none; border-radius: var(--radius-sm); cursor: pointer; diff --git a/drohnenfuehrer/frontend/src/index.css b/drohnenfuehrer/frontend/src/index.css index ec2585e..a76866f 100644 --- a/drohnenfuehrer/frontend/src/index.css +++ b/drohnenfuehrer/frontend/src/index.css @@ -1,13 +1,8 @@ -body { - margin: 0; - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', - 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', - sans-serif; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - -code { - font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', - monospace; +/* Basisstile stehen in App.css, wo auch die Design-Tokens definiert sind. + Hier stand vorher eine zweite body-Regel, die von App.css vollständig + überschrieben wurde. */ +html { + /* Verhindert, dass iOS beim Drehen die Schrift eigenmächtig vergrößert. */ + -webkit-text-size-adjust: 100%; + text-size-adjust: 100%; } diff --git a/nachsuche/frontend/index.html b/nachsuche/frontend/index.html index 4920ad1..ff0013d 100644 --- a/nachsuche/frontend/index.html +++ b/nachsuche/frontend/index.html @@ -5,7 +5,7 @@ - + diff --git a/nachsuche/frontend/public/logo-fallingbostel.png b/nachsuche/frontend/public/logo-fallingbostel.png deleted file mode 100644 index bf3e426..0000000 Binary files a/nachsuche/frontend/public/logo-fallingbostel.png and /dev/null differ diff --git a/nachsuche/frontend/public/logo-ljn.png b/nachsuche/frontend/public/logo-ljn.png deleted file mode 100644 index a1a6ce9..0000000 Binary files a/nachsuche/frontend/public/logo-ljn.png and /dev/null differ diff --git a/nachsuche/frontend/public/manifest.json b/nachsuche/frontend/public/manifest.json index 310f74e..2ab89a8 100644 --- a/nachsuche/frontend/public/manifest.json +++ b/nachsuche/frontend/public/manifest.json @@ -19,7 +19,7 @@ "scope": "/nachsuche/", "display": "standalone", "orientation": "portrait", - "theme_color": "#2d6a2d", - "background_color": "#ffffff", + "theme_color": "#1a3d1a", + "background_color": "#e8e8e2", "description": "Nachsuchenstation Heidekreis – Übersicht der Nachsuchenführer" } diff --git a/nachsuche/frontend/public/offline.html b/nachsuche/frontend/public/offline.html index 13728bd..b1c4d55 100644 --- a/nachsuche/frontend/public/offline.html +++ b/nachsuche/frontend/public/offline.html @@ -1,16 +1,93 @@ - + - - - Offline - Nachsuchenführer - + + + + Offline – Jagd Apps Heidekreis + -

Du bist offline

-

Die App ist derzeit nicht verfügbar. Bitte überprüfe deine Internetverbindung.

+
+ +

Keine Verbindung

+

+ Im Funkloch sind die zuletzt geladenen Daten nicht verfügbar. + Sobald wieder Empfang besteht, lädt die Seite normal. +

+ +
- \ No newline at end of file + diff --git a/nachsuche/frontend/src/App.css b/nachsuche/frontend/src/App.css index b8f3ffe..b3a77b8 100644 --- a/nachsuche/frontend/src/App.css +++ b/nachsuche/frontend/src/App.css @@ -2,43 +2,203 @@ box-sizing: border-box; } +/* ────────────────────────────────────────────────────────────────────────── + Design-Tokens — einzige Farbquelle der App. + Palette und Formensprache folgen dem Portal (portal/index.html), damit der + Wechsel vom Portal in eine App nicht wie ein Produktwechsel wirkt. + Schriftmodell wie im Portal: Serif für die Marken-/Überschriftenebene, + Sans für funktionale UI-Texte (auf kleinen Displays besser lesbar). + + Alle Textpaare erfüllen WCAG AA (>= 4.5:1), funktionale Rahmen >= 3.0:1 — + in beiden Varianten nachgerechnet. + ────────────────────────────────────────────────────────────────────────── */ :root { - --color-primary: #2e8b2e; - --color-primary-dark: #1e6b1e; - --color-primary-accent: #8B0D12; - --color-secondary: #6c757d; - --color-secondary-dark: #5a6268; - --color-success: #28a745; - --color-success-dark: #218838; - --color-danger: #dc3545; - --color-danger-dark: #c82333; - --color-bg: #f5f5f0; - --color-surface: #ffffff; + --font-display: Georgia, 'Times New Roman', serif; + --font-ui: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', + 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif; + --font-mono: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', monospace; + + /* Flächen */ + --color-bg: #e8e8e2; + --color-surface: #f4f4ee; + --color-surface-alt: #dedcd2; + --color-muted-bg: #dedcd2; + + /* Text */ --color-text: #1a1a1a; - --color-text-muted: #555; - --color-border: #b8d4b8; - --color-border-strong: #88b888; - --color-focus: rgba(46, 139, 46, 0.2); - --color-muted-bg: #f5f5f0; - --shadow-sm: 0 2px 4px rgba(0, 0, 0, 0.1); - --shadow-md: 0 4px 8px rgba(0, 0, 0, 0.2); - --radius-sm: 4px; - --radius-md: 8px; - --radius-pill: 12px; + --color-text-muted: #55554c; + + /* Rahmen: -border ist dekorativ (Trennlinien, Karten), + -border-strong begrenzt Bedienelemente und erfüllt die 3:1-Anforderung. */ + --color-border: #c9c9b8; + --color-border-strong: #7d7d68; + + /* Aktionsfarben – jeweils mit der zugehörigen Textfarbe, damit die + Dunkelvariante nicht auf weißem Text auf hellem Grund landet. */ + --color-primary: #2d5a2d; + --color-primary-dark: #1a3d1a; + --color-on-primary: #ffffff; + --color-secondary: #5c5c50; + --color-secondary-dark: #46463c; + --color-on-secondary: #ffffff; + --color-success: #1f6b34; + --color-success-dark: #175128; + --color-on-success: #ffffff; + --color-danger: #a32020; + --color-danger-dark: #821919; + --color-on-danger: #ffffff; + --color-warning: #7a5200; + --color-on-warning: #ffffff; + --color-accent: #8b0d12; + --color-on-accent: #ffffff; + /* Altname, wird von RulesDisplay noch benutzt */ + --color-primary-accent: #8b0d12; + + /* Getönte Status-Flächen (Meldungen, Badges, Zustands-Karten). + Der Block wird durch seine Füllung erkannt, der Rahmen ist Zierde. */ + --color-success-bg: #dfeedd; + --color-success-border: #a9cba4; + --color-success-text: #1a4a24; + --color-danger-bg: #f6e0e0; + --color-danger-border: #d9a9a9; + --color-danger-text: #7d1a1a; + --color-warning-bg: #f7edd4; + --color-warning-border: #d9c48a; + --color-warning-text: #5c3d00; + --color-info: #24608f; + --color-info-dark: #1b4a6e; + --color-on-info: #ffffff; + --color-info-bg: #dde8f1; + --color-info-border: #a5bfd4; + --color-info-text: #14405f; + + /* Als RGB-Tripel fuer rgba()-Anwendungen (Puls-Animation im Admin-Panel) */ + --color-primary-rgb: 45, 90, 45; + + --color-focus: rgba(45, 90, 45, 0.35); + + --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.15); + --shadow-md: 0 2px 6px rgba(0, 0, 0, 0.2); + + /* Kantige Ecken wie im Portal */ + --radius-sm: 2px; + --radius-md: 2px; + --radius-pill: 2px; + --space-1: 0.5rem; --space-2: 1rem; --space-3: 1.5rem; --space-4: 2rem; + + /* Mindestgröße für Bedienelemente auf Touchgeräten */ + --touch-target: 44px; } +/* Nachtvariante. Nachsuchen laufen in der Dämmerung und nachts — ein weißes + Vollbild blendet dann und kostet die Dunkeladaption der Augen. Warme, sehr + dunkle Grüntöne statt reinem Schwarz. */ +@media (prefers-color-scheme: dark) { + :root { + --color-bg: #14180f; + --color-surface: #1e241a; + --color-surface-alt: #2a3124; + --color-muted-bg: #2a3124; + + --color-text: #e9e7dd; + --color-text-muted: #a6a698; + + --color-border: #333b28; + --color-border-strong: #758566; + + --color-primary: #7fb36f; + --color-primary-dark: #9ccb8c; + --color-on-primary: #10140c; + --color-secondary: #8d8d80; + --color-secondary-dark: #a3a396; + --color-on-secondary: #10140c; + --color-success: #79c48c; + --color-success-dark: #93d3a3; + --color-on-success: #10140c; + --color-danger: #ea8b8b; + --color-danger-dark: #f2a5a5; + --color-on-danger: #10140c; + --color-warning: #d6b25f; + --color-on-warning: #10140c; + --color-accent: #e88a8f; + --color-on-accent: #10140c; + --color-primary-accent: #e88a8f; + + --color-success-bg: #1d2c20; + --color-success-border: #3d5c43; + --color-success-text: #93d3a3; + --color-danger-bg: #33201f; + --color-danger-border: #6b4040; + --color-danger-text: #f2a5a5; + --color-warning-bg: #322a15; + --color-warning-border: #63552c; + --color-warning-text: #e0c37c; + --color-info: #7fb0dc; + --color-info-dark: #9cc4e8; + --color-on-info: #10140c; + --color-info-bg: #1a2530; + --color-info-border: #3d5468; + --color-info-text: #9cc4e8; + + --color-primary-rgb: 127, 179, 111; + --color-focus: rgba(127, 179, 111, 0.45); + + --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.5); + --shadow-md: 0 2px 6px rgba(0, 0, 0, 0.6); + } +} + +body { + margin: 0; + font-family: var(--font-ui); + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + background: var(--color-bg); + color: var(--color-text); + /* Damit auch vom Browser gestellte Bedienelemente (Bildlaufleisten, + Datumsauswahl, Autofill) der gewählten Ansicht folgen. */ + color-scheme: light dark; +} + +/* Formularfelder brauchen ausdrücklich Farben: ohne sie nimmt der Browser + seinen Standard (weiß) — in der Nachtansicht leuchtet dann jedes Eingabefeld. */ +input:not([type='checkbox']):not([type='radio']):not([type='range']):not([type='file']), +select, +textarea { + background: var(--color-surface); + color: var(--color-text); +} + +input::placeholder, +textarea::placeholder { + color: var(--color-text-muted); + opacity: 1; +} + +h1, h2, h3 { + font-family: var(--font-display); +} + +code { + font-family: var(--font-mono); +} + +/* ── Bedienelemente ─────────────────────────────────────────────────────── */ + .btn { display: inline-flex; align-items: center; justify-content: center; gap: var(--space-1); + min-height: var(--touch-target); padding: 0.5rem 1rem; border: none; border-radius: var(--radius-sm); + font-family: var(--font-ui); font-size: 0.9rem; font-weight: 600; cursor: pointer; @@ -46,15 +206,24 @@ } .btn:disabled { - background: var(--color-border); + background: var(--color-surface-alt); color: var(--color-text-muted); cursor: not-allowed; box-shadow: none; } +/* Sichtbarer Tastaturfokus. Ohne das war die Tastaturbedienung unsichtbar — + Buttons hatten nur einen :hover-Stil. */ +.btn:focus-visible, +.nav-button:focus-visible, +a:focus-visible { + outline: 2px solid var(--color-primary); + outline-offset: 2px; +} + .btn-primary { background: var(--color-primary); - color: white; + color: var(--color-on-primary); } .btn-primary:hover:not(:disabled) { @@ -64,7 +233,7 @@ .btn-secondary { background: var(--color-secondary); - color: white; + color: var(--color-on-secondary); } .btn-secondary:hover:not(:disabled) { @@ -72,19 +241,9 @@ transform: translateY(-1px); } -.btn-success { - background: var(--color-success); - color: white; -} - -.btn-success:hover:not(:disabled) { - background: var(--color-success-dark); - transform: translateY(-1px); -} - .btn-danger { background: var(--color-danger); - color: white; + color: var(--color-on-danger); } .btn-danger:hover:not(:disabled) { @@ -96,9 +255,13 @@ .select, .textarea { width: 100%; + min-height: var(--touch-target); padding: 0.75rem 1rem; + background: var(--color-surface); + color: var(--color-text); border: 1px solid var(--color-border-strong); border-radius: var(--radius-sm); + font-family: var(--font-ui); font-size: 1rem; box-sizing: border-box; } @@ -111,33 +274,19 @@ box-shadow: 0 0 0 3px var(--color-focus); } -.panel { - background: var(--color-surface); - border: 1px solid var(--color-border); - border-radius: var(--radius-md); - padding: var(--space-3); - box-shadow: var(--shadow-sm); -} - .panel-title { margin: 0 0 var(--space-2); + font-family: var(--font-display); font-size: 1.1rem; color: var(--color-text); } -body { - margin: 0; - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', - 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', - sans-serif; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - background: var(--color-bg); - color: var(--color-text); -} +/* ── Grundgerüst ────────────────────────────────────────────────────────── */ .App { - min-height: 100vh; + /* dvh statt vh: mit ein- und ausblendender Adressleiste auf Mobilgeräten + entsteht mit vh sonst Überlauf. */ + min-height: 100dvh; display: flex; flex-direction: column; } @@ -151,44 +300,26 @@ body { display: flex; justify-content: center; align-items: center; - min-height: 100vh; + min-height: 100dvh; font-size: 1.2rem; color: var(--color-text-muted); } -.login-prompt { - position: fixed; - bottom: 20px; - right: 20px; -} - -.login-button-header { - padding: 0.75rem 1.5rem; - background: var(--color-primary); - color: white; - border: none; - border-radius: 4px; - font-size: 1rem; - font-weight: 600; - cursor: pointer; - box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2); - transition: all 0.2s; -} - -.login-button-header:hover { - background: var(--color-primary-dark); - transform: translateY(-2px); - box-shadow: 0 6px 12px rgba(0, 0, 0, 0.3); -} - -@media (max-width: 768px) { - .login-prompt { - bottom: 10px; - right: 10px; +/* Wer Bewegung reduziert haben möchte, bekommt keine Animationen. */ +@media (prefers-reduced-motion: reduce) { + *, + *::before, + *::after { + animation-duration: 0.01ms !important; + animation-iteration-count: 1 !important; + transition-duration: 0.01ms !important; + scroll-behavior: auto !important; } - .login-button-header { - padding: 0.6rem 1.2rem; - font-size: 0.9rem; + .btn:hover:not(:disabled), + .btn-primary:hover:not(:disabled), + .btn-secondary:hover:not(:disabled), + .btn-danger:hover:not(:disabled) { + transform: none; } } diff --git a/nachsuche/frontend/src/components/admin/AdminPanel.css b/nachsuche/frontend/src/components/admin/AdminPanel.css index 12ce644..16e6fa0 100644 --- a/nachsuche/frontend/src/components/admin/AdminPanel.css +++ b/nachsuche/frontend/src/components/admin/AdminPanel.css @@ -25,7 +25,7 @@ .tab-button.active { background: var(--color-primary); - color: white; + color: var(--color-on-primary); } .settings-panel { @@ -59,9 +59,9 @@ .unsaved-badge { display: inline-block; - background: #fff3cd; - color: #856404; - border: 1px solid #ffc107; + background: var(--color-warning-bg); + color: var(--color-warning-text); + border: 1px solid var(--color-warning); border-radius: var(--radius-sm); padding: 0.2rem 0.6rem; font-size: 0.8rem; @@ -102,7 +102,7 @@ display: flex; align-items: center; gap: 0.5rem; - background: var(--color-muted-bg, #f5f5f0); + background: var(--color-muted-bg, var(--color-surface-alt)); border: none; padding: 0.75rem var(--space-2); cursor: pointer; @@ -111,7 +111,7 @@ } .settings-section-header:hover { - background: var(--color-focus, #eef2e6); + background: var(--color-focus, var(--color-success-bg)); } .settings-section-header .settings-heading { @@ -193,7 +193,7 @@ .skeleton-line { height: 1rem; border-radius: var(--radius-sm); - background: linear-gradient(90deg, #e8e8e4 25%, #f0f0ec 50%, #e8e8e4 75%); + background: linear-gradient(90deg, var(--color-surface-alt) 25%, var(--color-surface-alt) 50%, var(--color-surface-alt) 75%); background-size: 200% 100%; animation: skeleton-shimmer 1.4s infinite; margin-bottom: 0.75rem; @@ -323,17 +323,17 @@ .notification.success { background: var(--color-success); - color: white; + color: var(--color-on-success); } .notification.error { background: var(--color-danger); - color: white; + color: var(--color-on-danger); } .notification.warning { - background: #e67e00; - color: white; + background: var(--color-warning); + color: var(--color-on-warning); } @keyframes slideIn { diff --git a/nachsuche/frontend/src/components/admin/AuditLogs.css b/nachsuche/frontend/src/components/admin/AuditLogs.css index 433cfc4..0f2d27a 100644 --- a/nachsuche/frontend/src/components/admin/AuditLogs.css +++ b/nachsuche/frontend/src/components/admin/AuditLogs.css @@ -13,8 +13,8 @@ gap: 12px; flex-wrap: wrap; } -.audit-header h2 { margin: 0 0 4px 0; color: #333; font-size: 26px; } -.audit-description { margin: 0; color: #666; font-size: 13px; } +.audit-header h2 { margin: 0 0 4px 0; color: var(--color-text); font-size: 26px; } +.audit-description { margin: 0; color: var(--color-text-muted); font-size: 13px; } .audit-header-actions { display: flex; @@ -32,24 +32,24 @@ } .btn-stats-toggle { padding: 6px 14px; - background: #f0f4f8; - border: 1px solid #d0d7de; + background: var(--color-surface-alt); + border: 1px solid var(--color-border); border-radius: 6px; cursor: pointer; font-size: 13px; - color: #444; + color: var(--color-text-muted); } -.btn-stats-toggle:hover { background: #e2e8f0; } +.btn-stats-toggle:hover { background: var(--color-surface-alt); } .stats-days-select { font-size: 13px; } .audit-stats { - background: #f8fafc; - border: 1px solid #e2e8f0; + background: var(--color-surface-alt); + border: 1px solid var(--color-border); border-radius: 10px; padding: 16px; margin-bottom: 16px; } -.stats-loading { color: #888; font-size: 13px; padding: 8px 0; } +.stats-loading { color: var(--color-text-muted); font-size: 13px; padding: 8px 0; } .stats-row { display: flex; @@ -60,18 +60,18 @@ .stat-card { flex: 1; min-width: 100px; - background: white; + background: var(--color-surface); border-radius: 8px; padding: 12px 16px; text-align: center; - border: 1px solid #e2e8f0; + border: 1px solid var(--color-border); } .stat-number { font-size: 28px; font-weight: 700; line-height: 1; } -.stat-label { font-size: 11px; color: #666; margin-top: 4px; text-transform: uppercase; letter-spacing: 0.5px; } -.stat-total .stat-number { color: #1976d2; } -.stat-failed .stat-number { color: #c62828; } -.stat-success .stat-number { color: #2e7d32; } -.stat-period .stat-number { color: #555; font-size: 20px; } +.stat-label { font-size: 11px; color: var(--color-text-muted); margin-top: 4px; text-transform: uppercase; letter-spacing: 0.5px; } +.stat-total .stat-number { color: var(--color-info-text); } +.stat-failed .stat-number { color: var(--color-danger-text); } +.stat-success .stat-number { color: var(--color-success-text); } +.stat-period .stat-number { color: var(--color-text-muted); font-size: 20px; } .stats-details { display: flex; @@ -79,7 +79,7 @@ flex-wrap: wrap; } .stats-col { flex: 1; min-width: 180px; } -.stats-col h4 { margin: 0 0 8px 0; font-size: 12px; text-transform: uppercase; color: #888; letter-spacing: 0.5px; } +.stats-col h4 { margin: 0 0 8px 0; font-size: 12px; text-transform: uppercase; color: var(--color-text-muted); letter-spacing: 0.5px; } .stat-bar-row { display: flex; @@ -88,8 +88,8 @@ gap: 8px; margin-bottom: 5px; } -.stat-bar-label { font-size: 13px; color: #444; } -.stat-bar-count { font-size: 13px; font-weight: 600; color: #333; flex-shrink: 0; } +.stat-bar-label { font-size: 13px; color: var(--color-text-muted); } +.stat-bar-count { font-size: 13px; font-weight: 600; color: var(--color-text); flex-shrink: 0; } /* Mini bar chart */ .stats-chart-col { flex: 2; min-width: 220px; } @@ -98,7 +98,7 @@ align-items: flex-end; gap: 3px; height: 80px; - background: #f0f4f8; + background: var(--color-surface-alt); border-radius: 6px; padding: 6px 6px 0; } @@ -110,7 +110,7 @@ } .chart-bar { width: 100%; - background: #1976d2; + background: var(--color-info); border-radius: 2px 2px 0 0; position: relative; min-height: 4px; @@ -121,7 +121,7 @@ bottom: 0; left: 0; width: 100%; - background: #e53935; + background: var(--color-danger); } /* ── Filters ─────────────────────────────────────────────────────── */ @@ -134,52 +134,52 @@ } .filter-select { padding: 8px 12px; - border: 1.5px solid #d0d7de; + border: 1.5px solid var(--color-border); border-radius: 6px; font-size: 13px; - background: white; + background: var(--color-surface); cursor: pointer; } -.filter-select:focus { outline: none; border-color: #1976d2; } +.filter-select:focus { outline: none; border-color: var(--color-primary); } .filter-input { padding: 8px 12px; - border: 1.5px solid #d0d7de; + border: 1.5px solid var(--color-border); border-radius: 6px; font-size: 13px; - background: white; + background: var(--color-surface); min-width: 140px; } -.filter-input:focus { outline: none; border-color: #1976d2; } +.filter-input:focus { outline: none; border-color: var(--color-primary); } .filter-date { min-width: 130px; } .btn-refresh { padding: 8px 14px; - background: #1976d2; - color: white; + background: var(--color-info); + color: var(--color-on-info); border: none; border-radius: 6px; cursor: pointer; font-size: 13px; font-weight: 500; } -.btn-refresh:hover:not(:disabled) { background: #1565c0; } -.btn-refresh:disabled { background: #bdbdbd; cursor: not-allowed; } +.btn-refresh:hover:not(:disabled) { background: var(--color-info-dark); } +.btn-refresh:disabled { background: var(--color-surface-alt); color: var(--color-text-muted); cursor: not-allowed; } .btn-reset { padding: 8px 12px; - background: white; - color: #666; - border: 1.5px solid #d0d7de; + background: var(--color-surface); + color: var(--color-text-muted); + border: 1.5px solid var(--color-border); border-radius: 6px; cursor: pointer; font-size: 13px; } -.btn-reset:hover { background: #f5f5f5; } +.btn-reset:hover { background: var(--color-surface-alt); } .btn-export { padding: 8px 16px; - background: #2e7d32; - color: white; + background: var(--color-success); + color: var(--color-on-success); border: none; border-radius: 6px; cursor: pointer; @@ -187,15 +187,15 @@ font-weight: 500; white-space: nowrap; } -.btn-export:hover:not(:disabled) { background: #1b5e20; } -.btn-export:disabled { background: #bdbdbd; cursor: not-allowed; } +.btn-export:hover:not(:disabled) { background: var(--color-success-dark); } +.btn-export:disabled { background: var(--color-surface-alt); color: var(--color-text-muted); cursor: not-allowed; } .auto-refresh-toggle { display: flex; align-items: center; gap: 6px; font-size: 13px; - color: #555; + color: var(--color-text-muted); cursor: pointer; white-space: nowrap; } @@ -206,7 +206,7 @@ justify-content: space-between; align-items: center; font-size: 13px; - color: #666; + color: var(--color-text-muted); margin-bottom: 10px; } .limit-select { padding: 4px 8px; font-size: 13px; } @@ -224,16 +224,16 @@ } .badge-create { background: #e8f5e9; color: #2e7d32; } .badge-update { background: #e3f2fd; color: #1565c0; } -.badge-delete { background: #ffebee; color: #c62828; } -.badge-restore { background: #fff3e0; color: #e65100; } +.badge-delete { background: #ffebee; color: var(--color-danger-text); } +.badge-restore { background: #fff3e0; color: #a83a00; } .badge-login { background: #f3e5f5; color: #6a1b9a; } .badge-logout { background: #fce4ec; color: #880e4f; } .badge-login-failed { background: #ffcdd2; color: #b71c1c; font-weight: 700; } .badge-import { background: #e0f7fa; color: #00695c; } .badge-export { background: #e8f5e9; color: #1b5e20; } -.badge-bulk-update { background: #e8eaf6; color: #283593; } +.badge-bulk-update { background: var(--color-surface-alt); color: #283593; } .badge-bulk-delete { background: #fbe9e7; color: #bf360c; } -.badge-password { background: #fff8e1; color: #f57f17; } +.badge-password { background: #fff8e1; color: #9c4e00; } .badge-default { background: #f5f5f5; color: #616161; } .status-code { @@ -244,16 +244,16 @@ font-family: monospace; } .status-ok { background: #e8f5e9; color: #2e7d32; } -.status-redirect { background: #fff3e0; color: #e65100; } -.status-error { background: #ffebee; color: #c62828; } +.status-redirect { background: #fff3e0; color: #a83a00; } +.status-error { background: #ffebee; color: var(--color-danger-text); } .status-server-error { background: #f3e5f5; color: #6a1b9a; } .duration-badge { padding: 2px 8px; border-radius: 4px; font-size: 11px; - background: #f5f5f5; - color: #777; + background: var(--color-surface-alt); + color: var(--color-text-muted); font-family: monospace; } @@ -261,24 +261,24 @@ .audit-empty { text-align: center; padding: 40px; - background: #f9f9f9; + background: var(--color-surface-alt); border-radius: 8px; - color: #888; + color: var(--color-text-muted); } .audit-error { text-align: center; padding: 20px; } -.audit-error p { color: #d32f2f; margin: 0; } +.audit-error p { color: var(--color-danger-text); margin: 0; } .audit-list { display: flex; flex-direction: column; gap: 8px; } .audit-item { - background: white; - border: 1px solid #e0e0e0; + background: var(--color-surface); + border: 1px solid var(--color-border); border-radius: 8px; overflow: hidden; transition: box-shadow 0.15s; } .audit-item:hover { box-shadow: 0 2px 8px rgba(0,0,0,0.08); } -.audit-item-failed { border-left: 4px solid #e53935; } +.audit-item-failed { border-left: 4px solid var(--color-danger); } .audit-item-header { display: flex; @@ -286,18 +286,18 @@ gap: 8px; padding: 10px 14px; flex-wrap: wrap; - background: #fafafa; - border-bottom: 1px solid #f0f0f0; + background: var(--color-surface-alt); + border-bottom: 1px solid var(--color-border); } -.audit-time { margin-left: auto; color: #999; font-size: 12px; white-space: nowrap; } -.expand-toggle { color: #aaa; font-size: 11px; cursor: pointer; padding: 0 4px; } +.audit-time { margin-left: auto; color: var(--color-text-muted); font-size: 12px; white-space: nowrap; } +.expand-toggle { color: var(--color-text-muted); font-size: 11px; cursor: pointer; padding: 0 4px; } .audit-resource { padding: 3px 8px; - background: #f0f0f0; + background: var(--color-surface-alt); border-radius: 4px; font-size: 12px; - color: #555; + color: var(--color-text-muted); } .audit-item-body { @@ -308,16 +308,16 @@ font-size: 13px; align-items: center; } -.audit-admin { color: #333; } -.audit-resource-name { color: #555; } -.audit-ip { color: #999; font-family: monospace; font-size: 12px; } -.audit-failed-badge { color: #c62828; font-weight: 600; font-size: 12px; } +.audit-admin { color: var(--color-text); } +.audit-resource-name { color: var(--color-text-muted); } +.audit-ip { color: var(--color-text-muted); font-family: monospace; font-size: 12px; } +.audit-failed-badge { color: var(--color-danger-text); font-weight: 600; font-size: 12px; } /* ── Expanded detail ─────────────────────────────────────────────── */ .audit-item-detail { padding: 10px 14px 14px; - border-top: 1px dashed #e0e0e0; - background: #fefefe; + border-top: 1px dashed var(--color-border); + background: var(--color-surface); display: flex; flex-direction: column; gap: 8px; @@ -330,7 +330,7 @@ } .detail-label { font-weight: 600; - color: #888; + color: var(--color-text-muted); font-size: 11px; text-transform: uppercase; min-width: 70px; @@ -338,23 +338,23 @@ } .detail-row code { font-family: monospace; - background: #f0f0f0; + background: var(--color-surface-alt); padding: 2px 6px; border-radius: 3px; font-size: 12px; } .detail-ua-full { - color: #aaa; + color: var(--color-text-muted); cursor: help; font-size: 12px; } -.detail-error { color: #c62828; } -.detail-error .detail-label { color: #c62828; } +.detail-error { color: var(--color-danger-text); } +.detail-error .detail-label { color: var(--color-danger-text); } .meta-tag { display: inline-block; - background: #e8eaf6; - color: #283593; + background: var(--color-surface-alt); + color: var(--color-info-text); border-radius: 4px; padding: 2px 8px; font-size: 12px; @@ -370,17 +370,17 @@ margin-top: 6px; } .diff-table th { - background: #f0f0f0; + background: var(--color-surface-alt); padding: 5px 10px; text-align: left; font-size: 11px; text-transform: uppercase; - color: #666; - border: 1px solid #e0e0e0; + color: var(--color-text-muted); + border: 1px solid var(--color-border); } -.diff-table td { padding: 5px 10px; border: 1px solid #e8e8e8; vertical-align: top; } -.diff-field { font-weight: 600; color: #444; font-family: monospace; white-space: nowrap; background: #fafafa; } -.diff-before { color: #c62828; background: #fff5f5; font-family: monospace; word-break: break-all; } +.diff-table td { padding: 5px 10px; border: 1px solid var(--color-border); vertical-align: top; } +.diff-field { font-weight: 600; color: var(--color-text-muted); font-family: monospace; white-space: nowrap; background: var(--color-surface-alt); } +.diff-before { color: var(--color-danger-text); background: #fff5f5; font-family: monospace; word-break: break-all; } .diff-after { color: #2e7d32; background: #f5fff5; font-family: monospace; word-break: break-all; } /* ── Pagination ──────────────────────────────────────────────────── */ @@ -393,16 +393,16 @@ } .btn-page { padding: 7px 14px; - border: 1.5px solid #d0d7de; + border: 1.5px solid var(--color-border); border-radius: 6px; - background: white; + background: var(--color-surface); cursor: pointer; font-size: 13px; - color: #333; + color: var(--color-text); } -.btn-page:hover:not(:disabled) { background: #f0f4f8; border-color: #1976d2; } -.btn-page:disabled { color: #bbb; cursor: not-allowed; border-color: #eee; } -.page-info { font-size: 13px; color: #666; padding: 0 8px; } +.btn-page:hover:not(:disabled) { background: var(--color-surface-alt); border-color: var(--color-primary); } +.btn-page:disabled { color: var(--color-text-muted); cursor: not-allowed; border-color: var(--color-border); } +.page-info { font-size: 13px; color: var(--color-text-muted); padding: 0 8px; } .audit-header { @@ -411,13 +411,13 @@ .audit-header h2 { margin: 0 0 8px 0; - color: #333; + color: var(--color-text); font-size: 28px; } .audit-description { margin: 0; - color: #666; + color: var(--color-text-muted); font-size: 14px; } @@ -428,7 +428,7 @@ } .audit-error p { - color: #d32f2f; + color: var(--color-danger-text); margin: 0; } @@ -441,23 +441,23 @@ .filter-select { padding: 10px 14px; - border: 2px solid #e0e0e0; + border: 2px solid var(--color-border); border-radius: 6px; font-size: 14px; - background: white; + background: var(--color-surface); cursor: pointer; transition: border-color 0.2s; } .filter-select:focus { outline: none; - border-color: #1976d2; + border-color: var(--color-primary); } .btn-refresh { padding: 10px 16px; - background: #1976d2; - color: white; + background: var(--color-info); + color: var(--color-on-info); border: none; border-radius: 6px; cursor: pointer; @@ -467,20 +467,21 @@ } .btn-refresh:hover:not(:disabled) { - background: #1565c0; + background: var(--color-info-dark); } .btn-refresh:disabled { - background: #bdbdbd; + background: var(--color-surface-alt); + color: var(--color-text-muted); cursor: not-allowed; } .audit-empty { text-align: center; padding: 40px; - background: #f5f5f5; + background: var(--color-surface-alt); border-radius: 8px; - color: #666; + color: var(--color-text-muted); } .audit-list { @@ -490,8 +491,8 @@ } .audit-item { - background: white; - border: 1px solid #e0e0e0; + background: var(--color-surface); + border: 1px solid var(--color-border); border-radius: 8px; padding: 16px; transition: box-shadow 0.2s; @@ -519,58 +520,18 @@ gap: 4px; } -.badge-create { - background: #e8f5e9; - color: #2e7d32; -} - -.badge-update { - background: #e3f2fd; - color: #1565c0; -} - -.badge-delete { - background: #ffebee; - color: #c62828; -} - -.badge-restore { - background: #fff3e0; - color: #e65100; -} - -.badge-login { - background: #f3e5f5; - color: #6a1b9a; -} - -.badge-logout { - background: #fce4ec; - color: #880e4f; -} - -.badge-login-failed { - background: #ffcdd2; - color: #b71c1c; - font-weight: 700; -} - -.badge-default { - background: #f5f5f5; - color: #616161; -} .audit-resource { padding: 4px 10px; - background: #f5f5f5; + background: var(--color-surface-alt); border-radius: 4px; font-size: 13px; - color: #666; + color: var(--color-text-muted); } .audit-time { margin-left: auto; - color: #999; + color: var(--color-text-muted); font-size: 13px; } @@ -582,23 +543,19 @@ } .audit-admin { - color: #333; + color: var(--color-text); } .audit-resource-name { - color: #666; + color: var(--color-text-muted); } .audit-ip { - color: #888; + color: var(--color-text-muted); font-family: monospace; font-size: 13px; } -.audit-error-message { - color: #d32f2f; - font-weight: 500; -} .audit-pagination { display: flex; @@ -607,15 +564,15 @@ gap: 16px; margin-top: 24px; padding: 16px; - background: white; + background: var(--color-surface); border-radius: 8px; - border: 1px solid #e0e0e0; + border: 1px solid var(--color-border); } .btn-page { padding: 8px 16px; - background: #1976d2; - color: white; + background: var(--color-info); + color: var(--color-on-info); border: none; border-radius: 6px; cursor: pointer; @@ -624,16 +581,17 @@ } .btn-page:hover:not(:disabled) { - background: #1565c0; + background: var(--color-info-dark); } .btn-page:disabled { - background: #bdbdbd; + background: var(--color-surface-alt); + color: var(--color-text-muted); cursor: not-allowed; } .page-info { - color: #666; + color: var(--color-text-muted); font-size: 14px; } @@ -656,3 +614,33 @@ width: 100%; } } + +/* ── Nachtvariante ─────────────────────────────────────────────────────── + Die Badges kodieren die Aktionsart über den Farbton – der bleibt erhalten, + nur Helligkeit und Sättigung drehen sich um. Alle Paare >= 6.4:1. */ +@media (prefers-color-scheme: dark) { + .badge-create { background: #162d17; color: #97d99a; } + .badge-update { background: #16202d; color: #89b5e6; } + .badge-delete { background: #2d1616; color: #e68989; } + .badge-restore { background: #2d1e16; color: #e6aa89; } + .badge-login { background: #24162d; color: #c389e6; } + .badge-logout { background: #2d1622; color: #e689bb; } + .badge-login-failed { background: #2d1616; color: #e68989; } + .badge-import { background: #162d2a; color: #89e6db; } + .badge-export { background: #162d17; color: #90df96; } + .badge-bulk-update { background: #16182d; color: #8f99e0; } + .badge-bulk-delete { background: #2d1b16; color: #e69f89; } + .badge-password { background: #2d2016; color: #e6b589; } + .badge-default { background: var(--color-surface-alt); color: var(--color-text-muted); } + + .status-ok { background: #162d17; color: #97d99a; } + .status-redirect { background: #2d1e16; color: #e6aa89; } + .status-error { background: #2d1616; color: #e68989; } + .status-server-error { background: #24162d; color: #c389e6; } + + /* Diff-Tabelle: die roten/gruenen Vorher-Nachher-Felder */ + .diff-table th { background: var(--color-surface-alt); } + .diff-before { color: #e68989; background: #2d1616; } + .diff-after { color: #97d99a; background: #162d17; } + .diff-field { background: var(--color-surface-alt); color: var(--color-text); } +} diff --git a/nachsuche/frontend/src/components/admin/ExportButton.css b/nachsuche/frontend/src/components/admin/ExportButton.css index 83981da..c231346 100644 --- a/nachsuche/frontend/src/components/admin/ExportButton.css +++ b/nachsuche/frontend/src/components/admin/ExportButton.css @@ -14,7 +14,7 @@ .export-button { padding: 0.5rem 1rem; background: var(--color-success); - color: white; + color: var(--color-on-success); border: none; border-radius: var(--radius-sm); cursor: pointer; @@ -41,8 +41,8 @@ .import-button { padding: 0.5rem 1rem; - background: var(--color-primary, #2563eb); - color: white; + background: var(--color-primary, var(--color-info)); + color: var(--color-on-primary); border: none; border-radius: var(--radius-sm); cursor: pointer; @@ -52,7 +52,7 @@ } .import-button:hover:not(:disabled) { - background: var(--color-primary-dark, #1d4ed8); + background: var(--color-primary-dark, var(--color-info-dark)); } .import-button:disabled { @@ -65,7 +65,7 @@ align-items: center; gap: 0.4rem; font-size: 0.85rem; - color: var(--color-text-muted, #6b7280); + color: var(--color-text-muted); cursor: pointer; white-space: nowrap; } diff --git a/nachsuche/frontend/src/components/admin/Trash.css b/nachsuche/frontend/src/components/admin/Trash.css index 200c68a..e70ac72 100644 --- a/nachsuche/frontend/src/components/admin/Trash.css +++ b/nachsuche/frontend/src/components/admin/Trash.css @@ -10,13 +10,13 @@ .trash-header h2 { margin: 0 0 8px 0; - color: #333; + color: var(--color-text); font-size: 28px; } .trash-description { margin: 0; - color: #666; + color: var(--color-text-muted); font-size: 14px; } @@ -27,14 +27,14 @@ } .trash-error h3 { - color: #d32f2f; + color: var(--color-danger-text); margin-bottom: 12px; } .btn-retry { padding: 10px 20px; - background: #1976d2; - color: white; + background: var(--color-info); + color: var(--color-on-info); border: none; border-radius: 6px; cursor: pointer; @@ -43,13 +43,13 @@ } .btn-retry:hover { - background: #1565c0; + background: var(--color-info-dark); } .trash-empty { text-align: center; padding: 60px 20px; - background: #f5f5f5; + background: var(--color-surface-alt); border-radius: 12px; } @@ -60,7 +60,7 @@ } .trash-empty p { - color: #666; + color: var(--color-text-muted); font-size: 16px; margin: 0; } @@ -72,8 +72,8 @@ } .trash-item { - background: #fff; - border: 2px solid #e0e0e0; + background: var(--color-surface); + border: 2px solid var(--color-border); border-radius: 8px; padding: 16px 20px; display: flex; @@ -84,7 +84,7 @@ .trash-item:hover { box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); - border-color: #bdbdbd; + border-color: var(--color-border); } .trash-item-info { @@ -93,7 +93,7 @@ .trash-item-info h3 { margin: 0 0 8px 0; - color: #333; + color: var(--color-text); font-size: 18px; font-weight: 600; } @@ -106,8 +106,8 @@ } .trash-item-type { - background: #e3f2fd; - color: #1976d2; + background: var(--color-info-bg); + color: var(--color-info-text); padding: 4px 10px; border-radius: 4px; font-size: 13px; @@ -116,12 +116,12 @@ .trash-item-address, .trash-item-phone { - color: #666; + color: var(--color-text-muted); font-size: 14px; } .trash-item-meta { - color: #999; + color: var(--color-text-muted); font-size: 13px; } @@ -140,8 +140,8 @@ align-items: center; gap: 6px; padding: 10px 16px; - background: #4caf50; - color: white; + background: var(--color-success); + color: var(--color-on-success); border: none; border-radius: 6px; cursor: pointer; @@ -151,7 +151,7 @@ } .btn-restore:hover:not(:disabled) { - background: #45a049; + background: var(--color-success-dark); transform: translateY(-1px); } @@ -160,7 +160,7 @@ } .btn-restore:disabled { - background: #bdbdbd; + background: var(--color-border-strong); cursor: not-allowed; } diff --git a/nachsuche/frontend/src/components/auth/LoginForm.css b/nachsuche/frontend/src/components/auth/LoginForm.css index 1a38755..56024ab 100644 --- a/nachsuche/frontend/src/components/auth/LoginForm.css +++ b/nachsuche/frontend/src/components/auth/LoginForm.css @@ -56,7 +56,7 @@ width: 100%; padding: 0.75rem; background: var(--color-primary); - color: white; + color: var(--color-on-primary); border: none; border-radius: var(--radius-sm); font-size: 1rem; @@ -76,8 +76,8 @@ .login-error { padding: 0.75rem; - background: #ffebee; - border: 1px solid #ffcdd2; + background: var(--color-danger-bg); + border: 1px solid var(--color-danger-border); border-radius: var(--radius-sm); color: var(--color-danger); margin-bottom: 1rem; diff --git a/nachsuche/frontend/src/components/auth/PasswordReset.css b/nachsuche/frontend/src/components/auth/PasswordReset.css index cd3c067..4ee08d1 100644 --- a/nachsuche/frontend/src/components/auth/PasswordReset.css +++ b/nachsuche/frontend/src/components/auth/PasswordReset.css @@ -1,5 +1,6 @@ .password-reset-container { - min-height: 100vh; + /* dvh: mit ein- und ausblendender Adressleiste entsteht mit vh Überlauf. */ + min-height: 100dvh; display: flex; justify-content: center; align-items: center; @@ -8,7 +9,7 @@ } .password-reset-card { - background: white; + background: var(--color-surface); border-radius: 12px; box-shadow: 0 10px 40px rgba(0, 0, 0, 0.1); padding: 40px; @@ -18,7 +19,7 @@ .password-reset-card h2 { margin: 0 0 24px 0; - color: #333; + color: var(--color-text); font-size: 28px; text-align: center; } @@ -32,15 +33,15 @@ } .message.success { - background-color: #d4edda; - color: #155724; - border: 1px solid #c3e6cb; + background-color: var(--color-success-bg); + color: var(--color-success-text); + border: 1px solid var(--color-success-border); } .message.error { - background-color: #f8d7da; - color: #721c24; - border: 1px solid #f5c6cb; + background-color: var(--color-danger-bg); + color: var(--color-danger-text); + border: 1px solid var(--color-danger-border); } .form-group { @@ -50,7 +51,7 @@ .form-group label { display: block; margin-bottom: 8px; - color: #555; + color: var(--color-text-muted); font-weight: 500; font-size: 14px; } @@ -58,7 +59,7 @@ .form-group input { width: 100%; padding: 12px 16px; - border: 2px solid #e0e0e0; + border: 2px solid var(--color-border); border-radius: 8px; font-size: 15px; transition: border-color 0.3s; @@ -71,14 +72,14 @@ } .form-group input:disabled { - background-color: #f5f5f5; + background-color: var(--color-surface-alt); cursor: not-allowed; } .form-group small { display: block; margin-top: 6px; - color: #888; + color: var(--color-text-muted); font-size: 13px; } @@ -86,7 +87,7 @@ width: 100%; padding: 14px; background: var(--color-primary); - color: white; + color: var(--color-on-primary); border: none; border-radius: 8px; font-size: 16px; diff --git a/nachsuche/frontend/src/components/common/ErrorMessage.css b/nachsuche/frontend/src/components/common/ErrorMessage.css index 38733d8..efba2ba 100644 --- a/nachsuche/frontend/src/components/common/ErrorMessage.css +++ b/nachsuche/frontend/src/components/common/ErrorMessage.css @@ -4,10 +4,10 @@ gap: 0.5rem; padding: 1rem; margin: 1rem 0; - background-color: #fee; - border: 1px solid #fcc; + background-color: var(--color-danger-bg); + border: 1px solid var(--color-danger-border); border-radius: 4px; - color: #c33; + color: var(--color-danger-text); } .error-icon { @@ -22,7 +22,7 @@ background: none; border: none; font-size: 1.5rem; - color: #c33; + color: var(--color-danger-text); cursor: pointer; padding: 0; width: 24px; @@ -34,5 +34,5 @@ } .error-close:hover { - color: #a22; + color: var(--color-danger-text); } diff --git a/nachsuche/frontend/src/components/common/Header.css b/nachsuche/frontend/src/components/common/Header.css index 69a023f..dd3e83d 100644 --- a/nachsuche/frontend/src/components/common/Header.css +++ b/nachsuche/frontend/src/components/common/Header.css @@ -1,6 +1,6 @@ .app-header { - background: #ffffff; - border-bottom: 1px solid #e5e5e5; + background: var(--color-surface); + border-bottom: 1px solid var(--color-border); padding: 0.75rem 2rem; display: flex; align-items: center; @@ -27,7 +27,7 @@ .portal-back-link:hover { background: var(--color-primary); - color: #fff; + color: var(--color-on-primary); } .app-brand { @@ -40,18 +40,18 @@ height: 52px; width: auto; object-fit: contain; -} - -.app-logo-ljn { - height: 44px; + flex-shrink: 0; } .app-title { margin: 0; + font-family: var(--font-display); font-size: 1.05rem; font-weight: 700; color: var(--color-text); - white-space: nowrap; + /* Kein nowrap: lange App-Namen haben die Kopfzeile sonst über die + Bildschirmbreite hinaus geschoben. */ + overflow-wrap: anywhere; } .app-nav { @@ -61,11 +61,14 @@ } .nav-button { + display: inline-flex; + align-items: center; + min-height: var(--touch-target); padding: 0.5rem 0.875rem; background: none; border: none; border-radius: var(--radius-sm); - color: #333; + color: var(--color-text); cursor: pointer; font-size: 0.9rem; font-weight: 500; @@ -97,12 +100,19 @@ .app-header { flex-direction: column; align-items: flex-start; - padding: 0.75rem 1rem; - gap: 0.5rem; + padding: 0.5rem 1rem; + gap: 0.4rem; + /* Auf schmalen Geräten nimmt die umgebrochene Kopfzeile viel Höhe ein. + Klebrig bleibt sie nur dort, wo genug Platz ist. */ + position: static; } .app-title { - font-size: 0.9rem; + font-size: 0.95rem; + } + + .app-logo { + height: 36px; } .app-nav { @@ -111,7 +121,31 @@ } .nav-button { - font-size: 0.85rem; + font-size: 0.9rem; padding: 0.4rem 0.7rem; } } + +@media (max-width: 480px) { + .app-header { + padding: 0.5rem 0.75rem; + } + + .app-brand { + gap: 0.5rem; + } + + .app-logo { + height: 30px; + } + + .app-nav { + width: 100%; + } + + .nav-button { + flex: 1 1 45%; + justify-content: center; + padding: 0.4rem 0.5rem; + } +} diff --git a/nachsuche/frontend/src/components/common/InstallBanner.css b/nachsuche/frontend/src/components/common/InstallBanner.css index f5b248d..0ab554a 100644 --- a/nachsuche/frontend/src/components/common/InstallBanner.css +++ b/nachsuche/frontend/src/components/common/InstallBanner.css @@ -2,8 +2,8 @@ position: sticky; top: 0; z-index: 1000; - background-color: #2d6a2d; - color: #fff; + background-color: var(--color-primary); + color: var(--color-on-primary); box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3); } @@ -22,8 +22,8 @@ } .install-banner__btn { - background: #fff; - color: #2d6a2d; + background: var(--color-surface); + color: var(--color-primary); border: none; border-radius: 4px; padding: 0.35rem 0.85rem; @@ -34,7 +34,7 @@ } .install-banner__btn:hover { - background: #e8f5e9; + background: var(--color-success-bg); } .install-banner__close { @@ -49,7 +49,7 @@ } .install-banner__close:hover { - color: #fff; + color: var(--color-on-primary); } .install-banner__share-icon { diff --git a/nachsuche/frontend/src/components/common/Loading.css b/nachsuche/frontend/src/components/common/Loading.css index ec8df60..e1dbe74 100644 --- a/nachsuche/frontend/src/components/common/Loading.css +++ b/nachsuche/frontend/src/components/common/Loading.css @@ -8,8 +8,8 @@ } .spinner { - border: 4px solid #f3f3f3; - border-top: 4px solid #3498db; + border: 4px solid var(--color-border); + border-top: 4px solid var(--color-primary); border-radius: 50%; width: 50px; height: 50px; @@ -23,6 +23,6 @@ .loading-message { margin-top: 1rem; - color: #666; + color: var(--color-text-muted); font-size: 0.9rem; } diff --git a/nachsuche/frontend/src/components/handler/HandlerDashboard.css b/nachsuche/frontend/src/components/handler/HandlerDashboard.css index 5078c48..7ebe76d 100644 --- a/nachsuche/frontend/src/components/handler/HandlerDashboard.css +++ b/nachsuche/frontend/src/components/handler/HandlerDashboard.css @@ -5,7 +5,7 @@ } .handler-dashboard-card { - background: white; + background: var(--color-surface); border-radius: 10px; padding: 2rem; width: 100%; @@ -46,7 +46,7 @@ .btn-handler-logout:hover { background: var(--color-danger); - color: white; + color: var(--color-on-danger); } .handler-message { @@ -56,8 +56,8 @@ font-size: 0.9rem; } -.handler-message-success { background: #dcfce7; color: #166534; } -.handler-message-error { background: #fee2e2; color: #b91c1c; } +.handler-message-success { background: var(--color-success-bg); color: var(--color-success-text); } +.handler-message-error { background: var(--color-danger-bg); color: var(--color-danger-text); } .handler-availability-section { background: var(--color-muted-bg); @@ -92,15 +92,15 @@ .availability-big-btn:disabled { opacity: 0.6; cursor: not-allowed; } .btn-green { - background: #dcfce7; - color: #15803d; - border-color: #86efac; + background: var(--color-success-bg); + color: var(--color-success-text); + border-color: var(--color-success-border); } .btn-red { - background: #fee2e2; - color: #b91c1c; - border-color: #fca5a5; + background: var(--color-danger-bg); + color: var(--color-danger-text); + border-color: var(--color-danger-border); } .status-dot-lg { @@ -110,8 +110,8 @@ flex-shrink: 0; } -.dot-green { background: #22c55e; } -.dot-red { background: #ef4444; } +.dot-green { background: var(--color-success); } +.dot-red { background: var(--color-danger); } .availability-hint { font-size: 0.82rem; @@ -147,7 +147,7 @@ font-size: 0.9rem; } -.btn-handler-edit:hover { background: var(--color-primary); color: white; } +.btn-handler-edit:hover { background: var(--color-primary); color: var(--color-on-primary); } .handler-info-list { display: flex; flex-direction: column; gap: 0.6rem; } @@ -206,7 +206,7 @@ flex: 1; padding: 0.65rem; background: var(--color-primary); - color: white; + color: var(--color-on-primary); border: none; border-radius: 6px; font-size: 0.95rem; diff --git a/nachsuche/frontend/src/components/handler/HandlerLogin.css b/nachsuche/frontend/src/components/handler/HandlerLogin.css index 6715730..65680ad 100644 --- a/nachsuche/frontend/src/components/handler/HandlerLogin.css +++ b/nachsuche/frontend/src/components/handler/HandlerLogin.css @@ -6,7 +6,7 @@ } .handler-login-card { - background: white; + background: var(--color-surface); border-radius: 10px; padding: 2rem; width: 100%; @@ -48,7 +48,7 @@ .handler-mode-toggle button.active { background: var(--color-primary); - color: white; + color: var(--color-on-primary); font-weight: 600; } @@ -82,7 +82,7 @@ width: 100%; padding: 0.75rem; background: var(--color-primary); - color: white; + color: var(--color-on-primary); border: none; border-radius: 6px; font-size: 1rem; @@ -102,8 +102,8 @@ } .handler-error { - background: #fee2e2; - color: #b91c1c; + background: var(--color-danger-bg); + color: var(--color-danger-text); border-radius: 4px; padding: 0.6rem 0.9rem; margin-bottom: 1rem; @@ -111,8 +111,8 @@ } .handler-success { - background: #dcfce7; - color: #166534; + background: var(--color-success-bg); + color: var(--color-success-text); border-radius: 4px; padding: 0.6rem 0.9rem; margin-bottom: 1rem; diff --git a/nachsuche/frontend/src/components/map/MapView.css b/nachsuche/frontend/src/components/map/MapView.css index bfb9cff..6e82ee3 100644 --- a/nachsuche/frontend/src/components/map/MapView.css +++ b/nachsuche/frontend/src/components/map/MapView.css @@ -13,32 +13,32 @@ left: 12px; z-index: 500; background: rgba(255, 255, 255, 0.95); - color: #444; + color: var(--color-text-muted); padding: 0.45rem 0.7rem; border-radius: 6px; font-size: 0.85rem; - border: 1px solid #dcdcdc; + border: 1px solid var(--color-border); } .map-no-data { padding: 3rem; text-align: center; - color: #666; - background: white; + color: var(--color-text-muted); + background: var(--color-surface); border-radius: 8px; margin: 1rem 0; } .map-popup h3 { margin: 0 0 0.5rem 0; - color: #333; + color: var(--color-text); font-size: 1rem; } .map-popup p { margin: 0.25rem 0; font-size: 0.85rem; - color: #666; + color: var(--color-text-muted); } .map-popup a { @@ -54,8 +54,40 @@ display: inline-block; padding: 0.2rem 0.5rem; background: var(--color-primary); - color: white; + color: var(--color-on-primary); border-radius: 4px; font-size: 0.75rem; margin-top: 0.5rem; } + +/* ── Nachtansicht ──────────────────────────────────────────────────────── + Die OSM-Kacheln sind immer taghell. In der Dämmerung ist die Karte damit + die mit Abstand hellste Fläche der App und blendet — genau die Situation, + in der Nachsuchen stattfinden. Die Kacheln werden deshalb abgedunkelt; + Marker und Bedienelemente bleiben unangetastet, damit sie lesbar sind. */ +@media (prefers-color-scheme: dark) { + .leaflet-tile-pane { + filter: brightness(0.62) saturate(0.75) contrast(1.05); + } + + .leaflet-container { + background: var(--color-surface-alt); + } + + /* Hoehere Spezifitaet als Leaflets eigene Regeln, die spaeter geladen werden */ + .leaflet-container .leaflet-control-zoom a, + .leaflet-container .leaflet-control-attribution { + background: var(--color-surface); + color: var(--color-text); + } + + .leaflet-container .leaflet-control-attribution a { + color: var(--color-primary); + } + + .leaflet-popup-content-wrapper, + .leaflet-popup-tip { + background: var(--color-surface); + color: var(--color-text); + } +} diff --git a/nachsuche/frontend/src/components/public/PublicUserList.css b/nachsuche/frontend/src/components/public/PublicUserList.css index c24d538..1eb3efd 100644 --- a/nachsuche/frontend/src/components/public/PublicUserList.css +++ b/nachsuche/frontend/src/components/public/PublicUserList.css @@ -14,7 +14,7 @@ } .public-user-list h2 { - color: #1a1a1a; + color: var(--color-text); margin: 0; font-size: 1.5rem; font-weight: 700; @@ -23,7 +23,7 @@ .toggle-map-button { padding: 0.5rem 1rem; background: var(--color-primary); - color: white; + color: var(--color-on-primary); border: none; border-radius: 4px; cursor: pointer; @@ -44,8 +44,8 @@ .filter-toggle-button { padding: 0.5rem 1rem; - background: #6c757d; - color: white; + background: var(--color-secondary); + color: var(--color-on-secondary); border: none; border-radius: 4px; cursor: pointer; @@ -55,12 +55,12 @@ } .filter-toggle-button:hover { - background: #5a6268; + background: var(--color-secondary-dark); } .location-panel { - background: white; - border: 1px solid #e5e5e5; + background: var(--color-surface); + border: 1px solid var(--color-border); border-radius: 8px; padding: 1rem 1.5rem; margin-bottom: 1.5rem; @@ -78,7 +78,7 @@ .location-button { padding: 0.5rem 1rem; background: var(--color-primary); - color: white; + color: var(--color-on-primary); border: none; border-radius: 4px; cursor: pointer; @@ -92,7 +92,7 @@ } .location-button:disabled { - background: #b6b6b6; + background: var(--color-border-strong); cursor: not-allowed; } @@ -103,13 +103,13 @@ } .location-status.success { - background: #e8f5e9; - color: var(--color-primary-dark); + background: var(--color-success-bg); + color: var(--color-success-text); } .location-status.error { - background: #ffebee; - color: #c62828; + background: var(--color-danger-bg); + color: var(--color-danger-text); } .postal-search { @@ -120,21 +120,21 @@ .postal-search input[type="text"] { padding: 0.5rem; - border: 1px solid #ddd; + border: 1px solid var(--color-border); border-radius: 4px; font-size: 0.9rem; width: 150px; } .postal-search input[type="text"]:disabled { - background: #f5f5f5; + background: var(--color-surface-alt); cursor: not-allowed; } .postal-search button { padding: 0.5rem 1rem; background: var(--color-primary); - color: white; + color: var(--color-on-primary); border: none; border-radius: 4px; cursor: pointer; @@ -148,14 +148,14 @@ } .postal-search button:disabled { - background: #b6b6b6; + background: var(--color-border-strong); cursor: not-allowed; } .radius-filter label { display: block; font-size: 0.9rem; - color: #555; + color: var(--color-text-muted); margin-bottom: 0.5rem; font-weight: 500; } @@ -174,26 +174,26 @@ .radius-inputs input[type="number"] { width: 80px; padding: 0.4rem 0.5rem; - border: 1px solid #ddd; + border: 1px solid var(--color-border); border-radius: 4px; font-size: 0.9rem; } .radius-inputs input:disabled { - background: #f5f5f5; + background: var(--color-surface-alt); cursor: not-allowed; } .radius-hint { font-size: 0.85rem; - color: #777; + color: var(--color-text-muted); margin-top: 0.5rem; } .gps-hint { margin-top: 0.5rem; font-size: 0.85rem; - color: #777; + color: var(--color-text-muted); } .user-grid { @@ -205,8 +205,8 @@ /* Jägerschaft-style card */ .user-card { - background: white; - border: 1px solid #e5e5e5; + background: var(--color-surface); + border: 1px solid var(--color-border); border-radius: 8px; padding: 1.5rem; box-shadow: 0 2px 6px rgba(0, 0, 0, 0.06); @@ -232,9 +232,9 @@ box-shadow: 0 6px 16px rgba(0, 0, 0, 0.1); } -.user-name { +.public-user-list .user-name { margin: 0 0 0.2rem; - color: #1a1a1a; + color: var(--color-text); font-size: 1rem; font-weight: 700; text-transform: uppercase; @@ -250,15 +250,15 @@ color: var(--color-primary); } -.user-info { +.public-user-list .user-info { display: flex; flex-direction: column; gap: 0.375rem; } -.user-address { +.public-user-list .user-address { margin: 0; - color: #666; + color: var(--color-text-muted); font-size: 0.9rem; } @@ -266,72 +266,80 @@ margin: 0.5rem 0 0; } -.type-badge { +.public-user-list .type-badge { display: inline-block; padding: 0.2rem 0.6rem; - background: #f0f0f0; - color: #444; + background: var(--color-surface-alt); + color: var(--color-text-muted); border-radius: 4px; font-size: 0.8rem; font-weight: 600; letter-spacing: 0.03em; } +/* Der Anruf beim Nachsuchenführer ist der Zweck dieser Liste und wird fast + immer mit dem Daumen auf dem Handy ausgelöst. Vorher war das ein 14 px hoher + Textlink; jetzt ein vollwertiges Ziel mit der empfohlenen Mindesthöhe. */ .user-phone { + display: flex; + align-items: center; + gap: 0.5rem; + min-height: var(--touch-target); + margin: 0.15rem 0; + padding: 0.35rem 0.6rem; + background: var(--color-surface-alt); + border: 1px solid var(--color-border); + border-radius: var(--radius-sm); color: var(--color-primary); text-decoration: none; - font-weight: 500; - font-size: 0.9rem; + font-weight: 600; + font-size: 1rem; } -.user-phone:hover { +.public-user-list .user-phone:hover, +.public-user-list .user-phone:focus-visible { + background: var(--color-surface); + border-color: var(--color-border-strong); text-decoration: underline; } -.user-gps { - margin-top: 1rem; - padding-top: 1rem; - border-top: 1px solid #e5e5e5; - font-size: 0.85rem; - color: #888; -} .user-distance { margin-top: 0.75rem; padding-top: 0.75rem; - border-top: 1px solid #e5e5e5; + border-top: 1px solid var(--color-border); font-size: 0.85rem; - color: #555; + color: var(--color-text-muted); font-weight: 500; } .no-users { text-align: center; padding: 3rem; - color: #666; + color: var(--color-text-muted); } .loading { text-align: center; padding: 3rem; - color: #666; + color: var(--color-text-muted); } @media (max-width: 768px) { - .user-grid { +.user-grid { grid-template-columns: 1fr; } - .public-user-list { +.public-user-list { padding: 1rem; } - .radius-inputs { +.radius-inputs { flex-direction: column; align-items: stretch; } - .radius-inputs input[type="number"] { +.radius-inputs input[type="number"] { width: 100%; } } diff --git a/nachsuche/frontend/src/components/public/RulesDisplay.css b/nachsuche/frontend/src/components/public/RulesDisplay.css index 32be9b6..4ec7a73 100644 --- a/nachsuche/frontend/src/components/public/RulesDisplay.css +++ b/nachsuche/frontend/src/components/public/RulesDisplay.css @@ -33,7 +33,7 @@ } .allgemeines-tab-btn.active { - background: white; + background: var(--color-surface); color: var(--color-primary); font-weight: 700; border-color: var(--color-primary); @@ -41,7 +41,7 @@ } .allgemeines-content { - background: white; + background: var(--color-surface); border: 1px solid var(--color-primary); border-top: none; border-radius: 0 0 8px 8px; diff --git a/nachsuche/frontend/src/components/users/UserCard.css b/nachsuche/frontend/src/components/users/UserCard.css index a6f6bb7..2c62fa9 100644 --- a/nachsuche/frontend/src/components/users/UserCard.css +++ b/nachsuche/frontend/src/components/users/UserCard.css @@ -25,7 +25,7 @@ border-bottom: 1px solid var(--color-border); } -.user-name-row { +.user-card-admin .user-name-row { display: flex; align-items: center; gap: 0.5rem; @@ -39,10 +39,10 @@ box-shadow: 0 0 4px rgba(0,0,0,0.2); } -.dot-green { background: #22c55e; } -.dot-red { background: #ef4444; } +.dot-green { background: var(--color-success); } +.dot-red { background: var(--color-danger); } -.user-name { +.user-card-admin .user-name { margin: 0; color: var(--color-text); font-size: 1.2rem; @@ -67,40 +67,40 @@ font-weight: 600; } -.label-green { color: #16a34a; } -.label-red { color: var(--color-danger); } +.label-green { color: var(--color-success); } +.label-red { color: var(--color-danger); } -.user-info { +.user-card-admin .user-info { display: flex; flex-direction: column; gap: 0.5rem; margin-bottom: 1rem; } -.user-address { +.user-card-admin .user-address { margin: 0; color: var(--color-text-muted); font-size: 0.9rem; } -.type-badge { +.user-card-admin .type-badge { display: inline-block; padding: 0.25rem 0.75rem; background: var(--color-primary); - color: white; + color: var(--color-on-primary); border-radius: var(--radius-pill); font-size: 0.85rem; font-weight: 500; } -.user-phone { +.user-card-admin .user-phone { color: var(--color-primary); text-decoration: none; font-weight: 500; font-size: 1rem; } -.user-phone:hover { +.user-card-admin .user-phone:hover { text-decoration: underline; } @@ -183,7 +183,7 @@ .edit-gps-button { padding: 0.25rem 0.75rem; background: var(--color-primary); - color: white; + color: var(--color-on-primary); border: none; border-radius: var(--radius-sm); cursor: pointer; @@ -229,7 +229,7 @@ .save-gps-button { background: var(--color-success); - color: white; + color: var(--color-on-success); } .save-gps-button:hover:not(:disabled) { @@ -243,7 +243,7 @@ .cancel-gps-button { background: var(--color-secondary); - color: white; + color: var(--color-on-secondary); } .cancel-gps-button:hover { @@ -272,7 +272,7 @@ .edit-button { background: var(--color-primary); - color: white; + color: var(--color-on-primary); } .edit-button:hover { @@ -281,7 +281,7 @@ .delete-button { background: var(--color-danger); - color: white; + color: var(--color-on-danger); } .delete-button:hover { @@ -289,17 +289,17 @@ } @media (max-width: 768px) { - .user-header { +.user-header { flex-direction: column; align-items: flex-start; gap: 0.5rem; } - .gps-inputs { +.gps-inputs { flex-direction: column; } - .card-actions { +.card-actions { flex-direction: column; } } @@ -322,7 +322,7 @@ display: block; margin-top: 0.35rem; padding: 0.4rem 0.5rem; - background: var(--color-bg-muted, #f2f2ec); + background: var(--color-surface-alt); border: 1px solid var(--color-border); border-radius: 2px; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; diff --git a/nachsuche/frontend/src/components/users/UserForm.css b/nachsuche/frontend/src/components/users/UserForm.css index 474c2a3..e3e62df 100644 --- a/nachsuche/frontend/src/components/users/UserForm.css +++ b/nachsuche/frontend/src/components/users/UserForm.css @@ -91,7 +91,7 @@ top: 100%; left: 0; right: 0; - background: white; + background: var(--color-surface); border: 1px solid var(--color-border-strong); border-top: none; border-radius: 0 0 var(--radius-sm) var(--radius-sm); @@ -163,7 +163,7 @@ .btn-primary { background: var(--color-primary); - color: white; + color: var(--color-on-primary); } .btn-primary:hover { @@ -172,7 +172,7 @@ .btn-secondary { background: var(--color-secondary); - color: white; + color: var(--color-on-secondary); } .btn-secondary:hover { diff --git a/nachsuche/frontend/src/components/users/UserList.css b/nachsuche/frontend/src/components/users/UserList.css index 4dd50f4..03ceb1a 100644 --- a/nachsuche/frontend/src/components/users/UserList.css +++ b/nachsuche/frontend/src/components/users/UserList.css @@ -34,7 +34,7 @@ .create-button { padding: 0.5rem 1rem; background: var(--color-success); - color: white; + color: var(--color-on-success); border: none; border-radius: var(--radius-sm); cursor: pointer; diff --git a/nachsuche/frontend/src/index.css b/nachsuche/frontend/src/index.css index ec2585e..a76866f 100644 --- a/nachsuche/frontend/src/index.css +++ b/nachsuche/frontend/src/index.css @@ -1,13 +1,8 @@ -body { - margin: 0; - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', - 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', - sans-serif; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - -code { - font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', - monospace; +/* Basisstile stehen in App.css, wo auch die Design-Tokens definiert sind. + Hier stand vorher eine zweite body-Regel, die von App.css vollständig + überschrieben wurde. */ +html { + /* Verhindert, dass iOS beim Drehen die Schrift eigenmächtig vergrößert. */ + -webkit-text-size-adjust: 100%; + text-size-adjust: 100%; } diff --git a/portal/index.html b/portal/index.html index aca5737..ccf4f6d 100644 --- a/portal/index.html +++ b/portal/index.html @@ -3,7 +3,7 @@ - + diff --git a/portal/manifest.json b/portal/manifest.json index 883c36c..9f6c7a2 100644 --- a/portal/manifest.json +++ b/portal/manifest.json @@ -31,7 +31,7 @@ "scope": "/", "display": "standalone", "orientation": "portrait", - "theme_color": "#2d6a2d", - "background_color": "#ffffff", + "theme_color": "#1a3d1a", + "background_color": "#e8e8e2", "description": "Jagd Apps Heidekreis – Übersicht aller Apps" } diff --git a/portal/offline.html b/portal/offline.html index 6e27ceb..b1c4d55 100644 --- a/portal/offline.html +++ b/portal/offline.html @@ -3,29 +3,91 @@ - Offline – Jagd Apps + + Offline – Jagd Apps Heidekreis -
📡
-

Keine Verbindung

-

Bitte prüfen Sie Ihre Internetverbindung und laden Sie die Seite neu.

+
+ +

Keine Verbindung

+

+ Im Funkloch sind die zuletzt geladenen Daten nicht verfügbar. + Sobald wieder Empfang besteht, lädt die Seite normal. +

+ +
diff --git a/stoeberhunde/frontend/index.html b/stoeberhunde/frontend/index.html index 2171d6b..808a918 100644 --- a/stoeberhunde/frontend/index.html +++ b/stoeberhunde/frontend/index.html @@ -5,7 +5,7 @@ - + diff --git a/stoeberhunde/frontend/public/logo-fallingbostel.png b/stoeberhunde/frontend/public/logo-fallingbostel.png deleted file mode 100644 index bf3e426..0000000 Binary files a/stoeberhunde/frontend/public/logo-fallingbostel.png and /dev/null differ diff --git a/stoeberhunde/frontend/public/logo-ljn.png b/stoeberhunde/frontend/public/logo-ljn.png deleted file mode 100644 index a1a6ce9..0000000 Binary files a/stoeberhunde/frontend/public/logo-ljn.png and /dev/null differ diff --git a/stoeberhunde/frontend/public/manifest.json b/stoeberhunde/frontend/public/manifest.json index e993e21..cdfd13f 100644 --- a/stoeberhunde/frontend/public/manifest.json +++ b/stoeberhunde/frontend/public/manifest.json @@ -19,7 +19,7 @@ "scope": "/stoeberhunde/", "display": "standalone", "orientation": "portrait", - "theme_color": "#2d6a2d", - "background_color": "#ffffff", + "theme_color": "#1a3d1a", + "background_color": "#e8e8e2", "description": "Stöberhunde Heidekreis – Übersicht der Stöberhundleiter" } diff --git a/stoeberhunde/frontend/public/offline.html b/stoeberhunde/frontend/public/offline.html index 6e5c44b..b1c4d55 100644 --- a/stoeberhunde/frontend/public/offline.html +++ b/stoeberhunde/frontend/public/offline.html @@ -1,16 +1,93 @@ - + - - - Offline - Stöberhundeführer - + + + + Offline – Jagd Apps Heidekreis + -

Du bist offline

-

Die App ist derzeit nicht verfügbar. Bitte überprüfe deine Internetverbindung.

+
+ +

Keine Verbindung

+

+ Im Funkloch sind die zuletzt geladenen Daten nicht verfügbar. + Sobald wieder Empfang besteht, lädt die Seite normal. +

+ +
- \ No newline at end of file + diff --git a/stoeberhunde/frontend/src/App.css b/stoeberhunde/frontend/src/App.css index b8f3ffe..b3a77b8 100644 --- a/stoeberhunde/frontend/src/App.css +++ b/stoeberhunde/frontend/src/App.css @@ -2,43 +2,203 @@ box-sizing: border-box; } +/* ────────────────────────────────────────────────────────────────────────── + Design-Tokens — einzige Farbquelle der App. + Palette und Formensprache folgen dem Portal (portal/index.html), damit der + Wechsel vom Portal in eine App nicht wie ein Produktwechsel wirkt. + Schriftmodell wie im Portal: Serif für die Marken-/Überschriftenebene, + Sans für funktionale UI-Texte (auf kleinen Displays besser lesbar). + + Alle Textpaare erfüllen WCAG AA (>= 4.5:1), funktionale Rahmen >= 3.0:1 — + in beiden Varianten nachgerechnet. + ────────────────────────────────────────────────────────────────────────── */ :root { - --color-primary: #2e8b2e; - --color-primary-dark: #1e6b1e; - --color-primary-accent: #8B0D12; - --color-secondary: #6c757d; - --color-secondary-dark: #5a6268; - --color-success: #28a745; - --color-success-dark: #218838; - --color-danger: #dc3545; - --color-danger-dark: #c82333; - --color-bg: #f5f5f0; - --color-surface: #ffffff; + --font-display: Georgia, 'Times New Roman', serif; + --font-ui: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', + 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif; + --font-mono: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', monospace; + + /* Flächen */ + --color-bg: #e8e8e2; + --color-surface: #f4f4ee; + --color-surface-alt: #dedcd2; + --color-muted-bg: #dedcd2; + + /* Text */ --color-text: #1a1a1a; - --color-text-muted: #555; - --color-border: #b8d4b8; - --color-border-strong: #88b888; - --color-focus: rgba(46, 139, 46, 0.2); - --color-muted-bg: #f5f5f0; - --shadow-sm: 0 2px 4px rgba(0, 0, 0, 0.1); - --shadow-md: 0 4px 8px rgba(0, 0, 0, 0.2); - --radius-sm: 4px; - --radius-md: 8px; - --radius-pill: 12px; + --color-text-muted: #55554c; + + /* Rahmen: -border ist dekorativ (Trennlinien, Karten), + -border-strong begrenzt Bedienelemente und erfüllt die 3:1-Anforderung. */ + --color-border: #c9c9b8; + --color-border-strong: #7d7d68; + + /* Aktionsfarben – jeweils mit der zugehörigen Textfarbe, damit die + Dunkelvariante nicht auf weißem Text auf hellem Grund landet. */ + --color-primary: #2d5a2d; + --color-primary-dark: #1a3d1a; + --color-on-primary: #ffffff; + --color-secondary: #5c5c50; + --color-secondary-dark: #46463c; + --color-on-secondary: #ffffff; + --color-success: #1f6b34; + --color-success-dark: #175128; + --color-on-success: #ffffff; + --color-danger: #a32020; + --color-danger-dark: #821919; + --color-on-danger: #ffffff; + --color-warning: #7a5200; + --color-on-warning: #ffffff; + --color-accent: #8b0d12; + --color-on-accent: #ffffff; + /* Altname, wird von RulesDisplay noch benutzt */ + --color-primary-accent: #8b0d12; + + /* Getönte Status-Flächen (Meldungen, Badges, Zustands-Karten). + Der Block wird durch seine Füllung erkannt, der Rahmen ist Zierde. */ + --color-success-bg: #dfeedd; + --color-success-border: #a9cba4; + --color-success-text: #1a4a24; + --color-danger-bg: #f6e0e0; + --color-danger-border: #d9a9a9; + --color-danger-text: #7d1a1a; + --color-warning-bg: #f7edd4; + --color-warning-border: #d9c48a; + --color-warning-text: #5c3d00; + --color-info: #24608f; + --color-info-dark: #1b4a6e; + --color-on-info: #ffffff; + --color-info-bg: #dde8f1; + --color-info-border: #a5bfd4; + --color-info-text: #14405f; + + /* Als RGB-Tripel fuer rgba()-Anwendungen (Puls-Animation im Admin-Panel) */ + --color-primary-rgb: 45, 90, 45; + + --color-focus: rgba(45, 90, 45, 0.35); + + --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.15); + --shadow-md: 0 2px 6px rgba(0, 0, 0, 0.2); + + /* Kantige Ecken wie im Portal */ + --radius-sm: 2px; + --radius-md: 2px; + --radius-pill: 2px; + --space-1: 0.5rem; --space-2: 1rem; --space-3: 1.5rem; --space-4: 2rem; + + /* Mindestgröße für Bedienelemente auf Touchgeräten */ + --touch-target: 44px; } +/* Nachtvariante. Nachsuchen laufen in der Dämmerung und nachts — ein weißes + Vollbild blendet dann und kostet die Dunkeladaption der Augen. Warme, sehr + dunkle Grüntöne statt reinem Schwarz. */ +@media (prefers-color-scheme: dark) { + :root { + --color-bg: #14180f; + --color-surface: #1e241a; + --color-surface-alt: #2a3124; + --color-muted-bg: #2a3124; + + --color-text: #e9e7dd; + --color-text-muted: #a6a698; + + --color-border: #333b28; + --color-border-strong: #758566; + + --color-primary: #7fb36f; + --color-primary-dark: #9ccb8c; + --color-on-primary: #10140c; + --color-secondary: #8d8d80; + --color-secondary-dark: #a3a396; + --color-on-secondary: #10140c; + --color-success: #79c48c; + --color-success-dark: #93d3a3; + --color-on-success: #10140c; + --color-danger: #ea8b8b; + --color-danger-dark: #f2a5a5; + --color-on-danger: #10140c; + --color-warning: #d6b25f; + --color-on-warning: #10140c; + --color-accent: #e88a8f; + --color-on-accent: #10140c; + --color-primary-accent: #e88a8f; + + --color-success-bg: #1d2c20; + --color-success-border: #3d5c43; + --color-success-text: #93d3a3; + --color-danger-bg: #33201f; + --color-danger-border: #6b4040; + --color-danger-text: #f2a5a5; + --color-warning-bg: #322a15; + --color-warning-border: #63552c; + --color-warning-text: #e0c37c; + --color-info: #7fb0dc; + --color-info-dark: #9cc4e8; + --color-on-info: #10140c; + --color-info-bg: #1a2530; + --color-info-border: #3d5468; + --color-info-text: #9cc4e8; + + --color-primary-rgb: 127, 179, 111; + --color-focus: rgba(127, 179, 111, 0.45); + + --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.5); + --shadow-md: 0 2px 6px rgba(0, 0, 0, 0.6); + } +} + +body { + margin: 0; + font-family: var(--font-ui); + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + background: var(--color-bg); + color: var(--color-text); + /* Damit auch vom Browser gestellte Bedienelemente (Bildlaufleisten, + Datumsauswahl, Autofill) der gewählten Ansicht folgen. */ + color-scheme: light dark; +} + +/* Formularfelder brauchen ausdrücklich Farben: ohne sie nimmt der Browser + seinen Standard (weiß) — in der Nachtansicht leuchtet dann jedes Eingabefeld. */ +input:not([type='checkbox']):not([type='radio']):not([type='range']):not([type='file']), +select, +textarea { + background: var(--color-surface); + color: var(--color-text); +} + +input::placeholder, +textarea::placeholder { + color: var(--color-text-muted); + opacity: 1; +} + +h1, h2, h3 { + font-family: var(--font-display); +} + +code { + font-family: var(--font-mono); +} + +/* ── Bedienelemente ─────────────────────────────────────────────────────── */ + .btn { display: inline-flex; align-items: center; justify-content: center; gap: var(--space-1); + min-height: var(--touch-target); padding: 0.5rem 1rem; border: none; border-radius: var(--radius-sm); + font-family: var(--font-ui); font-size: 0.9rem; font-weight: 600; cursor: pointer; @@ -46,15 +206,24 @@ } .btn:disabled { - background: var(--color-border); + background: var(--color-surface-alt); color: var(--color-text-muted); cursor: not-allowed; box-shadow: none; } +/* Sichtbarer Tastaturfokus. Ohne das war die Tastaturbedienung unsichtbar — + Buttons hatten nur einen :hover-Stil. */ +.btn:focus-visible, +.nav-button:focus-visible, +a:focus-visible { + outline: 2px solid var(--color-primary); + outline-offset: 2px; +} + .btn-primary { background: var(--color-primary); - color: white; + color: var(--color-on-primary); } .btn-primary:hover:not(:disabled) { @@ -64,7 +233,7 @@ .btn-secondary { background: var(--color-secondary); - color: white; + color: var(--color-on-secondary); } .btn-secondary:hover:not(:disabled) { @@ -72,19 +241,9 @@ transform: translateY(-1px); } -.btn-success { - background: var(--color-success); - color: white; -} - -.btn-success:hover:not(:disabled) { - background: var(--color-success-dark); - transform: translateY(-1px); -} - .btn-danger { background: var(--color-danger); - color: white; + color: var(--color-on-danger); } .btn-danger:hover:not(:disabled) { @@ -96,9 +255,13 @@ .select, .textarea { width: 100%; + min-height: var(--touch-target); padding: 0.75rem 1rem; + background: var(--color-surface); + color: var(--color-text); border: 1px solid var(--color-border-strong); border-radius: var(--radius-sm); + font-family: var(--font-ui); font-size: 1rem; box-sizing: border-box; } @@ -111,33 +274,19 @@ box-shadow: 0 0 0 3px var(--color-focus); } -.panel { - background: var(--color-surface); - border: 1px solid var(--color-border); - border-radius: var(--radius-md); - padding: var(--space-3); - box-shadow: var(--shadow-sm); -} - .panel-title { margin: 0 0 var(--space-2); + font-family: var(--font-display); font-size: 1.1rem; color: var(--color-text); } -body { - margin: 0; - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', - 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', - sans-serif; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - background: var(--color-bg); - color: var(--color-text); -} +/* ── Grundgerüst ────────────────────────────────────────────────────────── */ .App { - min-height: 100vh; + /* dvh statt vh: mit ein- und ausblendender Adressleiste auf Mobilgeräten + entsteht mit vh sonst Überlauf. */ + min-height: 100dvh; display: flex; flex-direction: column; } @@ -151,44 +300,26 @@ body { display: flex; justify-content: center; align-items: center; - min-height: 100vh; + min-height: 100dvh; font-size: 1.2rem; color: var(--color-text-muted); } -.login-prompt { - position: fixed; - bottom: 20px; - right: 20px; -} - -.login-button-header { - padding: 0.75rem 1.5rem; - background: var(--color-primary); - color: white; - border: none; - border-radius: 4px; - font-size: 1rem; - font-weight: 600; - cursor: pointer; - box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2); - transition: all 0.2s; -} - -.login-button-header:hover { - background: var(--color-primary-dark); - transform: translateY(-2px); - box-shadow: 0 6px 12px rgba(0, 0, 0, 0.3); -} - -@media (max-width: 768px) { - .login-prompt { - bottom: 10px; - right: 10px; +/* Wer Bewegung reduziert haben möchte, bekommt keine Animationen. */ +@media (prefers-reduced-motion: reduce) { + *, + *::before, + *::after { + animation-duration: 0.01ms !important; + animation-iteration-count: 1 !important; + transition-duration: 0.01ms !important; + scroll-behavior: auto !important; } - .login-button-header { - padding: 0.6rem 1.2rem; - font-size: 0.9rem; + .btn:hover:not(:disabled), + .btn-primary:hover:not(:disabled), + .btn-secondary:hover:not(:disabled), + .btn-danger:hover:not(:disabled) { + transform: none; } } diff --git a/stoeberhunde/frontend/src/components/admin/AdminPanel.css b/stoeberhunde/frontend/src/components/admin/AdminPanel.css index 12ce644..16e6fa0 100644 --- a/stoeberhunde/frontend/src/components/admin/AdminPanel.css +++ b/stoeberhunde/frontend/src/components/admin/AdminPanel.css @@ -25,7 +25,7 @@ .tab-button.active { background: var(--color-primary); - color: white; + color: var(--color-on-primary); } .settings-panel { @@ -59,9 +59,9 @@ .unsaved-badge { display: inline-block; - background: #fff3cd; - color: #856404; - border: 1px solid #ffc107; + background: var(--color-warning-bg); + color: var(--color-warning-text); + border: 1px solid var(--color-warning); border-radius: var(--radius-sm); padding: 0.2rem 0.6rem; font-size: 0.8rem; @@ -102,7 +102,7 @@ display: flex; align-items: center; gap: 0.5rem; - background: var(--color-muted-bg, #f5f5f0); + background: var(--color-muted-bg, var(--color-surface-alt)); border: none; padding: 0.75rem var(--space-2); cursor: pointer; @@ -111,7 +111,7 @@ } .settings-section-header:hover { - background: var(--color-focus, #eef2e6); + background: var(--color-focus, var(--color-success-bg)); } .settings-section-header .settings-heading { @@ -193,7 +193,7 @@ .skeleton-line { height: 1rem; border-radius: var(--radius-sm); - background: linear-gradient(90deg, #e8e8e4 25%, #f0f0ec 50%, #e8e8e4 75%); + background: linear-gradient(90deg, var(--color-surface-alt) 25%, var(--color-surface-alt) 50%, var(--color-surface-alt) 75%); background-size: 200% 100%; animation: skeleton-shimmer 1.4s infinite; margin-bottom: 0.75rem; @@ -323,17 +323,17 @@ .notification.success { background: var(--color-success); - color: white; + color: var(--color-on-success); } .notification.error { background: var(--color-danger); - color: white; + color: var(--color-on-danger); } .notification.warning { - background: #e67e00; - color: white; + background: var(--color-warning); + color: var(--color-on-warning); } @keyframes slideIn { diff --git a/stoeberhunde/frontend/src/components/admin/AuditLogs.css b/stoeberhunde/frontend/src/components/admin/AuditLogs.css index 433cfc4..0f2d27a 100644 --- a/stoeberhunde/frontend/src/components/admin/AuditLogs.css +++ b/stoeberhunde/frontend/src/components/admin/AuditLogs.css @@ -13,8 +13,8 @@ gap: 12px; flex-wrap: wrap; } -.audit-header h2 { margin: 0 0 4px 0; color: #333; font-size: 26px; } -.audit-description { margin: 0; color: #666; font-size: 13px; } +.audit-header h2 { margin: 0 0 4px 0; color: var(--color-text); font-size: 26px; } +.audit-description { margin: 0; color: var(--color-text-muted); font-size: 13px; } .audit-header-actions { display: flex; @@ -32,24 +32,24 @@ } .btn-stats-toggle { padding: 6px 14px; - background: #f0f4f8; - border: 1px solid #d0d7de; + background: var(--color-surface-alt); + border: 1px solid var(--color-border); border-radius: 6px; cursor: pointer; font-size: 13px; - color: #444; + color: var(--color-text-muted); } -.btn-stats-toggle:hover { background: #e2e8f0; } +.btn-stats-toggle:hover { background: var(--color-surface-alt); } .stats-days-select { font-size: 13px; } .audit-stats { - background: #f8fafc; - border: 1px solid #e2e8f0; + background: var(--color-surface-alt); + border: 1px solid var(--color-border); border-radius: 10px; padding: 16px; margin-bottom: 16px; } -.stats-loading { color: #888; font-size: 13px; padding: 8px 0; } +.stats-loading { color: var(--color-text-muted); font-size: 13px; padding: 8px 0; } .stats-row { display: flex; @@ -60,18 +60,18 @@ .stat-card { flex: 1; min-width: 100px; - background: white; + background: var(--color-surface); border-radius: 8px; padding: 12px 16px; text-align: center; - border: 1px solid #e2e8f0; + border: 1px solid var(--color-border); } .stat-number { font-size: 28px; font-weight: 700; line-height: 1; } -.stat-label { font-size: 11px; color: #666; margin-top: 4px; text-transform: uppercase; letter-spacing: 0.5px; } -.stat-total .stat-number { color: #1976d2; } -.stat-failed .stat-number { color: #c62828; } -.stat-success .stat-number { color: #2e7d32; } -.stat-period .stat-number { color: #555; font-size: 20px; } +.stat-label { font-size: 11px; color: var(--color-text-muted); margin-top: 4px; text-transform: uppercase; letter-spacing: 0.5px; } +.stat-total .stat-number { color: var(--color-info-text); } +.stat-failed .stat-number { color: var(--color-danger-text); } +.stat-success .stat-number { color: var(--color-success-text); } +.stat-period .stat-number { color: var(--color-text-muted); font-size: 20px; } .stats-details { display: flex; @@ -79,7 +79,7 @@ flex-wrap: wrap; } .stats-col { flex: 1; min-width: 180px; } -.stats-col h4 { margin: 0 0 8px 0; font-size: 12px; text-transform: uppercase; color: #888; letter-spacing: 0.5px; } +.stats-col h4 { margin: 0 0 8px 0; font-size: 12px; text-transform: uppercase; color: var(--color-text-muted); letter-spacing: 0.5px; } .stat-bar-row { display: flex; @@ -88,8 +88,8 @@ gap: 8px; margin-bottom: 5px; } -.stat-bar-label { font-size: 13px; color: #444; } -.stat-bar-count { font-size: 13px; font-weight: 600; color: #333; flex-shrink: 0; } +.stat-bar-label { font-size: 13px; color: var(--color-text-muted); } +.stat-bar-count { font-size: 13px; font-weight: 600; color: var(--color-text); flex-shrink: 0; } /* Mini bar chart */ .stats-chart-col { flex: 2; min-width: 220px; } @@ -98,7 +98,7 @@ align-items: flex-end; gap: 3px; height: 80px; - background: #f0f4f8; + background: var(--color-surface-alt); border-radius: 6px; padding: 6px 6px 0; } @@ -110,7 +110,7 @@ } .chart-bar { width: 100%; - background: #1976d2; + background: var(--color-info); border-radius: 2px 2px 0 0; position: relative; min-height: 4px; @@ -121,7 +121,7 @@ bottom: 0; left: 0; width: 100%; - background: #e53935; + background: var(--color-danger); } /* ── Filters ─────────────────────────────────────────────────────── */ @@ -134,52 +134,52 @@ } .filter-select { padding: 8px 12px; - border: 1.5px solid #d0d7de; + border: 1.5px solid var(--color-border); border-radius: 6px; font-size: 13px; - background: white; + background: var(--color-surface); cursor: pointer; } -.filter-select:focus { outline: none; border-color: #1976d2; } +.filter-select:focus { outline: none; border-color: var(--color-primary); } .filter-input { padding: 8px 12px; - border: 1.5px solid #d0d7de; + border: 1.5px solid var(--color-border); border-radius: 6px; font-size: 13px; - background: white; + background: var(--color-surface); min-width: 140px; } -.filter-input:focus { outline: none; border-color: #1976d2; } +.filter-input:focus { outline: none; border-color: var(--color-primary); } .filter-date { min-width: 130px; } .btn-refresh { padding: 8px 14px; - background: #1976d2; - color: white; + background: var(--color-info); + color: var(--color-on-info); border: none; border-radius: 6px; cursor: pointer; font-size: 13px; font-weight: 500; } -.btn-refresh:hover:not(:disabled) { background: #1565c0; } -.btn-refresh:disabled { background: #bdbdbd; cursor: not-allowed; } +.btn-refresh:hover:not(:disabled) { background: var(--color-info-dark); } +.btn-refresh:disabled { background: var(--color-surface-alt); color: var(--color-text-muted); cursor: not-allowed; } .btn-reset { padding: 8px 12px; - background: white; - color: #666; - border: 1.5px solid #d0d7de; + background: var(--color-surface); + color: var(--color-text-muted); + border: 1.5px solid var(--color-border); border-radius: 6px; cursor: pointer; font-size: 13px; } -.btn-reset:hover { background: #f5f5f5; } +.btn-reset:hover { background: var(--color-surface-alt); } .btn-export { padding: 8px 16px; - background: #2e7d32; - color: white; + background: var(--color-success); + color: var(--color-on-success); border: none; border-radius: 6px; cursor: pointer; @@ -187,15 +187,15 @@ font-weight: 500; white-space: nowrap; } -.btn-export:hover:not(:disabled) { background: #1b5e20; } -.btn-export:disabled { background: #bdbdbd; cursor: not-allowed; } +.btn-export:hover:not(:disabled) { background: var(--color-success-dark); } +.btn-export:disabled { background: var(--color-surface-alt); color: var(--color-text-muted); cursor: not-allowed; } .auto-refresh-toggle { display: flex; align-items: center; gap: 6px; font-size: 13px; - color: #555; + color: var(--color-text-muted); cursor: pointer; white-space: nowrap; } @@ -206,7 +206,7 @@ justify-content: space-between; align-items: center; font-size: 13px; - color: #666; + color: var(--color-text-muted); margin-bottom: 10px; } .limit-select { padding: 4px 8px; font-size: 13px; } @@ -224,16 +224,16 @@ } .badge-create { background: #e8f5e9; color: #2e7d32; } .badge-update { background: #e3f2fd; color: #1565c0; } -.badge-delete { background: #ffebee; color: #c62828; } -.badge-restore { background: #fff3e0; color: #e65100; } +.badge-delete { background: #ffebee; color: var(--color-danger-text); } +.badge-restore { background: #fff3e0; color: #a83a00; } .badge-login { background: #f3e5f5; color: #6a1b9a; } .badge-logout { background: #fce4ec; color: #880e4f; } .badge-login-failed { background: #ffcdd2; color: #b71c1c; font-weight: 700; } .badge-import { background: #e0f7fa; color: #00695c; } .badge-export { background: #e8f5e9; color: #1b5e20; } -.badge-bulk-update { background: #e8eaf6; color: #283593; } +.badge-bulk-update { background: var(--color-surface-alt); color: #283593; } .badge-bulk-delete { background: #fbe9e7; color: #bf360c; } -.badge-password { background: #fff8e1; color: #f57f17; } +.badge-password { background: #fff8e1; color: #9c4e00; } .badge-default { background: #f5f5f5; color: #616161; } .status-code { @@ -244,16 +244,16 @@ font-family: monospace; } .status-ok { background: #e8f5e9; color: #2e7d32; } -.status-redirect { background: #fff3e0; color: #e65100; } -.status-error { background: #ffebee; color: #c62828; } +.status-redirect { background: #fff3e0; color: #a83a00; } +.status-error { background: #ffebee; color: var(--color-danger-text); } .status-server-error { background: #f3e5f5; color: #6a1b9a; } .duration-badge { padding: 2px 8px; border-radius: 4px; font-size: 11px; - background: #f5f5f5; - color: #777; + background: var(--color-surface-alt); + color: var(--color-text-muted); font-family: monospace; } @@ -261,24 +261,24 @@ .audit-empty { text-align: center; padding: 40px; - background: #f9f9f9; + background: var(--color-surface-alt); border-radius: 8px; - color: #888; + color: var(--color-text-muted); } .audit-error { text-align: center; padding: 20px; } -.audit-error p { color: #d32f2f; margin: 0; } +.audit-error p { color: var(--color-danger-text); margin: 0; } .audit-list { display: flex; flex-direction: column; gap: 8px; } .audit-item { - background: white; - border: 1px solid #e0e0e0; + background: var(--color-surface); + border: 1px solid var(--color-border); border-radius: 8px; overflow: hidden; transition: box-shadow 0.15s; } .audit-item:hover { box-shadow: 0 2px 8px rgba(0,0,0,0.08); } -.audit-item-failed { border-left: 4px solid #e53935; } +.audit-item-failed { border-left: 4px solid var(--color-danger); } .audit-item-header { display: flex; @@ -286,18 +286,18 @@ gap: 8px; padding: 10px 14px; flex-wrap: wrap; - background: #fafafa; - border-bottom: 1px solid #f0f0f0; + background: var(--color-surface-alt); + border-bottom: 1px solid var(--color-border); } -.audit-time { margin-left: auto; color: #999; font-size: 12px; white-space: nowrap; } -.expand-toggle { color: #aaa; font-size: 11px; cursor: pointer; padding: 0 4px; } +.audit-time { margin-left: auto; color: var(--color-text-muted); font-size: 12px; white-space: nowrap; } +.expand-toggle { color: var(--color-text-muted); font-size: 11px; cursor: pointer; padding: 0 4px; } .audit-resource { padding: 3px 8px; - background: #f0f0f0; + background: var(--color-surface-alt); border-radius: 4px; font-size: 12px; - color: #555; + color: var(--color-text-muted); } .audit-item-body { @@ -308,16 +308,16 @@ font-size: 13px; align-items: center; } -.audit-admin { color: #333; } -.audit-resource-name { color: #555; } -.audit-ip { color: #999; font-family: monospace; font-size: 12px; } -.audit-failed-badge { color: #c62828; font-weight: 600; font-size: 12px; } +.audit-admin { color: var(--color-text); } +.audit-resource-name { color: var(--color-text-muted); } +.audit-ip { color: var(--color-text-muted); font-family: monospace; font-size: 12px; } +.audit-failed-badge { color: var(--color-danger-text); font-weight: 600; font-size: 12px; } /* ── Expanded detail ─────────────────────────────────────────────── */ .audit-item-detail { padding: 10px 14px 14px; - border-top: 1px dashed #e0e0e0; - background: #fefefe; + border-top: 1px dashed var(--color-border); + background: var(--color-surface); display: flex; flex-direction: column; gap: 8px; @@ -330,7 +330,7 @@ } .detail-label { font-weight: 600; - color: #888; + color: var(--color-text-muted); font-size: 11px; text-transform: uppercase; min-width: 70px; @@ -338,23 +338,23 @@ } .detail-row code { font-family: monospace; - background: #f0f0f0; + background: var(--color-surface-alt); padding: 2px 6px; border-radius: 3px; font-size: 12px; } .detail-ua-full { - color: #aaa; + color: var(--color-text-muted); cursor: help; font-size: 12px; } -.detail-error { color: #c62828; } -.detail-error .detail-label { color: #c62828; } +.detail-error { color: var(--color-danger-text); } +.detail-error .detail-label { color: var(--color-danger-text); } .meta-tag { display: inline-block; - background: #e8eaf6; - color: #283593; + background: var(--color-surface-alt); + color: var(--color-info-text); border-radius: 4px; padding: 2px 8px; font-size: 12px; @@ -370,17 +370,17 @@ margin-top: 6px; } .diff-table th { - background: #f0f0f0; + background: var(--color-surface-alt); padding: 5px 10px; text-align: left; font-size: 11px; text-transform: uppercase; - color: #666; - border: 1px solid #e0e0e0; + color: var(--color-text-muted); + border: 1px solid var(--color-border); } -.diff-table td { padding: 5px 10px; border: 1px solid #e8e8e8; vertical-align: top; } -.diff-field { font-weight: 600; color: #444; font-family: monospace; white-space: nowrap; background: #fafafa; } -.diff-before { color: #c62828; background: #fff5f5; font-family: monospace; word-break: break-all; } +.diff-table td { padding: 5px 10px; border: 1px solid var(--color-border); vertical-align: top; } +.diff-field { font-weight: 600; color: var(--color-text-muted); font-family: monospace; white-space: nowrap; background: var(--color-surface-alt); } +.diff-before { color: var(--color-danger-text); background: #fff5f5; font-family: monospace; word-break: break-all; } .diff-after { color: #2e7d32; background: #f5fff5; font-family: monospace; word-break: break-all; } /* ── Pagination ──────────────────────────────────────────────────── */ @@ -393,16 +393,16 @@ } .btn-page { padding: 7px 14px; - border: 1.5px solid #d0d7de; + border: 1.5px solid var(--color-border); border-radius: 6px; - background: white; + background: var(--color-surface); cursor: pointer; font-size: 13px; - color: #333; + color: var(--color-text); } -.btn-page:hover:not(:disabled) { background: #f0f4f8; border-color: #1976d2; } -.btn-page:disabled { color: #bbb; cursor: not-allowed; border-color: #eee; } -.page-info { font-size: 13px; color: #666; padding: 0 8px; } +.btn-page:hover:not(:disabled) { background: var(--color-surface-alt); border-color: var(--color-primary); } +.btn-page:disabled { color: var(--color-text-muted); cursor: not-allowed; border-color: var(--color-border); } +.page-info { font-size: 13px; color: var(--color-text-muted); padding: 0 8px; } .audit-header { @@ -411,13 +411,13 @@ .audit-header h2 { margin: 0 0 8px 0; - color: #333; + color: var(--color-text); font-size: 28px; } .audit-description { margin: 0; - color: #666; + color: var(--color-text-muted); font-size: 14px; } @@ -428,7 +428,7 @@ } .audit-error p { - color: #d32f2f; + color: var(--color-danger-text); margin: 0; } @@ -441,23 +441,23 @@ .filter-select { padding: 10px 14px; - border: 2px solid #e0e0e0; + border: 2px solid var(--color-border); border-radius: 6px; font-size: 14px; - background: white; + background: var(--color-surface); cursor: pointer; transition: border-color 0.2s; } .filter-select:focus { outline: none; - border-color: #1976d2; + border-color: var(--color-primary); } .btn-refresh { padding: 10px 16px; - background: #1976d2; - color: white; + background: var(--color-info); + color: var(--color-on-info); border: none; border-radius: 6px; cursor: pointer; @@ -467,20 +467,21 @@ } .btn-refresh:hover:not(:disabled) { - background: #1565c0; + background: var(--color-info-dark); } .btn-refresh:disabled { - background: #bdbdbd; + background: var(--color-surface-alt); + color: var(--color-text-muted); cursor: not-allowed; } .audit-empty { text-align: center; padding: 40px; - background: #f5f5f5; + background: var(--color-surface-alt); border-radius: 8px; - color: #666; + color: var(--color-text-muted); } .audit-list { @@ -490,8 +491,8 @@ } .audit-item { - background: white; - border: 1px solid #e0e0e0; + background: var(--color-surface); + border: 1px solid var(--color-border); border-radius: 8px; padding: 16px; transition: box-shadow 0.2s; @@ -519,58 +520,18 @@ gap: 4px; } -.badge-create { - background: #e8f5e9; - color: #2e7d32; -} - -.badge-update { - background: #e3f2fd; - color: #1565c0; -} - -.badge-delete { - background: #ffebee; - color: #c62828; -} - -.badge-restore { - background: #fff3e0; - color: #e65100; -} - -.badge-login { - background: #f3e5f5; - color: #6a1b9a; -} - -.badge-logout { - background: #fce4ec; - color: #880e4f; -} - -.badge-login-failed { - background: #ffcdd2; - color: #b71c1c; - font-weight: 700; -} - -.badge-default { - background: #f5f5f5; - color: #616161; -} .audit-resource { padding: 4px 10px; - background: #f5f5f5; + background: var(--color-surface-alt); border-radius: 4px; font-size: 13px; - color: #666; + color: var(--color-text-muted); } .audit-time { margin-left: auto; - color: #999; + color: var(--color-text-muted); font-size: 13px; } @@ -582,23 +543,19 @@ } .audit-admin { - color: #333; + color: var(--color-text); } .audit-resource-name { - color: #666; + color: var(--color-text-muted); } .audit-ip { - color: #888; + color: var(--color-text-muted); font-family: monospace; font-size: 13px; } -.audit-error-message { - color: #d32f2f; - font-weight: 500; -} .audit-pagination { display: flex; @@ -607,15 +564,15 @@ gap: 16px; margin-top: 24px; padding: 16px; - background: white; + background: var(--color-surface); border-radius: 8px; - border: 1px solid #e0e0e0; + border: 1px solid var(--color-border); } .btn-page { padding: 8px 16px; - background: #1976d2; - color: white; + background: var(--color-info); + color: var(--color-on-info); border: none; border-radius: 6px; cursor: pointer; @@ -624,16 +581,17 @@ } .btn-page:hover:not(:disabled) { - background: #1565c0; + background: var(--color-info-dark); } .btn-page:disabled { - background: #bdbdbd; + background: var(--color-surface-alt); + color: var(--color-text-muted); cursor: not-allowed; } .page-info { - color: #666; + color: var(--color-text-muted); font-size: 14px; } @@ -656,3 +614,33 @@ width: 100%; } } + +/* ── Nachtvariante ─────────────────────────────────────────────────────── + Die Badges kodieren die Aktionsart über den Farbton – der bleibt erhalten, + nur Helligkeit und Sättigung drehen sich um. Alle Paare >= 6.4:1. */ +@media (prefers-color-scheme: dark) { + .badge-create { background: #162d17; color: #97d99a; } + .badge-update { background: #16202d; color: #89b5e6; } + .badge-delete { background: #2d1616; color: #e68989; } + .badge-restore { background: #2d1e16; color: #e6aa89; } + .badge-login { background: #24162d; color: #c389e6; } + .badge-logout { background: #2d1622; color: #e689bb; } + .badge-login-failed { background: #2d1616; color: #e68989; } + .badge-import { background: #162d2a; color: #89e6db; } + .badge-export { background: #162d17; color: #90df96; } + .badge-bulk-update { background: #16182d; color: #8f99e0; } + .badge-bulk-delete { background: #2d1b16; color: #e69f89; } + .badge-password { background: #2d2016; color: #e6b589; } + .badge-default { background: var(--color-surface-alt); color: var(--color-text-muted); } + + .status-ok { background: #162d17; color: #97d99a; } + .status-redirect { background: #2d1e16; color: #e6aa89; } + .status-error { background: #2d1616; color: #e68989; } + .status-server-error { background: #24162d; color: #c389e6; } + + /* Diff-Tabelle: die roten/gruenen Vorher-Nachher-Felder */ + .diff-table th { background: var(--color-surface-alt); } + .diff-before { color: #e68989; background: #2d1616; } + .diff-after { color: #97d99a; background: #162d17; } + .diff-field { background: var(--color-surface-alt); color: var(--color-text); } +} diff --git a/stoeberhunde/frontend/src/components/admin/ExportButton.css b/stoeberhunde/frontend/src/components/admin/ExportButton.css index 83981da..c231346 100644 --- a/stoeberhunde/frontend/src/components/admin/ExportButton.css +++ b/stoeberhunde/frontend/src/components/admin/ExportButton.css @@ -14,7 +14,7 @@ .export-button { padding: 0.5rem 1rem; background: var(--color-success); - color: white; + color: var(--color-on-success); border: none; border-radius: var(--radius-sm); cursor: pointer; @@ -41,8 +41,8 @@ .import-button { padding: 0.5rem 1rem; - background: var(--color-primary, #2563eb); - color: white; + background: var(--color-primary, var(--color-info)); + color: var(--color-on-primary); border: none; border-radius: var(--radius-sm); cursor: pointer; @@ -52,7 +52,7 @@ } .import-button:hover:not(:disabled) { - background: var(--color-primary-dark, #1d4ed8); + background: var(--color-primary-dark, var(--color-info-dark)); } .import-button:disabled { @@ -65,7 +65,7 @@ align-items: center; gap: 0.4rem; font-size: 0.85rem; - color: var(--color-text-muted, #6b7280); + color: var(--color-text-muted); cursor: pointer; white-space: nowrap; } diff --git a/stoeberhunde/frontend/src/components/admin/Trash.css b/stoeberhunde/frontend/src/components/admin/Trash.css index 200c68a..e70ac72 100644 --- a/stoeberhunde/frontend/src/components/admin/Trash.css +++ b/stoeberhunde/frontend/src/components/admin/Trash.css @@ -10,13 +10,13 @@ .trash-header h2 { margin: 0 0 8px 0; - color: #333; + color: var(--color-text); font-size: 28px; } .trash-description { margin: 0; - color: #666; + color: var(--color-text-muted); font-size: 14px; } @@ -27,14 +27,14 @@ } .trash-error h3 { - color: #d32f2f; + color: var(--color-danger-text); margin-bottom: 12px; } .btn-retry { padding: 10px 20px; - background: #1976d2; - color: white; + background: var(--color-info); + color: var(--color-on-info); border: none; border-radius: 6px; cursor: pointer; @@ -43,13 +43,13 @@ } .btn-retry:hover { - background: #1565c0; + background: var(--color-info-dark); } .trash-empty { text-align: center; padding: 60px 20px; - background: #f5f5f5; + background: var(--color-surface-alt); border-radius: 12px; } @@ -60,7 +60,7 @@ } .trash-empty p { - color: #666; + color: var(--color-text-muted); font-size: 16px; margin: 0; } @@ -72,8 +72,8 @@ } .trash-item { - background: #fff; - border: 2px solid #e0e0e0; + background: var(--color-surface); + border: 2px solid var(--color-border); border-radius: 8px; padding: 16px 20px; display: flex; @@ -84,7 +84,7 @@ .trash-item:hover { box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); - border-color: #bdbdbd; + border-color: var(--color-border); } .trash-item-info { @@ -93,7 +93,7 @@ .trash-item-info h3 { margin: 0 0 8px 0; - color: #333; + color: var(--color-text); font-size: 18px; font-weight: 600; } @@ -106,8 +106,8 @@ } .trash-item-type { - background: #e3f2fd; - color: #1976d2; + background: var(--color-info-bg); + color: var(--color-info-text); padding: 4px 10px; border-radius: 4px; font-size: 13px; @@ -116,12 +116,12 @@ .trash-item-address, .trash-item-phone { - color: #666; + color: var(--color-text-muted); font-size: 14px; } .trash-item-meta { - color: #999; + color: var(--color-text-muted); font-size: 13px; } @@ -140,8 +140,8 @@ align-items: center; gap: 6px; padding: 10px 16px; - background: #4caf50; - color: white; + background: var(--color-success); + color: var(--color-on-success); border: none; border-radius: 6px; cursor: pointer; @@ -151,7 +151,7 @@ } .btn-restore:hover:not(:disabled) { - background: #45a049; + background: var(--color-success-dark); transform: translateY(-1px); } @@ -160,7 +160,7 @@ } .btn-restore:disabled { - background: #bdbdbd; + background: var(--color-border-strong); cursor: not-allowed; } diff --git a/stoeberhunde/frontend/src/components/auth/LoginForm.css b/stoeberhunde/frontend/src/components/auth/LoginForm.css index 1a38755..56024ab 100644 --- a/stoeberhunde/frontend/src/components/auth/LoginForm.css +++ b/stoeberhunde/frontend/src/components/auth/LoginForm.css @@ -56,7 +56,7 @@ width: 100%; padding: 0.75rem; background: var(--color-primary); - color: white; + color: var(--color-on-primary); border: none; border-radius: var(--radius-sm); font-size: 1rem; @@ -76,8 +76,8 @@ .login-error { padding: 0.75rem; - background: #ffebee; - border: 1px solid #ffcdd2; + background: var(--color-danger-bg); + border: 1px solid var(--color-danger-border); border-radius: var(--radius-sm); color: var(--color-danger); margin-bottom: 1rem; diff --git a/stoeberhunde/frontend/src/components/auth/PasswordReset.css b/stoeberhunde/frontend/src/components/auth/PasswordReset.css index cd3c067..4ee08d1 100644 --- a/stoeberhunde/frontend/src/components/auth/PasswordReset.css +++ b/stoeberhunde/frontend/src/components/auth/PasswordReset.css @@ -1,5 +1,6 @@ .password-reset-container { - min-height: 100vh; + /* dvh: mit ein- und ausblendender Adressleiste entsteht mit vh Überlauf. */ + min-height: 100dvh; display: flex; justify-content: center; align-items: center; @@ -8,7 +9,7 @@ } .password-reset-card { - background: white; + background: var(--color-surface); border-radius: 12px; box-shadow: 0 10px 40px rgba(0, 0, 0, 0.1); padding: 40px; @@ -18,7 +19,7 @@ .password-reset-card h2 { margin: 0 0 24px 0; - color: #333; + color: var(--color-text); font-size: 28px; text-align: center; } @@ -32,15 +33,15 @@ } .message.success { - background-color: #d4edda; - color: #155724; - border: 1px solid #c3e6cb; + background-color: var(--color-success-bg); + color: var(--color-success-text); + border: 1px solid var(--color-success-border); } .message.error { - background-color: #f8d7da; - color: #721c24; - border: 1px solid #f5c6cb; + background-color: var(--color-danger-bg); + color: var(--color-danger-text); + border: 1px solid var(--color-danger-border); } .form-group { @@ -50,7 +51,7 @@ .form-group label { display: block; margin-bottom: 8px; - color: #555; + color: var(--color-text-muted); font-weight: 500; font-size: 14px; } @@ -58,7 +59,7 @@ .form-group input { width: 100%; padding: 12px 16px; - border: 2px solid #e0e0e0; + border: 2px solid var(--color-border); border-radius: 8px; font-size: 15px; transition: border-color 0.3s; @@ -71,14 +72,14 @@ } .form-group input:disabled { - background-color: #f5f5f5; + background-color: var(--color-surface-alt); cursor: not-allowed; } .form-group small { display: block; margin-top: 6px; - color: #888; + color: var(--color-text-muted); font-size: 13px; } @@ -86,7 +87,7 @@ width: 100%; padding: 14px; background: var(--color-primary); - color: white; + color: var(--color-on-primary); border: none; border-radius: 8px; font-size: 16px; diff --git a/stoeberhunde/frontend/src/components/common/ErrorMessage.css b/stoeberhunde/frontend/src/components/common/ErrorMessage.css index 38733d8..efba2ba 100644 --- a/stoeberhunde/frontend/src/components/common/ErrorMessage.css +++ b/stoeberhunde/frontend/src/components/common/ErrorMessage.css @@ -4,10 +4,10 @@ gap: 0.5rem; padding: 1rem; margin: 1rem 0; - background-color: #fee; - border: 1px solid #fcc; + background-color: var(--color-danger-bg); + border: 1px solid var(--color-danger-border); border-radius: 4px; - color: #c33; + color: var(--color-danger-text); } .error-icon { @@ -22,7 +22,7 @@ background: none; border: none; font-size: 1.5rem; - color: #c33; + color: var(--color-danger-text); cursor: pointer; padding: 0; width: 24px; @@ -34,5 +34,5 @@ } .error-close:hover { - color: #a22; + color: var(--color-danger-text); } diff --git a/stoeberhunde/frontend/src/components/common/Header.css b/stoeberhunde/frontend/src/components/common/Header.css index 69a023f..dd3e83d 100644 --- a/stoeberhunde/frontend/src/components/common/Header.css +++ b/stoeberhunde/frontend/src/components/common/Header.css @@ -1,6 +1,6 @@ .app-header { - background: #ffffff; - border-bottom: 1px solid #e5e5e5; + background: var(--color-surface); + border-bottom: 1px solid var(--color-border); padding: 0.75rem 2rem; display: flex; align-items: center; @@ -27,7 +27,7 @@ .portal-back-link:hover { background: var(--color-primary); - color: #fff; + color: var(--color-on-primary); } .app-brand { @@ -40,18 +40,18 @@ height: 52px; width: auto; object-fit: contain; -} - -.app-logo-ljn { - height: 44px; + flex-shrink: 0; } .app-title { margin: 0; + font-family: var(--font-display); font-size: 1.05rem; font-weight: 700; color: var(--color-text); - white-space: nowrap; + /* Kein nowrap: lange App-Namen haben die Kopfzeile sonst über die + Bildschirmbreite hinaus geschoben. */ + overflow-wrap: anywhere; } .app-nav { @@ -61,11 +61,14 @@ } .nav-button { + display: inline-flex; + align-items: center; + min-height: var(--touch-target); padding: 0.5rem 0.875rem; background: none; border: none; border-radius: var(--radius-sm); - color: #333; + color: var(--color-text); cursor: pointer; font-size: 0.9rem; font-weight: 500; @@ -97,12 +100,19 @@ .app-header { flex-direction: column; align-items: flex-start; - padding: 0.75rem 1rem; - gap: 0.5rem; + padding: 0.5rem 1rem; + gap: 0.4rem; + /* Auf schmalen Geräten nimmt die umgebrochene Kopfzeile viel Höhe ein. + Klebrig bleibt sie nur dort, wo genug Platz ist. */ + position: static; } .app-title { - font-size: 0.9rem; + font-size: 0.95rem; + } + + .app-logo { + height: 36px; } .app-nav { @@ -111,7 +121,31 @@ } .nav-button { - font-size: 0.85rem; + font-size: 0.9rem; padding: 0.4rem 0.7rem; } } + +@media (max-width: 480px) { + .app-header { + padding: 0.5rem 0.75rem; + } + + .app-brand { + gap: 0.5rem; + } + + .app-logo { + height: 30px; + } + + .app-nav { + width: 100%; + } + + .nav-button { + flex: 1 1 45%; + justify-content: center; + padding: 0.4rem 0.5rem; + } +} diff --git a/stoeberhunde/frontend/src/components/common/InstallBanner.css b/stoeberhunde/frontend/src/components/common/InstallBanner.css index f5b248d..0ab554a 100644 --- a/stoeberhunde/frontend/src/components/common/InstallBanner.css +++ b/stoeberhunde/frontend/src/components/common/InstallBanner.css @@ -2,8 +2,8 @@ position: sticky; top: 0; z-index: 1000; - background-color: #2d6a2d; - color: #fff; + background-color: var(--color-primary); + color: var(--color-on-primary); box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3); } @@ -22,8 +22,8 @@ } .install-banner__btn { - background: #fff; - color: #2d6a2d; + background: var(--color-surface); + color: var(--color-primary); border: none; border-radius: 4px; padding: 0.35rem 0.85rem; @@ -34,7 +34,7 @@ } .install-banner__btn:hover { - background: #e8f5e9; + background: var(--color-success-bg); } .install-banner__close { @@ -49,7 +49,7 @@ } .install-banner__close:hover { - color: #fff; + color: var(--color-on-primary); } .install-banner__share-icon { diff --git a/stoeberhunde/frontend/src/components/common/Loading.css b/stoeberhunde/frontend/src/components/common/Loading.css index ec8df60..e1dbe74 100644 --- a/stoeberhunde/frontend/src/components/common/Loading.css +++ b/stoeberhunde/frontend/src/components/common/Loading.css @@ -8,8 +8,8 @@ } .spinner { - border: 4px solid #f3f3f3; - border-top: 4px solid #3498db; + border: 4px solid var(--color-border); + border-top: 4px solid var(--color-primary); border-radius: 50%; width: 50px; height: 50px; @@ -23,6 +23,6 @@ .loading-message { margin-top: 1rem; - color: #666; + color: var(--color-text-muted); font-size: 0.9rem; } diff --git a/stoeberhunde/frontend/src/components/map/MapView.css b/stoeberhunde/frontend/src/components/map/MapView.css index bfb9cff..6e82ee3 100644 --- a/stoeberhunde/frontend/src/components/map/MapView.css +++ b/stoeberhunde/frontend/src/components/map/MapView.css @@ -13,32 +13,32 @@ left: 12px; z-index: 500; background: rgba(255, 255, 255, 0.95); - color: #444; + color: var(--color-text-muted); padding: 0.45rem 0.7rem; border-radius: 6px; font-size: 0.85rem; - border: 1px solid #dcdcdc; + border: 1px solid var(--color-border); } .map-no-data { padding: 3rem; text-align: center; - color: #666; - background: white; + color: var(--color-text-muted); + background: var(--color-surface); border-radius: 8px; margin: 1rem 0; } .map-popup h3 { margin: 0 0 0.5rem 0; - color: #333; + color: var(--color-text); font-size: 1rem; } .map-popup p { margin: 0.25rem 0; font-size: 0.85rem; - color: #666; + color: var(--color-text-muted); } .map-popup a { @@ -54,8 +54,40 @@ display: inline-block; padding: 0.2rem 0.5rem; background: var(--color-primary); - color: white; + color: var(--color-on-primary); border-radius: 4px; font-size: 0.75rem; margin-top: 0.5rem; } + +/* ── Nachtansicht ──────────────────────────────────────────────────────── + Die OSM-Kacheln sind immer taghell. In der Dämmerung ist die Karte damit + die mit Abstand hellste Fläche der App und blendet — genau die Situation, + in der Nachsuchen stattfinden. Die Kacheln werden deshalb abgedunkelt; + Marker und Bedienelemente bleiben unangetastet, damit sie lesbar sind. */ +@media (prefers-color-scheme: dark) { + .leaflet-tile-pane { + filter: brightness(0.62) saturate(0.75) contrast(1.05); + } + + .leaflet-container { + background: var(--color-surface-alt); + } + + /* Hoehere Spezifitaet als Leaflets eigene Regeln, die spaeter geladen werden */ + .leaflet-container .leaflet-control-zoom a, + .leaflet-container .leaflet-control-attribution { + background: var(--color-surface); + color: var(--color-text); + } + + .leaflet-container .leaflet-control-attribution a { + color: var(--color-primary); + } + + .leaflet-popup-content-wrapper, + .leaflet-popup-tip { + background: var(--color-surface); + color: var(--color-text); + } +} diff --git a/stoeberhunde/frontend/src/components/public/PublicUserList.css b/stoeberhunde/frontend/src/components/public/PublicUserList.css index c24d538..55233f6 100644 --- a/stoeberhunde/frontend/src/components/public/PublicUserList.css +++ b/stoeberhunde/frontend/src/components/public/PublicUserList.css @@ -14,7 +14,7 @@ } .public-user-list h2 { - color: #1a1a1a; + color: var(--color-text); margin: 0; font-size: 1.5rem; font-weight: 700; @@ -23,7 +23,7 @@ .toggle-map-button { padding: 0.5rem 1rem; background: var(--color-primary); - color: white; + color: var(--color-on-primary); border: none; border-radius: 4px; cursor: pointer; @@ -44,8 +44,8 @@ .filter-toggle-button { padding: 0.5rem 1rem; - background: #6c757d; - color: white; + background: var(--color-secondary); + color: var(--color-on-secondary); border: none; border-radius: 4px; cursor: pointer; @@ -55,12 +55,12 @@ } .filter-toggle-button:hover { - background: #5a6268; + background: var(--color-secondary-dark); } .location-panel { - background: white; - border: 1px solid #e5e5e5; + background: var(--color-surface); + border: 1px solid var(--color-border); border-radius: 8px; padding: 1rem 1.5rem; margin-bottom: 1.5rem; @@ -78,7 +78,7 @@ .location-button { padding: 0.5rem 1rem; background: var(--color-primary); - color: white; + color: var(--color-on-primary); border: none; border-radius: 4px; cursor: pointer; @@ -92,7 +92,7 @@ } .location-button:disabled { - background: #b6b6b6; + background: var(--color-border-strong); cursor: not-allowed; } @@ -103,13 +103,13 @@ } .location-status.success { - background: #e8f5e9; - color: var(--color-primary-dark); + background: var(--color-success-bg); + color: var(--color-success-text); } .location-status.error { - background: #ffebee; - color: #c62828; + background: var(--color-danger-bg); + color: var(--color-danger-text); } .postal-search { @@ -120,21 +120,21 @@ .postal-search input[type="text"] { padding: 0.5rem; - border: 1px solid #ddd; + border: 1px solid var(--color-border); border-radius: 4px; font-size: 0.9rem; width: 150px; } .postal-search input[type="text"]:disabled { - background: #f5f5f5; + background: var(--color-surface-alt); cursor: not-allowed; } .postal-search button { padding: 0.5rem 1rem; background: var(--color-primary); - color: white; + color: var(--color-on-primary); border: none; border-radius: 4px; cursor: pointer; @@ -148,14 +148,14 @@ } .postal-search button:disabled { - background: #b6b6b6; + background: var(--color-border-strong); cursor: not-allowed; } .radius-filter label { display: block; font-size: 0.9rem; - color: #555; + color: var(--color-text-muted); margin-bottom: 0.5rem; font-weight: 500; } @@ -174,26 +174,26 @@ .radius-inputs input[type="number"] { width: 80px; padding: 0.4rem 0.5rem; - border: 1px solid #ddd; + border: 1px solid var(--color-border); border-radius: 4px; font-size: 0.9rem; } .radius-inputs input:disabled { - background: #f5f5f5; + background: var(--color-surface-alt); cursor: not-allowed; } .radius-hint { font-size: 0.85rem; - color: #777; + color: var(--color-text-muted); margin-top: 0.5rem; } .gps-hint { margin-top: 0.5rem; font-size: 0.85rem; - color: #777; + color: var(--color-text-muted); } .user-grid { @@ -205,8 +205,8 @@ /* Jägerschaft-style card */ .user-card { - background: white; - border: 1px solid #e5e5e5; + background: var(--color-surface); + border: 1px solid var(--color-border); border-radius: 8px; padding: 1.5rem; box-shadow: 0 2px 6px rgba(0, 0, 0, 0.06); @@ -232,9 +232,9 @@ box-shadow: 0 6px 16px rgba(0, 0, 0, 0.1); } -.user-name { +.public-user-list .user-name { margin: 0 0 0.2rem; - color: #1a1a1a; + color: var(--color-text); font-size: 1rem; font-weight: 700; text-transform: uppercase; @@ -250,15 +250,15 @@ color: var(--color-primary); } -.user-info { +.public-user-list .user-info { display: flex; flex-direction: column; gap: 0.375rem; } -.user-address { +.public-user-list .user-address { margin: 0; - color: #666; + color: var(--color-text-muted); font-size: 0.9rem; } @@ -266,72 +266,80 @@ margin: 0.5rem 0 0; } -.type-badge { +.public-user-list .type-badge { display: inline-block; padding: 0.2rem 0.6rem; - background: #f0f0f0; - color: #444; + background: var(--color-surface-alt); + color: var(--color-text-muted); border-radius: 4px; font-size: 0.8rem; font-weight: 600; letter-spacing: 0.03em; } +/* Der Anruf beim Stöberhundeführer ist der Zweck dieser Liste und wird fast + immer mit dem Daumen auf dem Handy ausgelöst. Vorher war das ein 14 px hoher + Textlink; jetzt ein vollwertiges Ziel mit der empfohlenen Mindesthöhe. */ .user-phone { + display: flex; + align-items: center; + gap: 0.5rem; + min-height: var(--touch-target); + margin: 0.15rem 0; + padding: 0.35rem 0.6rem; + background: var(--color-surface-alt); + border: 1px solid var(--color-border); + border-radius: var(--radius-sm); color: var(--color-primary); text-decoration: none; - font-weight: 500; - font-size: 0.9rem; + font-weight: 600; + font-size: 1rem; } -.user-phone:hover { +.public-user-list .user-phone:hover, +.public-user-list .user-phone:focus-visible { + background: var(--color-surface); + border-color: var(--color-border-strong); text-decoration: underline; } -.user-gps { - margin-top: 1rem; - padding-top: 1rem; - border-top: 1px solid #e5e5e5; - font-size: 0.85rem; - color: #888; -} .user-distance { margin-top: 0.75rem; padding-top: 0.75rem; - border-top: 1px solid #e5e5e5; + border-top: 1px solid var(--color-border); font-size: 0.85rem; - color: #555; + color: var(--color-text-muted); font-weight: 500; } .no-users { text-align: center; padding: 3rem; - color: #666; + color: var(--color-text-muted); } .loading { text-align: center; padding: 3rem; - color: #666; + color: var(--color-text-muted); } @media (max-width: 768px) { - .user-grid { +.user-grid { grid-template-columns: 1fr; } - .public-user-list { +.public-user-list { padding: 1rem; } - .radius-inputs { +.radius-inputs { flex-direction: column; align-items: stretch; } - .radius-inputs input[type="number"] { +.radius-inputs input[type="number"] { width: 100%; } } diff --git a/stoeberhunde/frontend/src/components/public/RulesDisplay.css b/stoeberhunde/frontend/src/components/public/RulesDisplay.css index 32be9b6..4ec7a73 100644 --- a/stoeberhunde/frontend/src/components/public/RulesDisplay.css +++ b/stoeberhunde/frontend/src/components/public/RulesDisplay.css @@ -33,7 +33,7 @@ } .allgemeines-tab-btn.active { - background: white; + background: var(--color-surface); color: var(--color-primary); font-weight: 700; border-color: var(--color-primary); @@ -41,7 +41,7 @@ } .allgemeines-content { - background: white; + background: var(--color-surface); border: 1px solid var(--color-primary); border-top: none; border-radius: 0 0 8px 8px; diff --git a/stoeberhunde/frontend/src/components/stoeberhundefuehrer/StoeberhundefuehrerDashboard.css b/stoeberhunde/frontend/src/components/stoeberhundefuehrer/StoeberhundefuehrerDashboard.css index 643a941..fee5347 100644 --- a/stoeberhunde/frontend/src/components/stoeberhundefuehrer/StoeberhundefuehrerDashboard.css +++ b/stoeberhunde/frontend/src/components/stoeberhundefuehrer/StoeberhundefuehrerDashboard.css @@ -5,7 +5,7 @@ } .stoeberhundefuehrer-dashboard-card { - background: white; + background: var(--color-surface); border-radius: 10px; padding: 2rem; width: 100%; @@ -46,7 +46,7 @@ .btn-stoeberhundefuehrer-logout:hover { background: var(--color-danger); - color: white; + color: var(--color-on-danger); } .stoeberhundefuehrer-message { @@ -56,8 +56,8 @@ font-size: 0.9rem; } -.stoeberhundefuehrer-message-success { background: #dcfce7; color: #166534; } -.stoeberhundefuehrer-message-error { background: #fee2e2; color: #b91c1c; } +.stoeberhundefuehrer-message-success { background: var(--color-success-bg); color: var(--color-success-text); } +.stoeberhundefuehrer-message-error { background: var(--color-danger-bg); color: var(--color-danger-text); } .stoeberhundefuehrer-availability-section { background: var(--color-muted-bg); @@ -92,15 +92,15 @@ .availability-big-btn:disabled { opacity: 0.6; cursor: not-allowed; } .btn-green { - background: #dcfce7; - color: #15803d; - border-color: #86efac; + background: var(--color-success-bg); + color: var(--color-success-text); + border-color: var(--color-success-border); } .btn-red { - background: #fee2e2; - color: #b91c1c; - border-color: #fca5a5; + background: var(--color-danger-bg); + color: var(--color-danger-text); + border-color: var(--color-danger-border); } .status-dot-lg { @@ -110,8 +110,8 @@ flex-shrink: 0; } -.dot-green { background: #22c55e; } -.dot-red { background: #ef4444; } +.dot-green { background: var(--color-success); } +.dot-red { background: var(--color-danger); } .availability-hint { font-size: 0.82rem; @@ -147,7 +147,7 @@ font-size: 0.9rem; } -.btn-stoeberhundefuehrer-edit:hover { background: var(--color-primary); color: white; } +.btn-stoeberhundefuehrer-edit:hover { background: var(--color-primary); color: var(--color-on-primary); } .stoeberhundefuehrer-info-list { display: flex; flex-direction: column; gap: 0.6rem; } @@ -206,7 +206,7 @@ flex: 1; padding: 0.65rem; background: var(--color-primary); - color: white; + color: var(--color-on-primary); border: none; border-radius: 6px; font-size: 0.95rem; diff --git a/stoeberhunde/frontend/src/components/stoeberhundefuehrer/StoeberhundefuehrerLogin.css b/stoeberhunde/frontend/src/components/stoeberhundefuehrer/StoeberhundefuehrerLogin.css index 3068103..2cb0f68 100644 --- a/stoeberhunde/frontend/src/components/stoeberhundefuehrer/StoeberhundefuehrerLogin.css +++ b/stoeberhunde/frontend/src/components/stoeberhundefuehrer/StoeberhundefuehrerLogin.css @@ -6,7 +6,7 @@ } .stoeberhundefuehrer-login-card { - background: white; + background: var(--color-surface); border-radius: 10px; padding: 2rem; width: 100%; @@ -48,7 +48,7 @@ .stoeberhundefuehrer-mode-toggle button.active { background: var(--color-primary); - color: white; + color: var(--color-on-primary); font-weight: 600; } @@ -82,7 +82,7 @@ width: 100%; padding: 0.75rem; background: var(--color-primary); - color: white; + color: var(--color-on-primary); border: none; border-radius: 6px; font-size: 1rem; @@ -102,8 +102,8 @@ } .stoeberhundefuehrer-error { - background: #fee2e2; - color: #b91c1c; + background: var(--color-danger-bg); + color: var(--color-danger-text); border-radius: 4px; padding: 0.6rem 0.9rem; margin-bottom: 1rem; @@ -111,8 +111,8 @@ } .stoeberhundefuehrer-success { - background: #dcfce7; - color: #166534; + background: var(--color-success-bg); + color: var(--color-success-text); border-radius: 4px; padding: 0.6rem 0.9rem; margin-bottom: 1rem; diff --git a/stoeberhunde/frontend/src/components/users/UserCard.css b/stoeberhunde/frontend/src/components/users/UserCard.css index a6f6bb7..2c62fa9 100644 --- a/stoeberhunde/frontend/src/components/users/UserCard.css +++ b/stoeberhunde/frontend/src/components/users/UserCard.css @@ -25,7 +25,7 @@ border-bottom: 1px solid var(--color-border); } -.user-name-row { +.user-card-admin .user-name-row { display: flex; align-items: center; gap: 0.5rem; @@ -39,10 +39,10 @@ box-shadow: 0 0 4px rgba(0,0,0,0.2); } -.dot-green { background: #22c55e; } -.dot-red { background: #ef4444; } +.dot-green { background: var(--color-success); } +.dot-red { background: var(--color-danger); } -.user-name { +.user-card-admin .user-name { margin: 0; color: var(--color-text); font-size: 1.2rem; @@ -67,40 +67,40 @@ font-weight: 600; } -.label-green { color: #16a34a; } -.label-red { color: var(--color-danger); } +.label-green { color: var(--color-success); } +.label-red { color: var(--color-danger); } -.user-info { +.user-card-admin .user-info { display: flex; flex-direction: column; gap: 0.5rem; margin-bottom: 1rem; } -.user-address { +.user-card-admin .user-address { margin: 0; color: var(--color-text-muted); font-size: 0.9rem; } -.type-badge { +.user-card-admin .type-badge { display: inline-block; padding: 0.25rem 0.75rem; background: var(--color-primary); - color: white; + color: var(--color-on-primary); border-radius: var(--radius-pill); font-size: 0.85rem; font-weight: 500; } -.user-phone { +.user-card-admin .user-phone { color: var(--color-primary); text-decoration: none; font-weight: 500; font-size: 1rem; } -.user-phone:hover { +.user-card-admin .user-phone:hover { text-decoration: underline; } @@ -183,7 +183,7 @@ .edit-gps-button { padding: 0.25rem 0.75rem; background: var(--color-primary); - color: white; + color: var(--color-on-primary); border: none; border-radius: var(--radius-sm); cursor: pointer; @@ -229,7 +229,7 @@ .save-gps-button { background: var(--color-success); - color: white; + color: var(--color-on-success); } .save-gps-button:hover:not(:disabled) { @@ -243,7 +243,7 @@ .cancel-gps-button { background: var(--color-secondary); - color: white; + color: var(--color-on-secondary); } .cancel-gps-button:hover { @@ -272,7 +272,7 @@ .edit-button { background: var(--color-primary); - color: white; + color: var(--color-on-primary); } .edit-button:hover { @@ -281,7 +281,7 @@ .delete-button { background: var(--color-danger); - color: white; + color: var(--color-on-danger); } .delete-button:hover { @@ -289,17 +289,17 @@ } @media (max-width: 768px) { - .user-header { +.user-header { flex-direction: column; align-items: flex-start; gap: 0.5rem; } - .gps-inputs { +.gps-inputs { flex-direction: column; } - .card-actions { +.card-actions { flex-direction: column; } } @@ -322,7 +322,7 @@ display: block; margin-top: 0.35rem; padding: 0.4rem 0.5rem; - background: var(--color-bg-muted, #f2f2ec); + background: var(--color-surface-alt); border: 1px solid var(--color-border); border-radius: 2px; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; diff --git a/stoeberhunde/frontend/src/components/users/UserForm.css b/stoeberhunde/frontend/src/components/users/UserForm.css index 474c2a3..e3e62df 100644 --- a/stoeberhunde/frontend/src/components/users/UserForm.css +++ b/stoeberhunde/frontend/src/components/users/UserForm.css @@ -91,7 +91,7 @@ top: 100%; left: 0; right: 0; - background: white; + background: var(--color-surface); border: 1px solid var(--color-border-strong); border-top: none; border-radius: 0 0 var(--radius-sm) var(--radius-sm); @@ -163,7 +163,7 @@ .btn-primary { background: var(--color-primary); - color: white; + color: var(--color-on-primary); } .btn-primary:hover { @@ -172,7 +172,7 @@ .btn-secondary { background: var(--color-secondary); - color: white; + color: var(--color-on-secondary); } .btn-secondary:hover { diff --git a/stoeberhunde/frontend/src/components/users/UserList.css b/stoeberhunde/frontend/src/components/users/UserList.css index 4dd50f4..03ceb1a 100644 --- a/stoeberhunde/frontend/src/components/users/UserList.css +++ b/stoeberhunde/frontend/src/components/users/UserList.css @@ -34,7 +34,7 @@ .create-button { padding: 0.5rem 1rem; background: var(--color-success); - color: white; + color: var(--color-on-success); border: none; border-radius: var(--radius-sm); cursor: pointer; diff --git a/stoeberhunde/frontend/src/index.css b/stoeberhunde/frontend/src/index.css index ec2585e..a76866f 100644 --- a/stoeberhunde/frontend/src/index.css +++ b/stoeberhunde/frontend/src/index.css @@ -1,13 +1,8 @@ -body { - margin: 0; - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', - 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', - sans-serif; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - -code { - font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', - monospace; +/* Basisstile stehen in App.css, wo auch die Design-Tokens definiert sind. + Hier stand vorher eine zweite body-Regel, die von App.css vollständig + überschrieben wurde. */ +html { + /* Verhindert, dass iOS beim Drehen die Schrift eigenmächtig vergrößert. */ + -webkit-text-size-adjust: 100%; + text-size-adjust: 100%; }