335 lines
9.4 KiB
CSS
335 lines
9.4 KiB
CSS
* {
|
||
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 {
|
||
/* Sagt dem Browser, dass die Seite beide Ansichten kann. Native Bedienelemente
|
||
— Checkboxen, Auswahllisten, Bildlaufleisten — passen sich dadurch an,
|
||
statt in der Nachtansicht hell aufzublitzen. */
|
||
color-scheme: light dark;
|
||
|
||
--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: #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);
|
||
}
|
||
|
||
/* 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;
|
||
}
|
||
|
||
/* Checkbox, Radio und Schieberegler in der Markenfarbe statt im Browser-Blau. */
|
||
input[type="checkbox"],
|
||
input[type="radio"],
|
||
input[type="range"] {
|
||
accent-color: var(--color-primary);
|
||
}
|
||
|
||
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;
|
||
transition: background 0.2s, box-shadow 0.2s, transform 0.2s;
|
||
}
|
||
|
||
.btn:disabled {
|
||
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: var(--color-on-primary);
|
||
}
|
||
|
||
.btn-primary:hover:not(:disabled) {
|
||
background: var(--color-primary-dark);
|
||
transform: translateY(-1px);
|
||
}
|
||
|
||
.btn-secondary {
|
||
background: var(--color-secondary);
|
||
color: var(--color-on-secondary);
|
||
}
|
||
|
||
.btn-secondary:hover:not(:disabled) {
|
||
background: var(--color-secondary-dark);
|
||
transform: translateY(-1px);
|
||
}
|
||
|
||
.btn-danger {
|
||
background: var(--color-danger);
|
||
color: var(--color-on-danger);
|
||
}
|
||
|
||
.btn-danger:hover:not(:disabled) {
|
||
background: var(--color-danger-dark);
|
||
transform: translateY(-1px);
|
||
}
|
||
|
||
.input,
|
||
.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;
|
||
}
|
||
|
||
.input:focus,
|
||
.select:focus,
|
||
.textarea:focus {
|
||
outline: none;
|
||
border-color: var(--color-primary);
|
||
box-shadow: 0 0 0 3px var(--color-focus);
|
||
}
|
||
|
||
.panel-title {
|
||
margin: 0 0 var(--space-2);
|
||
font-family: var(--font-display);
|
||
font-size: 1.1rem;
|
||
color: var(--color-text);
|
||
}
|
||
|
||
/* ── Grundgerüst ────────────────────────────────────────────────────────── */
|
||
|
||
.App {
|
||
/* dvh statt vh: mit ein- und ausblendender Adressleiste auf Mobilgeräten
|
||
entsteht mit vh sonst Überlauf. */
|
||
min-height: 100dvh;
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
|
||
.app-main {
|
||
flex: 1;
|
||
padding: 0;
|
||
}
|
||
|
||
.app-loading {
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
min-height: 100dvh;
|
||
font-size: 1.2rem;
|
||
color: var(--color-text-muted);
|
||
}
|
||
|
||
/* 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;
|
||
}
|
||
|
||
.btn:hover:not(:disabled),
|
||
.btn-primary:hover:not(:disabled),
|
||
.btn-secondary:hover:not(:disabled),
|
||
.btn-danger:hover:not(:disabled) {
|
||
transform: none;
|
||
}
|
||
}
|