Files
geograsim/v2-platform/assets/css/design-system-v2.css
T
Adminator 1e51ef7def Nachtrag: alle bisher untracked Ordner + hängende Änderungen mit-committen
- Konzept/, didaktik_geografie/, didaktik_simulation/, v2-modules/, v2-platform/
- 12 code-workspace-Files
- STATUS-*.md
- viele M/D/R-Änderungen an bereits getrackten Files
- .gitignore verstärkt: **/.humaninput/, **/secret_keys.txt

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-07-08 02:27:02 +02:00

480 lines
16 KiB
CSS
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* ==========================================================================
GeoGraSim Design-System V2
==========================================================================
Verbindlich für alle V2-Module und V2-Plattform-UIs.
Module includen dieses File und nutzen die Tokens als CSS-Variablen.
Tokens für: Farben (Standard + High-Contrast), Spacing, Radien, Shadows,
Typografie. Plus A11y-Patterns: Focus-Indikatoren, Reduced-Motion,
Visually-Hidden, Sticky-Modal-Pattern.
Bild-Palette ≠ UI-Palette. Generierte Bilder folgen Flat-Scandinavian
(siehe v2-modules/_spec/platform-standards.md § 5).
========================================================================== */
/* ── 1. Tokens (Standard-Modus) ────────────────────────────────────────── */
:root {
/* Farben */
--ggs-fjord: #4a7c8a; --ggs-fjord-dark: #1f4e5a; --ggs-fjord-light: #dae8ec;
--ggs-moss: #5a8a5e; --ggs-moss-dark: #3a6b3e; --ggs-moss-light: #dcead0;
--ggs-sand: #e8d5b5; --ggs-sand-dark: #c4a97a;
--ggs-coral: #c85c4a; --ggs-coral-light: #f0d0ca;
--ggs-orange: #e8833a;
--ggs-bg: #f5f2eb;
--ggs-bg-dark: #e8e4d8;
--ggs-white: #ffffff;
--ggs-text: #2a2a2a;
--ggs-text-muted: #8a8a8a;
--ggs-text-light: #b0b0b0;
--ggs-border: #e0ddd4;
--ggs-success: var(--ggs-moss);
--ggs-warning: var(--ggs-orange);
--ggs-danger: var(--ggs-coral);
--ggs-info: var(--ggs-fjord);
/* Spacing */
--ggs-gap-xs: 4px;
--ggs-gap-sm: 8px;
--ggs-gap-md: 16px;
--ggs-gap-lg: 24px;
--ggs-gap-xl: 32px;
/* Radien */
--ggs-radius-sm: 6px;
--ggs-radius-md: 12px;
--ggs-radius-lg: 16px;
--ggs-radius-pill: 999px;
/* Schatten */
--ggs-shadow-sm: 0 1px 3px rgba(0,0,0,.08);
--ggs-shadow-md: 0 2px 8px rgba(0,0,0,.12);
--ggs-shadow-lg: 0 4px 16px rgba(0,0,0,.16);
/* Typografie */
--ggs-font: 'Inter', system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
--ggs-font-mono: 'JetBrains Mono', 'Fira Code', Consolas, monospace;
/* Schrift-Skalierung — wird durch [data-text-scale] überschrieben */
--ggs-font-base: 1rem; /* ~16px */
/* Touch-Targets */
--ggs-touch-min: 36px;
--ggs-touch-major: 44px; /* Schließen, Bestätigen, Abbrechen */
/* Animations-Dauern */
--ggs-anim-fast: 0.15s;
--ggs-anim-med: 0.3s;
--ggs-anim-slow: 0.6s;
}
/* ── 2. High-Contrast-Modus — hell (schwarz auf weiß) ─────────────────── */
/* Default-Variante: visuell ruhig, hohe Lesbarkeit, dunkel-saturierte Farben */
body[data-high-contrast="light"] {
--ggs-fjord: #003366; --ggs-fjord-dark: #001a4d; --ggs-fjord-light: #cfd8e6;
--ggs-moss: #1a4d1a; --ggs-moss-dark: #003300; --ggs-moss-light: #d0e6d0;
--ggs-sand: #5a3a00; --ggs-sand-dark: #3a2400;
--ggs-coral: #800000; --ggs-coral-light: #e6cccc;
--ggs-orange: #b35900;
--ggs-bg: #ffffff;
--ggs-bg-dark: #f0f0f0;
--ggs-white: #ffffff;
--ggs-text: #000000;
--ggs-text-muted: #000000;
--ggs-text-light: #1a1a1a;
--ggs-border: #000000;
}
/* ── 2b. High-Contrast-Modus — dunkel (gelb/grün auf schwarz) ─────────── */
/* Für Schüler*innen, die ein dunkles Schema bevorzugen */
body[data-high-contrast="dark"] {
--ggs-fjord: #ffff00; --ggs-fjord-dark: #ffff00; --ggs-fjord-light: #404000;
--ggs-moss: #00ff00; --ggs-moss-dark: #00ff00; --ggs-moss-light: #003300;
--ggs-sand: #ffaa00; --ggs-sand-dark: #ffaa00;
--ggs-coral: #ff6060; --ggs-coral-light: #330000;
--ggs-orange: #ffaa00;
--ggs-bg: #000000;
--ggs-bg-dark: #000000;
--ggs-white: #000000;
--ggs-text: #ffffff;
--ggs-text-muted: #e0e0e0;
--ggs-text-light: #b0b0b0;
--ggs-border: #ffffff;
}
/* Legacy-Kompatibilität: data-high-contrast="true" wird auf hell gemappt */
body[data-high-contrast="true"] {
--ggs-fjord: #003366; --ggs-fjord-dark: #001a4d;
--ggs-moss: #1a4d1a; --ggs-moss-dark: #003300;
--ggs-coral: #800000;
--ggs-bg: #ffffff; --ggs-white: #ffffff;
--ggs-text: #000000; --ggs-text-muted: #000000;
--ggs-border: #000000;
}
/* ── 3. Schrift-Skalierung (für textScale-Profil) ───────────────────────── */
body[data-text-scale="large"] { --ggs-font-base: 1.125rem; } /* ~18px */
body[data-text-scale="xlarge"] { --ggs-font-base: 1.25rem; } /* ~20px */
/* ── 4. Base Reset + Box ───────────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; padding: 0; }
html, body {
font-family: var(--ggs-font);
font-size: var(--ggs-font-base);
background: var(--ggs-bg);
color: var(--ggs-text);
line-height: 1.5;
touch-action: manipulation;
-webkit-tap-highlight-color: transparent;
}
input, textarea, select { font-size: max(16px, var(--ggs-font-base)); } /* iOS Zoom verhindern */
/* ── 5. Reduced-Motion: alles fast aus ────────────────────────────────── */
@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;
}
}
/* Plus: Profil-Setting per data-Attribut (für Module die JS-Animationen haben) */
body[data-reduced-motion="true"] *,
body[data-reduced-motion="true"] *::before,
body[data-reduced-motion="true"] *::after {
animation-duration: 0.01ms !important;
transition-duration: 0.01ms !important;
}
/* ── 6. Focus-Indikatoren (Pflicht für A11y) ─────────────────────────── */
:focus { outline: none; } /* default mouse-focus weg, aber NUR weil :focus-visible drunter setzt */
:focus-visible {
outline: 3px solid var(--ggs-fjord-dark);
outline-offset: 2px;
border-radius: 2px;
}
body[data-high-contrast="light"] :focus-visible {
outline: 3px solid #000000;
outline-offset: 2px;
}
body[data-high-contrast="dark"] :focus-visible {
outline: 3px solid #ffff00;
outline-offset: 2px;
}
body[data-high-contrast="true"] :focus-visible {
outline: 3px solid #000000;
outline-offset: 2px;
}
/* ── 7. Visually-Hidden (Screen-Reader-Only Text) ─────────────────────── */
.ggs-visually-hidden,
.visually-hidden {
position: absolute !important;
width: 1px !important;
height: 1px !important;
padding: 0 !important;
margin: -1px !important;
overflow: hidden !important;
clip: rect(0, 0, 0, 0) !important;
white-space: nowrap !important;
border: 0 !important;
}
/* Skip-Link (taucht bei Tab-Fokus auf) */
.ggs-skip-link {
position: absolute;
top: -100px;
left: var(--ggs-gap-md);
background: var(--ggs-fjord-dark);
color: var(--ggs-white);
padding: var(--ggs-gap-sm) var(--ggs-gap-md);
border-radius: var(--ggs-radius-sm);
text-decoration: none;
z-index: 9999;
transition: top var(--ggs-anim-fast);
}
.ggs-skip-link:focus { top: var(--ggs-gap-md); }
/* ── 8. Buttons ───────────────────────────────────────────────────────── */
.ggs-btn {
display: inline-flex;
align-items: center;
justify-content: center;
gap: var(--ggs-gap-sm);
font-family: inherit;
font-size: inherit;
font-weight: 600;
min-height: var(--ggs-touch-min);
padding: 0 var(--ggs-gap-md);
border-radius: var(--ggs-radius-md);
border: 2px solid transparent;
background: transparent;
color: var(--ggs-text);
cursor: pointer;
transition: background var(--ggs-anim-fast), border-color var(--ggs-anim-fast);
}
.ggs-btn-primary {
background: var(--ggs-fjord-dark);
color: var(--ggs-white);
border-color: var(--ggs-fjord-dark);
}
@media (hover: hover) {
.ggs-btn-primary:hover { background: var(--ggs-fjord); border-color: var(--ggs-fjord); }
}
.ggs-btn-primary:active { transform: translateY(1px); }
.ggs-btn-secondary {
background: var(--ggs-white);
color: var(--ggs-fjord-dark);
border-color: var(--ggs-fjord-dark);
}
.ggs-btn-ghost {
background: transparent;
color: var(--ggs-text-muted);
border-color: transparent;
}
@media (hover: hover) {
.ggs-btn-ghost:hover { background: var(--ggs-bg-dark); color: var(--ggs-text); }
}
.ggs-btn-danger {
background: var(--ggs-danger);
color: var(--ggs-white);
border-color: var(--ggs-danger);
}
.ggs-btn-major { min-height: var(--ggs-touch-major); padding: 0 var(--ggs-gap-lg); font-size: 1.05em; }
.ggs-btn[disabled] { opacity: 0.5; cursor: not-allowed; }
/* Icon-Button (kreisrund) */
.ggs-icon-btn {
width: var(--ggs-touch-min);
height: var(--ggs-touch-min);
border-radius: 50%;
display: inline-flex; align-items: center; justify-content: center;
background: var(--ggs-white);
border: 2px solid transparent;
color: var(--ggs-text);
cursor: pointer;
font-size: 1.1em;
}
.ggs-icon-btn[aria-pressed="true"] {
background: var(--ggs-fjord);
color: var(--ggs-white);
}
/* ── 9. Karten ─────────────────────────────────────────────────────────── */
.ggs-card {
background: var(--ggs-white);
border: 1px solid var(--ggs-border);
border-radius: var(--ggs-radius-lg);
padding: var(--ggs-gap-lg);
box-shadow: var(--ggs-shadow-sm);
}
.ggs-card-header {
font-size: 0.62rem;
text-transform: uppercase;
letter-spacing: 0.05em;
color: var(--ggs-text-muted);
margin-bottom: var(--ggs-gap-sm);
}
/* ── 10. Modal- und Overlay-Pattern (iPad-Pflicht) ────────────────────── */
.ggs-modal-overlay {
position: fixed;
inset: 0;
background: rgba(0,0,0,.45);
display: flex;
align-items: center;
justify-content: center;
z-index: 1000;
padding: env(safe-area-inset-top) env(safe-area-inset-right) env(safe-area-inset-bottom) env(safe-area-inset-left);
}
.ggs-modal {
background: var(--ggs-white);
border-radius: var(--ggs-radius-lg);
max-width: 720px;
width: 100%;
max-height: 94dvh; /* dvh statt vh — Pflicht für iPad */
overflow: hidden;
display: flex;
flex-direction: column;
box-shadow: var(--ggs-shadow-lg);
position: relative;
}
.ggs-modal-content {
padding: var(--ggs-gap-lg);
overflow-y: auto;
-webkit-overflow-scrolling: touch;
}
.ggs-modal-actions {
position: sticky; /* sticky am unteren Rand — Pflicht für iPad */
bottom: 0;
background: linear-gradient(to top, var(--ggs-white) 80%, transparent);
padding: var(--ggs-gap-md);
padding-bottom: max(var(--ggs-gap-md), env(safe-area-inset-bottom));
display: flex;
justify-content: flex-end;
gap: var(--ggs-gap-md);
border-top: 1px solid var(--ggs-border);
}
.ggs-modal-close {
position: absolute;
top: var(--ggs-gap-sm);
right: var(--ggs-gap-sm);
width: var(--ggs-touch-major);
height: var(--ggs-touch-major);
border-radius: 50%;
border: none;
background: var(--ggs-bg-dark);
color: var(--ggs-text);
cursor: pointer;
font-size: 1.2em;
display: inline-flex;
align-items: center;
justify-content: center;
}
/* ── 11. Form-Elemente ────────────────────────────────────────────────── */
.ggs-input, .ggs-select, .ggs-textarea {
width: 100%;
padding: var(--ggs-gap-sm) var(--ggs-gap-md);
border: 2px solid var(--ggs-border);
border-radius: var(--ggs-radius-md);
background: var(--ggs-white);
color: var(--ggs-text);
font-family: inherit;
font-size: max(16px, var(--ggs-font-base));
min-height: var(--ggs-touch-min);
}
.ggs-input:focus, .ggs-select:focus, .ggs-textarea:focus {
border-color: var(--ggs-fjord-dark);
}
.ggs-label {
display: block;
font-size: 0.85em;
color: var(--ggs-text-muted);
margin-bottom: var(--ggs-gap-xs);
font-weight: 600;
}
/* ── 12. Status-Pills (Erfolg/Warnung/Danger) ─────────────────────────── */
.ggs-pill {
display: inline-flex;
align-items: center;
gap: var(--ggs-gap-xs);
padding: 2px var(--ggs-gap-sm);
border-radius: var(--ggs-radius-pill);
font-size: 0.78em;
font-weight: 700;
}
.ggs-pill-success { background: var(--ggs-moss-light); color: var(--ggs-moss-dark); }
.ggs-pill-warning { background: #fff3cd; color: #8a5a00; }
.ggs-pill-danger { background: var(--ggs-coral-light); color: #862d20; }
.ggs-pill-info { background: var(--ggs-fjord-light); color: var(--ggs-fjord-dark); }
/* Information mit Icon (nicht nur Farbe — A11y-Pflicht) */
.ggs-pill::before {
content: attr(data-icon);
font-weight: 900;
}
/* ── 13. Live-Region für Score-/Phase-Updates (A11y-Stufe-2-Vorbereitung) ── */
.ggs-live-region {
/* Visuell: nichts. Aber Screen-Reader liest aria-live="polite" mit. */
}
/* ── 14. Stuck-Banner-Pattern ─────────────────────────────────────────── */
.ggs-stuck-banner {
background: #fff3cd;
border-left: 4px solid var(--ggs-orange);
padding: var(--ggs-gap-md);
border-radius: var(--ggs-radius-md);
font-size: 0.9em;
color: #8a5a00;
}
body[data-high-contrast="light"] .ggs-stuck-banner {
background: #ffffff;
color: #5a3a00;
border: 2px solid #5a3a00;
}
body[data-high-contrast="dark"] .ggs-stuck-banner {
background: #ffaa00;
color: #000;
border-left-color: #ffff00;
}
/* ── 15. Avatare ──────────────────────────────────────────────────────── */
.ggs-avatar {
width: 40px;
height: 40px;
border-radius: 50%;
background: var(--ggs-fjord-light);
object-fit: cover;
border: 2px solid var(--ggs-white);
box-shadow: var(--ggs-shadow-sm);
}
.ggs-avatar-lg { width: 64px; height: 64px; }
.ggs-avatar-xl { width: 96px; height: 96px; }
/* ── 16. Layout-Helper ────────────────────────────────────────────────── */
.ggs-stack { display: flex; flex-direction: column; gap: var(--ggs-gap-md); }
.ggs-row { display: flex; flex-direction: row; gap: var(--ggs-gap-md); align-items: center; }
.ggs-row-end { justify-content: flex-end; }
.ggs-row-between { justify-content: space-between; }
.ggs-spacer { flex: 1; }
/* ── 17. Responsive Layout-Breakpoints ────────────────────────────────── */
/* Desktop ≥ 1200px: dreispaltig
iPad Landscape 9001199px: dreispaltig kompakter
iPad Portrait / Mobile < 900px: einspaltig */
.ggs-layout-3col {
display: grid;
grid-template-columns: 240px 1fr 280px;
gap: var(--ggs-gap-lg);
}
@media (max-width: 1199px) {
.ggs-layout-3col { grid-template-columns: 210px 1fr 250px; gap: var(--ggs-gap-md); }
}
@media (max-width: 899px) {
.ggs-layout-3col { grid-template-columns: 1fr; }
}
/* ── 18. Notes für Modul-Entwickler*innen ────────────────────────────── */
/*
- Hex-Werte NICHT hardcoden — immer var(--ggs-...) nutzen.
- Modul-eigene Farben (z.B. Wettersymbole) als --<modul>-* lokal definieren,
aber GGS-Tokens als Fallback einbinden.
- Eigene Modale: bitte .ggs-modal/.ggs-modal-actions/.ggs-modal-close nutzen,
nicht eigene Modal-Klassen — sonst geht das iPad-Pattern verloren.
- Information NIE nur durch Farbe vermitteln — immer Icon + Farbe.
- Bei Auto-Play-Animationen: prefers-reduced-motion respektieren UND
im UI einen Stop-Button anbieten.
*/