wannpassts/frontend/src/styles/main.css
Tronax f220d96e3b
feat(frontend): add dark/light theme toggle with system detection
- Add ThemeToggle component (Auto / Dark / Light) to all views
- Store preference per browser and detect system preference live
  via prefers-color-scheme
- Apply theme before first render in index.html to prevent flash
- Extend CSS with light theme variables and refactor glass styles
2026-08-25 18:59:12 +02:00

376 lines
14 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.

/* ─── WannPassts · Liquid Glass (Dark & Light) ────────────────────────────── */
/* Dunkles Design = Standard */
:root {
color-scheme: dark;
--bg-0: #05070c;
--bg-1: #0a0e18;
--text: #eef1f8;
--text-muted: rgba(238, 241, 248, 0.58);
--text-faint: rgba(238, 241, 248, 0.34);
--border: rgba(255, 255, 255, 0.13);
--border-soft: rgba(255, 255, 255, 0.08);
--border-strong: rgba(255, 255, 255, 0.24);
--glass-fill: linear-gradient(150deg, rgba(255, 255, 255, 0.085), rgba(255, 255, 255, 0.028));
--glass-soft-fill: rgba(255, 255, 255, 0.04);
--input-bg: rgba(255, 255, 255, 0.05);
--input-bg-focus: rgba(255, 255, 255, 0.07);
--btn-fill: linear-gradient(150deg, rgba(255, 255, 255, 0.10), rgba(255, 255, 255, 0.04));
--btn-hover-shadow: 0 10px 30px rgba(0, 0, 0, 0.35);
--card-shadow: 0 24px 60px rgba(0, 0, 0, 0.45), inset 0 1px 0 rgba(255, 255, 255, 0.10);
--inset-hi: rgba(255, 255, 255, 0.10);
--option-bg: #10141f;
--tabs-bg: rgba(255, 255, 255, 0.035);
--tab-active-fill: linear-gradient(150deg, rgba(255, 255, 255, 0.14), rgba(255, 255, 255, 0.06));
--orb-opacity: 0.45;
--glow-a: rgba(125, 176, 255, 0.10);
--glow-b: rgba(183, 140, 255, 0.09);
--glow-c: rgba(111, 227, 196, 0.06);
--accent: #7db0ff;
--accent-2: #b78cff;
--accent-3: #6fe3c4;
--danger: #ff7a8a;
--ok: #46e0a5;
--radius-lg: 24px;
--radius-md: 16px;
--radius-sm: 12px;
--font: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
}
/* Helles Design aktiv per html[data-theme="light"] (Auto/Dunkel/Hell-Umschalter) */
html[data-theme='light'] {
color-scheme: light;
--bg-0: #e7ebf3;
--bg-1: #fbfcfe;
--text: #171c26;
--text-muted: rgba(23, 28, 38, 0.62);
--text-faint: rgba(23, 28, 38, 0.40);
--border: rgba(24, 34, 64, 0.16);
--border-soft: rgba(24, 34, 64, 0.10);
--border-strong: rgba(24, 34, 64, 0.30);
--glass-fill: linear-gradient(150deg, rgba(255, 255, 255, 0.75), rgba(255, 255, 255, 0.45));
--glass-soft-fill: rgba(255, 255, 255, 0.55);
--input-bg: rgba(255, 255, 255, 0.65);
--input-bg-focus: rgba(255, 255, 255, 0.85);
--btn-fill: linear-gradient(150deg, rgba(255, 255, 255, 0.85), rgba(255, 255, 255, 0.55));
--btn-hover-shadow: 0 10px 30px rgba(35, 48, 90, 0.16);
--card-shadow: 0 24px 60px rgba(35, 48, 90, 0.13), inset 0 1px 0 rgba(255, 255, 255, 0.7);
--inset-hi: rgba(255, 255, 255, 0.65);
--option-bg: #ffffff;
--tabs-bg: rgba(255, 255, 255, 0.5);
--tab-active-fill: linear-gradient(150deg, rgba(255, 255, 255, 0.92), rgba(255, 255, 255, 0.62));
--orb-opacity: 0.22;
--glow-a: rgba(90, 140, 235, 0.14);
--glow-b: rgba(150, 105, 230, 0.12);
--glow-c: rgba(80, 200, 170, 0.10);
--accent: #3f74d6;
--accent-2: #8350d8;
--accent-3: #12a179;
--danger: #d9374c;
--ok: #0c9e63;
}
* { box-sizing: border-box; }
html, body {
margin: 0;
padding: 0;
min-height: 100%;
}
body {
font-family: var(--font);
color: var(--text);
background:
radial-gradient(1200px 800px at 85% -10%, var(--glow-a), transparent 60%),
radial-gradient(1000px 700px at -10% 30%, var(--glow-b), transparent 55%),
radial-gradient(900px 600px at 50% 110%, var(--glow-c), transparent 60%),
linear-gradient(180deg, var(--bg-1), var(--bg-0));
background-attachment: fixed;
-webkit-font-smoothing: antialiased;
letter-spacing: 0.01em;
transition: color 0.2s ease;
}
#app { min-height: 100vh; }
/* Farbliche "Orbs" hinter allem geben dem Glass etwas zum Brechen */
.bg-scene { position: fixed; inset: 0; z-index: -1; overflow: hidden; pointer-events: none; }
.orb {
position: absolute;
border-radius: 50%;
filter: blur(110px);
opacity: var(--orb-opacity);
animation: orb-drift 26s ease-in-out infinite alternate;
}
.orb-1 { width: 46vw; height: 46vw; left: -10vw; top: -14vh; background: radial-gradient(circle, #2b5cc4, transparent 70%); }
.orb-2 { width: 40vw; height: 40vw; right: -8vw; top: 22vh; background: radial-gradient(circle, #6d3fb8, transparent 70%); animation-delay: -8s; }
.orb-3 { width: 34vw; height: 34vw; left: 28vw; bottom: -18vh; background: radial-gradient(circle, #1a7f68, transparent 70%); animation-delay: -16s; }
@keyframes orb-drift {
from { transform: translate3d(0, 0, 0) scale(1); }
to { transform: translate3d(6vw, 5vh, 0) scale(1.12); }
}
@media (prefers-reduced-motion: reduce) {
.orb { animation: none; }
* { transition-duration: 0.01ms !important; animation-duration: 0.01ms !important; }
}
/* ─── Glass-Bausteine ─────────────────────────────────────────────────────── */
.glass {
background: var(--glass-fill);
backdrop-filter: blur(26px) saturate(170%);
-webkit-backdrop-filter: blur(26px) saturate(170%);
border: 1px solid var(--border);
border-radius: var(--radius-lg);
box-shadow: var(--card-shadow);
}
.glass-soft {
background: var(--glass-soft-fill);
border: 1px solid var(--border-soft);
border-radius: var(--radius-md);
backdrop-filter: blur(12px);
-webkit-backdrop-filter: blur(12px);
}
/* ─── Layout ──────────────────────────────────────────────────────────────── */
.page {
max-width: 1060px;
margin: 0 auto;
padding: 24px 20px 80px;
}
.row { display: flex; gap: 12px; align-items: center; }
.col { display: flex; flex-direction: column; gap: 12px; }
.grow { flex: 1; }
.muted { color: var(--text-muted); }
.faint { color: var(--text-faint); }
.small { font-size: 13px; }
/* ─── Buttons ─────────────────────────────────────────────────────────────── */
.btn {
appearance: none;
border: 1px solid var(--border);
border-radius: 999px;
background: var(--btn-fill);
color: var(--text);
font: 600 14px/1 var(--font);
padding: 11px 20px;
cursor: pointer;
backdrop-filter: blur(14px);
-webkit-backdrop-filter: blur(14px);
transition: transform 0.15s ease, box-shadow 0.15s ease, border-color 0.15s ease, opacity 0.15s ease;
}
.btn:hover { transform: translateY(-1px); border-color: var(--border-strong); box-shadow: var(--btn-hover-shadow); }
.btn:active { transform: translateY(0); }
.btn:disabled { opacity: 0.45; cursor: not-allowed; transform: none; }
.btn-primary {
background: linear-gradient(135deg, var(--accent), var(--accent-2));
border: none;
color: #071018;
box-shadow: 0 10px 34px rgba(125, 176, 255, 0.35), inset 0 1px 0 rgba(255, 255, 255, 0.35);
}
.btn-primary:hover { box-shadow: 0 14px 40px rgba(125, 176, 255, 0.5), inset 0 1px 0 rgba(255, 255, 255, 0.35); }
.btn-danger {
border-color: rgba(255, 122, 138, 0.4);
color: var(--danger);
background: rgba(255, 122, 138, 0.08);
}
.btn-danger:hover { border-color: rgba(255, 122, 138, 0.7); box-shadow: 0 8px 24px rgba(255, 122, 138, 0.18); }
.btn-sm { padding: 8px 14px; font-size: 13px; }
/* ─── Formulare ───────────────────────────────────────────────────────────── */
label.field { display: flex; flex-direction: column; gap: 7px; }
label.field > span { font-size: 13px; color: var(--text-muted); font-weight: 500; }
.input, select.input, textarea.input {
width: 100%;
background: var(--input-bg);
border: 1px solid var(--border);
border-radius: var(--radius-sm);
color: var(--text);
font: 500 14px/1.4 var(--font);
padding: 11px 14px;
outline: none;
transition: border-color 0.15s ease, box-shadow 0.15s ease, background 0.15s ease;
}
.input:focus {
border-color: rgba(125, 176, 255, 0.65);
box-shadow: 0 0 0 3px rgba(125, 176, 255, 0.18);
background: var(--input-bg-focus);
}
.input::placeholder { color: var(--text-faint); }
select.input option { background: var(--option-bg); color: var(--text); }
textarea.input { resize: vertical; min-height: 84px; }
/* ─── Badges & Chips ──────────────────────────────────────────────────────── */
.badge {
display: inline-flex;
align-items: center;
gap: 6px;
font-size: 12px;
font-weight: 600;
padding: 4px 11px;
border-radius: 999px;
border: 1px solid var(--border);
background: var(--glass-soft-fill);
color: var(--text-muted);
}
.badge-pending { border-color: rgba(125, 176, 255, 0.45); color: var(--accent); background: rgba(125, 176, 255, 0.10); }
.badge-accepted { border-color: rgba(70, 224, 165, 0.45); color: var(--ok); background: rgba(70, 224, 165, 0.10); }
.badge-declined { border-color: rgba(255, 122, 138, 0.4); color: var(--danger); background: rgba(255, 122, 138, 0.08); }
/* ─── Tabs ────────────────────────────────────────────────────────────────── */
.tabs {
display: flex;
gap: 6px;
padding: 6px;
border-radius: 999px;
border: 1px solid var(--border-soft);
background: var(--tabs-bg);
backdrop-filter: blur(18px);
-webkit-backdrop-filter: blur(18px);
overflow-x: auto;
scrollbar-width: none;
}
.tabs::-webkit-scrollbar { display: none; }
.tab {
flex: 1;
white-space: nowrap;
appearance: none;
border: none;
background: transparent;
color: var(--text-muted);
font: 600 14px/1 var(--font);
padding: 10px 18px;
border-radius: 999px;
cursor: pointer;
transition: background 0.15s ease, color 0.15s ease, box-shadow 0.15s ease;
}
.tab:hover { color: var(--text); }
.tab.active {
color: var(--text);
background: var(--tab-active-fill);
box-shadow: inset 0 1px 0 var(--inset-hi), 0 6px 18px rgba(0, 0, 0, 0.12);
}
/* ─── Toasts ──────────────────────────────────────────────────────────────── */
.toasts {
position: fixed;
bottom: 22px;
left: 50%;
transform: translateX(-50%);
display: flex;
flex-direction: column;
gap: 10px;
z-index: 100;
width: min(480px, calc(100vw - 32px));
}
.toast {
padding: 13px 18px;
font-size: 14px;
font-weight: 500;
animation: toast-in 0.25s ease;
}
.toast-ok { border-color: rgba(70, 224, 165, 0.5); }
.toast-error { border-color: rgba(255, 122, 138, 0.5); }
@keyframes toast-in { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }
/* ─── Slot-Chips (Buchungsseite) ──────────────────────────────────────────── */
.slot-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(88px, 1fr));
gap: 10px;
}
.slot-chip {
appearance: none;
border: 1px solid var(--border-soft);
border-radius: var(--radius-sm);
background: var(--glass-soft-fill);
color: var(--text-muted);
font: 600 14px/1 var(--font);
padding: 12px 0;
cursor: pointer;
transition: all 0.13s ease;
}
.slot-chip:hover:not(:disabled) {
color: var(--text);
border-color: rgba(125, 176, 255, 0.5);
background: rgba(125, 176, 255, 0.10);
}
.slot-chip.selected {
color: #071018;
background: linear-gradient(135deg, var(--accent), var(--accent-2));
border-color: transparent;
box-shadow: 0 8px 26px rgba(125, 176, 255, 0.4);
}
.slot-chip:disabled { opacity: 0.28; cursor: not-allowed; text-decoration: line-through; }
/* ─── Day-Picker ──────────────────────────────────────────────────────────── */
.day-strip {
display: flex;
gap: 9px;
overflow-x: auto;
padding-bottom: 6px;
scrollbar-width: thin;
}
.day-chip {
appearance: none;
flex: 0 0 auto;
min-width: 74px;
border: 1px solid var(--border-soft);
border-radius: var(--radius-md);
background: var(--glass-soft-fill);
color: var(--text-muted);
font-family: var(--font);
padding: 10px 8px;
cursor: pointer;
display: flex;
flex-direction: column;
align-items: center;
gap: 3px;
transition: all 0.13s ease;
}
.day-chip:hover { border-color: var(--border); color: var(--text); }
.day-chip.selected {
color: var(--text);
border-color: rgba(125, 176, 255, 0.55);
background: linear-gradient(150deg, rgba(125, 176, 255, 0.16), rgba(183, 140, 255, 0.10));
box-shadow: inset 0 1px 0 var(--inset-hi), 0 8px 24px rgba(0, 0, 0, 0.12);
}
.day-chip .wd { font-size: 11px; text-transform: uppercase; letter-spacing: 0.08em; }
.day-chip .dom { font-size: 20px; font-weight: 700; color: inherit; }
.day-chip .mon { font-size: 11px; }
/* ─── Verschiedenes ───────────────────────────────────────────────────────── */
.divider { height: 1px; background: var(--border-soft); border: none; margin: 4px 0; }
.skeleton {
border-radius: var(--radius-md);
background: linear-gradient(100deg, rgba(140, 150, 170, 0.10) 40%, rgba(140, 150, 170, 0.22) 50%, rgba(140, 150, 170, 0.10) 60%);
background-size: 200% 100%;
animation: shimmer 1.4s infinite;
}
@keyframes shimmer { to { background-position: -200% 0; } }
.fade-enter-active, .fade-leave-active { transition: opacity 0.18s ease, transform 0.18s ease; }
.fade-enter-from, .fade-leave-to { opacity: 0; transform: translateY(6px); }
@media (max-width: 640px) {
.page { padding: 16px 14px 64px; }
}