Files
Calendarr/frontend/css/app.css
Scarriffle 37e5507261 feat(web): admin theme import + branding dimension hints
- Admin default-theme editor: "Theme importieren" button loads a .theme.json
  into the editor (colours only, live preview) so an imported theme can be set
  as the instance default (still confirmed via "Standard speichern").
- Branding: drop the "Standard" placeholder; show pixel-dimension hints instead
  (logo shown at max 150×40, favicon 128×128). Logo preview box now mirrors its
  real topbar footprint.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-20 14:33:59 +02:00

2396 lines
90 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.
/* ═══════════════════════════════════════════════════════
Calendarr — Dark-Mode-first CSS
═══════════════════════════════════════════════════════ */
/* ── Variables ─────────────────────────────────────────── */
:root {
--primary: #4285f4;
--primary-dim: rgba(66,133,244,.15);
--accent: #ea4335;
--today-color: #4285f4;
--bg-app: #0e0e14;
--bg-topbar: #18181f;
--bg-sidebar: #18181f;
--bg-surface: #22222c;
--bg-hover: #2a2a38;
--bg-active: #32324a;
--text-1: #e8e8f0;
--text-2: #9090aa;
--text-3: #55556a;
--border: #2e2e40;
--border-light: #242438;
--scrollbar: #30303c;
/* Fine-grained element colours (customisable via Settings → Farben).
Defaults reference the derived values so the look is unchanged until the
user overrides them; applyTheme() writes concrete overrides on top. */
--hover-highlight: var(--bg-hover); /* general interactive hover */
--icon-inactive-color: var(--text-2); /* sidebar action icons: resting/off/not-hovered */
--icon-active-color: var(--text-1); /* sidebar action icons: hovered / on / pressed */
--day-hover-color: var(--bg-hover); /* calendar day-cell hover */
--day-selected-base: var(--primary); /* selected day (tinted via color-mix) */
--day-bg: transparent; /* normal day background */
--today-bg-base: var(--today-color); /* today's day (tinted via color-mix) */
--topbar-h: 64px;
--sidebar-w: 256px;
--shadow: 0 2px 12px rgba(0,0,0,.45);
--shadow-lg: 0 8px 28px rgba(0,0,0,.55);
--radius: 8px;
--radius-sm: 4px;
--transition: .15s ease;
}
/* ── Reset ──────────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
html, body { height: 100%; overflow: hidden; }
body {
font-family: 'Google Sans', 'Roboto', system-ui, sans-serif;
background: var(--bg-app);
color: var(--text-1);
font-size: 14px;
line-height: 1.5;
}
input, select, textarea, button { font-family: inherit; font-size: inherit; color: inherit; }
button { cursor: pointer; border: none; background: none; }
/* Treat the app like native UI chrome: clicking a heading, button, icon or
dropdown must not place a blinking text caret or select the label. Real text
entry (inputs / textareas) opts selection back in. */
body { -webkit-user-select: none; user-select: none; }
input, textarea, [contenteditable="true"], .selectable {
-webkit-user-select: text; user-select: text;
}
a { color: var(--primary); text-decoration: none; }
::-webkit-scrollbar { width: 6px; height: 6px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: var(--scrollbar); border-radius: 3px; }
/* ── Utilities ──────────────────────────────────────────── */
.hidden { display: none !important; }
.flex { display: flex; }
.flex-col { display: flex; flex-direction: column; }
.gap-8 { gap: 8px; }
/* ── Buttons ──────────────────────────────────────────────
Modern pill style: fully rounded, subtle coloured shadow on the
prominent variants, lift on hover, snap back on press. The
primary-coloured glow follows --primary via color-mix(), so it adapts
when the user changes the theme colour in settings. */
.btn {
display: inline-flex; align-items: center; justify-content: center;
gap: 8px;
padding: 10px 22px;
border-radius: 999px;
font-weight: 500; font-size: 14px;
letter-spacing: .1px;
white-space: nowrap;
user-select: none;
-webkit-tap-highlight-color: transparent;
transition:
background var(--transition),
color var(--transition),
border-color var(--transition),
box-shadow .18s ease,
transform .12s ease,
filter var(--transition);
}
.btn:active { transform: translateY(0) scale(.985); transition-duration: .05s; }
.btn:focus-visible {
outline: 2px solid var(--primary);
outline-offset: 2px;
}
.btn-primary {
background: var(--primary);
color: #fff;
box-shadow: 0 2px 8px rgba(66,133,244,.28);
box-shadow: 0 2px 8px color-mix(in srgb, var(--primary) 30%, transparent);
}
.btn-primary:hover {
filter: brightness(1.08);
transform: translateY(-1px);
box-shadow: 0 6px 18px rgba(66,133,244,.42);
box-shadow: 0 6px 18px color-mix(in srgb, var(--primary) 45%, transparent);
}
.btn-secondary {
background: var(--bg-surface);
color: var(--text-1);
border: 1px solid var(--border);
}
.btn-secondary:hover {
background: var(--bg-hover);
border-color: var(--primary);
transform: translateY(-1px);
}
.btn-ghost {
color: var(--primary);
background: transparent;
}
.btn-ghost:hover {
background: var(--primary-dim);
transform: translateY(-1px);
}
.btn-danger {
background: var(--accent);
color: #fff;
box-shadow: 0 2px 8px rgba(234,67,53,.28);
box-shadow: 0 2px 8px color-mix(in srgb, var(--accent) 30%, transparent);
}
.btn-danger:hover {
filter: brightness(1.08);
transform: translateY(-1px);
box-shadow: 0 6px 18px rgba(234,67,53,.42);
box-shadow: 0 6px 18px color-mix(in srgb, var(--accent) 45%, transparent);
}
.btn-full { width: 100%; }
/* The big sidebar "Erstellen" button: same pill aesthetic, primary tinted,
lives in the calm dark sidebar so the shadow is a touch stronger. */
.btn-fab {
display: flex; align-items: center; gap: 10px;
padding: 12px 22px;
border-radius: 999px;
background: var(--primary);
color: #fff;
font-weight: 600;
margin: 16px 12px 8px;
box-shadow: 0 4px 14px rgba(66,133,244,.32);
box-shadow: 0 4px 14px color-mix(in srgb, var(--primary) 35%, transparent);
transition:
background var(--transition),
box-shadow .18s ease,
transform .12s ease,
filter var(--transition);
}
.btn-fab:hover {
filter: brightness(1.08);
transform: translateY(-1px);
box-shadow: 0 8px 22px rgba(66,133,244,.5);
box-shadow: 0 8px 22px color-mix(in srgb, var(--primary) 50%, transparent);
}
.btn-fab:active { transform: translateY(0) scale(.985); }
/* Split create button: one seamless pill — main "Erstellen" action on the left,
a caret section on the right that opens a small menu (new event / new birthday). */
.create-split {
display: flex; align-items: stretch; margin: 16px 12px 8px;
border-radius: 999px;
box-shadow: 0 4px 14px color-mix(in srgb, var(--primary) 35%, transparent);
}
.create-split .btn-fab { margin: 0; box-shadow: none; border-radius: 0; }
.create-split .btn-fab:hover { transform: none; box-shadow: none; filter: brightness(1.08); }
.create-split .create-main { flex: 1; justify-content: center; border-radius: 999px 0 0 999px; }
.create-split .create-caret {
flex: 0 0 auto; padding: 12px 14px; border-radius: 0 999px 999px 0;
border-left: 1px solid color-mix(in srgb, #fff 25%, transparent);
}
.create-split .create-caret svg { width: 18px; height: 18px; }
.create-menu { left: 0; right: auto; min-width: 200px; }
/* Birthday modal: day / month / year row */
.birthday-date-row { display: flex; gap: 8px; }
.birthday-date-row select { flex: 1; }
.birthday-date-row #birthday-year { width: 90px; flex: 0 0 auto; }
/* Circular icon buttons (topbar nav, modal close, etc.) */
.icon-btn {
display: inline-flex; align-items: center; justify-content: center;
width: 40px; height: 40px;
border-radius: 50%;
color: var(--text-2);
flex-shrink: 0;
-webkit-tap-highlight-color: transparent;
transition:
background var(--transition),
color var(--transition),
transform .1s ease;
}
.icon-btn svg { width: 20px; height: 20px; fill: currentColor; }
.icon-btn:hover { background: var(--hover-highlight); color: var(--text-1); }
.icon-btn:active { transform: scale(.92); }
.icon-btn:focus-visible {
outline: 2px solid var(--primary);
outline-offset: 2px;
}
/* ── Auth Screens ───────────────────────────────────────── */
.auth-screen {
position: fixed; inset: 0;
display: flex; align-items: center; justify-content: center;
background: var(--bg-app);
z-index: 1000;
}
.auth-card {
background: var(--bg-surface);
border: 1px solid var(--border);
border-radius: var(--radius);
padding: 40px;
width: 100%; max-width: 400px;
box-shadow: var(--shadow-lg);
}
.auth-logo {
display: flex; align-items: center; gap: 10px;
margin-bottom: 24px;
}
.auth-logo .logo-icon { display: block; color: var(--primary); }
.auth-logo h1 { font-size: 24px; font-weight: 600; color: var(--text-1); margin: 0; }
.auth-tagline { font-size: 12px; color: var(--text-3); margin: 2px 0 0; }
.auth-card h2 { font-size: 18px; margin-bottom: 4px; }
.auth-sub { color: var(--text-2); margin-bottom: 24px; }
.impressum-link {
position: absolute; bottom: 20px; left: 50%; transform: translateX(-50%);
background: none; border: none; cursor: pointer;
font-size: 12px; color: var(--text-3);
transition: color var(--transition); white-space: nowrap;
}
.impressum-link:hover { color: var(--text-1); }
/* ── Forms ──────────────────────────────────────────────── */
.form-group {
display: flex; flex-direction: column; gap: 6px;
margin-bottom: 16px;
}
.form-group label { color: var(--text-2); font-size: 12px; font-weight: 500; text-transform: uppercase; letter-spacing: .5px; }
.form-group input, .form-group select, .form-group textarea {
background: var(--bg-app);
border: 1px solid var(--border);
border-radius: 8px;
padding: 11px 14px;
color: var(--text-1);
outline: none;
transition: border-color var(--transition), box-shadow var(--transition);
width: 100%;
}
.form-group input:hover:not(:focus),
.form-group select:hover:not(:focus),
.form-group textarea:hover:not(:focus) {
border-color: var(--text-3);
}
.form-group input:focus, .form-group select:focus, .form-group textarea:focus {
border-color: var(--primary);
box-shadow: 0 0 0 3px rgba(66,133,244,.18);
box-shadow: 0 0 0 3px color-mix(in srgb, var(--primary) 18%, transparent);
}
.form-group textarea { resize: vertical; }
/* ── Custom calendar dropdown (shows colour dot + group icon) ── */
.cal-native-hidden { display: none !important; }
.cal-select { position: relative; }
.cal-select-trigger {
display: flex; align-items: center; gap: 8px;
width: 100%;
background: var(--bg-app);
border: 1px solid var(--border);
border-radius: 8px;
padding: 11px 14px;
color: var(--text-1);
cursor: pointer;
transition: border-color var(--transition), box-shadow var(--transition);
}
.cal-select-trigger:hover { border-color: var(--text-3); }
.cal-select[data-open="1"] .cal-select-trigger {
border-color: var(--primary);
box-shadow: 0 0 0 3px color-mix(in srgb, var(--primary) 18%, transparent);
}
.cal-select-current { display: flex; align-items: center; gap: 8px; flex: 1; min-width: 0; }
.cal-select-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cal-select-chevron { flex-shrink: 0; color: var(--text-3); }
.cal-select-dot { width: 12px; height: 12px; border-radius: 50%; flex-shrink: 0; }
.cal-select-gicon { display: inline-flex; color: var(--text-2); flex-shrink: 0; }
.cal-select-gicon svg { display: block; }
.cal-select-menu {
position: absolute; left: 0; right: 0; top: calc(100% + 4px);
background: var(--bg-surface);
border: 1px solid var(--border);
border-radius: 12px;
box-shadow: var(--shadow-lg);
max-height: 280px; overflow-y: auto;
z-index: 50; padding: 4px;
}
.cal-select-section {
font-size: 11px; color: var(--text-3); font-weight: 600;
padding: 8px 10px 4px; text-transform: uppercase; letter-spacing: .4px;
}
.cal-select-option {
display: flex; align-items: center; gap: 8px;
padding: 9px 10px; border-radius: 8px; cursor: pointer;
}
.cal-select-option:hover { background: var(--hover-highlight); }
.cal-select-option.selected { background: var(--primary-dim); }
/* ── Date/time input dark mode ──────────────────────────── */
.form-group input[type="datetime-local"],
.form-group input[type="date"] {
color-scheme: dark;
}
.form-group input[type="datetime-local"]::-webkit-calendar-picker-indicator,
.form-group input[type="date"]::-webkit-calendar-picker-indicator {
filter: invert(0.8);
opacity: 0.7;
cursor: pointer;
}
.form-row {
display: flex; gap: 12px; margin-bottom: 16px; align-items: center;
}
.form-group.half { flex: 1; margin-bottom: 0; }
.form-error {
background: rgba(234,67,53,.15);
border: 1px solid rgba(234,67,53,.4);
border-radius: var(--radius-sm);
padding: 10px 12px;
color: #f28b82;
margin-bottom: 12px;
}
.input-title {
font-size: 20px !important; font-weight: 500;
background: transparent !important;
border: none !important;
border-bottom: 2px solid var(--border) !important;
border-radius: 0 !important;
padding: 8px 0 !important;
margin-bottom: 8px;
}
.input-title:focus { border-bottom-color: var(--primary) !important; }
.toggle-label {
display: flex; align-items: center; gap: 8px;
cursor: pointer; color: var(--text-1);
}
.toggle-label input[type=checkbox] { width: 16px; height: 16px; accent-color: var(--primary); }
.color-input {
width: 52px; height: 40px; padding: 3px;
border-radius: var(--radius-sm);
border: 1px solid var(--border);
background: var(--bg-surface);
cursor: pointer;
outline: none;
}
.color-input::-webkit-color-swatch-wrapper { padding: 2px; }
.color-input::-webkit-color-swatch { border-radius: 3px; border: none; }
.color-row { display: flex; align-items: center; gap: 10px; }
.color-label { font-size: 12px; color: var(--text-2); font-family: monospace; }
/* ── Color Picker ───────────────────────────────────────── */
.color-picker { display: flex; gap: 8px; flex-wrap: wrap; }
.color-swatch {
width: 28px; height: 28px; border-radius: 50%; cursor: pointer;
border: 3px solid transparent;
transition: border-color var(--transition), transform var(--transition);
}
.color-swatch:hover { transform: scale(1.15); }
.color-swatch.active { border-color: var(--text-1); }
.ev-color-row { display: flex; align-items: center; gap: 8px; }
.ev-reminders-list { display: flex; flex-direction: column; gap: 6px; margin-bottom: 6px; }
.ev-reminder-row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.ev-reminder-row > select { flex: 1; min-width: 120px; }
.ev-reminder-remove { flex-shrink: 0; }
.ev-reminder-custom { display: inline-flex; align-items: center; gap: 6px; flex-basis: 100%; }
.ev-reminder-custom input[type="number"] { width: 64px; }
.ev-reminder-before { color: var(--text-3); font-size: 12px; }
.form-hint { font-size: 12px; color: var(--text-3); margin-bottom: 6px; }
.reminders-disabled .ev-reminders-list,
.reminders-disabled #ev-reminder-add { opacity: 0.5; }
#ev-reminders-hint { color: var(--accent); }
.ev-color-hex {
flex: 1; height: 36px; padding: 0 10px;
background: var(--bg-hover); border: 1px solid var(--border);
border-radius: var(--radius-sm); color: var(--text-1);
font-family: 'Roboto Mono', monospace; font-size: 13px;
}
.ev-color-hex:focus { outline: none; border-color: var(--primary); }
.ev-color-preview {
width: 36px; height: 36px; border-radius: var(--radius-sm);
border: 1px solid var(--border); cursor: pointer;
flex-shrink: 0; transition: box-shadow var(--transition);
}
.ev-color-preview:hover { box-shadow: 0 0 0 2px var(--primary); }
/* ── Gradient Color Picker (Dark) ──────────────────────── */
.gcp {
position: fixed; z-index: 600;
width: 252px; padding: 16px;
background: var(--bg-surface); border: 1px solid var(--border);
border-radius: var(--radius); box-shadow: var(--shadow-lg);
}
.gcp-sv {
display: block; width: 100%; height: 160px;
border-radius: var(--radius-sm); cursor: crosshair;
}
.gcp-sv-cursor {
position: absolute; width: 14px; height: 14px;
border: 2px solid #fff; border-radius: 50%;
box-shadow: 0 0 0 1px rgba(0,0,0,.4), inset 0 0 0 1px rgba(0,0,0,.3);
transform: translate(-50%, -50%); pointer-events: none;
}
.gcp-hue-track {
position: relative; margin-top: 12px; height: 14px; cursor: pointer;
}
.gcp-hue {
display: block; width: 100%; height: 14px;
border-radius: 7px; cursor: pointer;
}
.gcp-hue-thumb {
position: absolute; top: 50%; width: 18px; height: 18px;
border: 2px solid #fff; border-radius: 50%;
box-shadow: 0 0 0 1px rgba(0,0,0,.3), 0 1px 4px rgba(0,0,0,.4);
transform: translate(-50%, -50%); pointer-events: none;
background: transparent;
}
.gcp-bottom {
display: flex; align-items: center; gap: 10px; margin-top: 12px;
}
.gcp-preview {
width: 36px; height: 36px; border-radius: var(--radius-sm);
border: 1px solid var(--border); flex-shrink: 0;
}
.gcp-hex {
flex: 1; height: 36px; padding: 0 10px;
background: var(--bg-hover); border: 1px solid var(--border);
border-radius: var(--radius-sm); color: var(--text-1);
font-family: 'Roboto Mono', monospace; font-size: 13px;
outline: none;
}
.gcp-hex:focus { border-color: var(--primary); }
.gcp-select {
display: block; width: 100%; margin-top: 12px;
padding: 8px 0; background: var(--primary); color: #fff;
border: none; border-radius: var(--radius-sm);
font-weight: 600; font-size: 13px; cursor: pointer;
transition: opacity var(--transition);
}
.gcp-select:hover { opacity: .85; }
/* ── Top Bar ────────────────────────────────────────────── */
.topbar {
position: fixed; top: 0; left: 0; right: 0; z-index: 100;
height: var(--topbar-h);
background: var(--bg-topbar);
border-bottom: 1px solid var(--border);
display: flex; align-items: center;
padding: 0 8px;
gap: 8px;
}
.topbar-left { display: flex; align-items: center; gap: 4px; width: var(--sidebar-w); flex-shrink: 0; }
.topbar-logo { display: flex; align-items: center; gap: 8px; user-select: none; }
.topbar-logo span:first-child { font-size: 22px; }
.logo-text { font-size: 20px; font-weight: 400; color: var(--text-1); }
.topbar-center { display: flex; align-items: center; gap: 4px; flex: 1; }
.view-title { font-size: 20px; font-weight: 400; color: var(--text-1); white-space: nowrap; padding-left: 8px; }
.topbar-right { display: flex; align-items: center; gap: 4px; }
.view-switcher { display: flex; background: var(--bg-surface); border-radius: 20px; overflow: hidden; border: 1px solid var(--border); }
.view-btn {
padding: 6px 14px; font-size: 13px; font-weight: 500;
color: var(--text-2);
transition: background var(--transition), color var(--transition);
border-radius: 20px;
}
.view-btn:hover { background: var(--hover-highlight); color: var(--text-1); }
.view-btn.active { background: var(--primary-dim); color: var(--primary); }
.user-menu-wrapper { position: relative; }
.user-avatar {
width: 34px; height: 34px; border-radius: 50%;
background: var(--primary);
display: flex; align-items: center; justify-content: center;
font-weight: 600; font-size: 14px; color: #fff;
cursor: pointer; user-select: none; flex-shrink: 0;
overflow: hidden; position: relative;
}
.user-dropdown {
position: absolute; top: 42px; right: 0;
background: var(--bg-surface); border: 1px solid var(--border);
border-radius: var(--radius); min-width: 180px;
box-shadow: 0 8px 24px rgba(0,0,0,.4); z-index: 200;
overflow: hidden;
}
.dropdown-user {
padding: 12px 16px; font-size: 13px; font-weight: 600;
color: var(--text-1); border-bottom: 1px solid var(--border);
}
.dropdown-item {
display: flex; align-items: center; gap: 10px;
width: 100%; padding: 10px 16px; border: none;
background: none; color: var(--text-2); font-size: 13px;
cursor: pointer; transition: background var(--transition);
}
.dropdown-item:hover { background: var(--hover-highlight); color: var(--text-1); }
.dropdown-item svg { flex-shrink: 0;
}
/* ── Layout ─────────────────────────────────────────────── */
#app {
display: flex; flex-direction: column; height: 100vh;
}
.content-wrapper {
margin-top: var(--topbar-h);
display: flex; flex: 1; overflow: hidden; height: calc(100vh - var(--topbar-h));
}
.sidebar {
width: var(--sidebar-w);
background: var(--bg-sidebar);
border-right: 1px solid var(--border);
flex-shrink: 0;
overflow-y: auto;
overflow-x: hidden;
transition: transform var(--transition);
scrollbar-width: none;
}
.sidebar::-webkit-scrollbar { display: none; }
.sidebar.collapsed { transform: translateX(calc(-1 * var(--sidebar-w))); margin-right: calc(-1 * var(--sidebar-w)); }
.sidebar-inner { padding-bottom: 8px; }
.sidebar-copyright {
display: block; width: 100%;
padding: 10px 16px 12px;
font-size: 11px; color: var(--text-3);
text-align: center; cursor: pointer;
background: none; border: none; border-top: 1px solid var(--border);
transition: color var(--transition);
white-space: nowrap;
position: sticky; bottom: 0;
background: var(--bg-sidebar);
}
.sidebar-copyright:hover { color: var(--text-1); }
.main-view { flex: 1; overflow: hidden; display: flex; flex-direction: column; }
#view-container { flex: 1; display: flex; flex-direction: column; min-height: 0; }
/* ── Mini Calendar ──────────────────────────────────────── */
.mini-cal { padding: 12px 16px; }
.mini-cal-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 8px; }
.mini-title { font-size: 13px; font-weight: 500; color: var(--text-1); }
.mini-btn { width: 28px; height: 28px; font-size: 18px; color: var(--text-2); }
.mini-btn:hover { color: var(--text-1); background: var(--hover-highlight); }
.mini-cal-grid { display: grid; grid-template-columns: repeat(7, 1fr); text-align: center; }
.mini-dow { font-size: 11px; color: var(--text-3); padding: 2px 0; font-weight: 500; }
.mini-cal-days { display: grid; grid-template-columns: repeat(7, 1fr); text-align: center; }
.mini-day {
font-size: 12px; padding: 3px 0; border-radius: 50%;
cursor: pointer; transition: background var(--transition);
color: var(--text-2); width: 28px; height: 28px;
display: flex; align-items: center; justify-content: center;
margin: 1px auto; position: relative;
}
.mini-day:hover { background: var(--day-hover-color); color: var(--text-1); }
.mini-day.other-month { color: var(--text-3); }
.mini-day.today {
background: var(--today-color);
color: #fff; font-weight: 700;
}
.mini-day.selected:not(.today) { background: color-mix(in srgb, var(--day-selected-base) 15%, transparent); color: var(--primary); font-weight: 600; }
.mini-day.has-events::after {
content: ''; position: absolute; bottom: 2px; left: 50%; transform: translateX(-50%);
width: 4px; height: 4px; border-radius: 50%; background: var(--primary);
}
.mini-day.today.has-events::after { background: #fff; }
/* ── Calendar List ──────────────────────────────────────── */
.cal-list { padding: 8px 0; }
.cal-list-header {
display: flex; align-items: center; justify-content: space-between;
padding: 8px 16px;
font-size: 12px; font-weight: 600; text-transform: uppercase;
letter-spacing: .5px; color: var(--text-2);
}
.add-cal-dropdown-wrap { position: relative; }
.add-cal-dropdown {
position: absolute; top: 100%; right: 0; z-index: 200;
min-width: 180px; padding: 4px 0;
background: var(--bg-surface); border: 1px solid var(--border);
border-radius: var(--radius); box-shadow: var(--shadow-lg);
}
.add-cal-dropdown button {
display: block; width: 100%; padding: 8px 14px;
text-align: left; font-size: 13px; color: var(--text-1);
background: none; border: none; cursor: pointer;
}
.add-cal-dropdown button:hover { background: var(--hover-highlight); }
.cal-item {
display: flex; align-items: center; gap: 10px;
padding: 6px 16px; cursor: pointer;
transition: background var(--transition);
border-radius: 0 20px 20px 0;
margin-right: 12px;
}
.cal-item:hover { background: var(--hover-highlight); }
.cal-item-dot {
width: 14px; height: 14px; border-radius: 3px; flex-shrink: 0; cursor: pointer;
}
.cal-item-dot:hover { outline: 2px solid var(--text-2); outline-offset: 1px; }
.cal-item input[type=checkbox] { accent-color: var(--primary); width: 14px; height: 14px; }
.cal-item-name { font-size: 13px; flex: 1; min-width: 0; color: var(--text-1); cursor: default; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cal-item-remove { flex-shrink: 0; display: none; }
.cal-rename-input {
font-size: 13px; flex: 1; color: var(--text-1);
background: var(--bg-app); border: 1px solid var(--primary);
border-radius: var(--radius-sm); padding: 2px 6px;
outline: none;
}
.cal-account-name { font-size: 11px; color: var(--text-3); padding: 4px 16px 2px; font-weight: 500; }
/* Fixed min-height so 28px mini-btns never change row height when they appear. */
.cal-item { position: relative; min-height: 40px; }
/* Sidebar action icons (bell / hide / delete / read-only flag) share two theme
colours: "inactive" (resting/off) and "active" (hovered/on/pressed). */
.cal-item-bell { display: none; flex-shrink: 0; color: var(--icon-active-color); } /* bell shown = reminders on = active */
.cal-item:hover .cal-item-remove,
.cal-item:hover .cal-item-bell { display: inline-flex; }
.cal-item-bell.off { display: inline-flex; opacity: .55; color: var(--icon-inactive-color); }
.cal-item:hover .cal-item-bell.off { opacity: 1; color: var(--icon-inactive-color); }
.cal-item-bell:hover, .cal-item-bell.off:hover { color: var(--icon-active-color); }
.cal-item-remove { color: var(--icon-inactive-color); }
.cal-item-remove:hover { color: var(--icon-active-color); }
/* ── Month View ─────────────────────────────────────────── */
.month-view { display: flex; flex-direction: column; flex: 1; min-height: 0; }
.month-header {
display: grid; grid-template-columns: 38px repeat(7, 1fr);
border-bottom: 1px solid var(--border); flex-shrink: 0;
}
.month-kw-header {
padding: 8px 0; text-align: center;
font-size: 13px; font-weight: 700; text-transform: uppercase;
letter-spacing: .3px; color: var(--text-3);
border-right: 1px solid var(--border-light);
}
.month-dow {
padding: 8px 0; text-align: center;
font-size: 11px; font-weight: 600; text-transform: uppercase;
letter-spacing: .5px; color: var(--text-2);
}
.month-kw-cell {
position: absolute; left: 0; top: 0; bottom: 0; width: 38px;
display: flex; align-items: flex-start; justify-content: center;
padding-top: 6px;
font-size: 13px; color: var(--text-3); font-weight: 700;
border-right: 1px solid var(--border-light);
cursor: default; user-select: none; z-index: 1;
background: var(--bg-app);
}
/* Full-height column divs — click target + border */
.month-col {
flex: 1; border-right: 1px solid var(--border);
cursor: pointer; transition: background var(--transition);
padding: 4px 4px 0; min-width: 0;
background: var(--day-bg);
}
.month-col:last-child { border-right: none; }
.month-col:hover { background: var(--day-hover-color); }
.month-col.today { background: color-mix(in srgb, var(--today-bg-base) 10%, transparent); }
.month-col.month-selected { background: color-mix(in srgb, var(--day-selected-base) 15%, transparent); }
.month-col.month-selected .cell-day { border: 2px solid var(--primary); color: var(--primary); font-weight: 700; }
.month-col.month-selected .cell-day.today { background: var(--today-color); color: #fff; border: none; }
.month-col.other-month .cell-day { color: var(--text-3); }
.cell-day {
font-size: 12px; font-weight: 500; color: var(--text-2);
width: 26px; height: 26px;
display: inline-flex; align-items: center; justify-content: center;
vertical-align: top;
border-radius: 50%; flex-shrink: 0;
}
.cell-day.today { background: var(--today-color); color: #fff; font-weight: 700; }
/* Month boundary marker: thicker line + month abbreviation on the 1st */
.month-col {
position: relative; /* anchor for divider pseudo-elements */
}
/* first-of-month keeps the normal block layout (number top-left); the month
label sits inline next to the number via .cell-day/.month-marker below. */
/* Dividers via pseudo-elements so they render above events (z-index 2) */
.month-col.month-divider-left::before {
content: '';
position: absolute;
left: 0; top: 0; bottom: 0;
width: 3px;
background: var(--month-divider-color, #7090c0);
z-index: 4;
pointer-events: none;
}
.month-col.month-divider-top::after {
content: '';
position: absolute;
top: 0; left: 0; right: 0;
height: 3px;
background: var(--month-divider-color, #7090c0);
z-index: 4;
pointer-events: none;
}
/* Bottom divider on the previous-month cells in the same row as the change.
Uses ::before because these cells never have month-divider-left. */
.month-col.month-divider-bottom::before {
content: '';
position: absolute;
bottom: 0; left: 0; right: 0;
height: 3px;
background: var(--month-divider-color, #7090c0);
z-index: 4;
pointer-events: none;
}
.month-row.month-divider-top {
position: relative;
}
.month-row.month-divider-top::before {
content: '';
position: absolute;
top: 0; left: 0; right: 0;
height: 3px;
background: var(--month-divider-color, #7090c0);
z-index: 4;
pointer-events: none;
}
.month-marker {
font-size: 11px;
font-weight: 600;
text-transform: none;
letter-spacing: .3px;
color: var(--month-label-color, #7090c0);
line-height: 26px; /* align with the day-number circle */
margin-left: 4px;
vertical-align: top;
position: relative;
z-index: 3; /* above events overlay (z-index 2) */
}
/* Make sure the day number stays visible above events */
.cell-day {
position: relative;
z-index: 3;
}
/* Month marker now sits inline next to the day number, so the header height is
uniform and the events overlay needs no extra offset for month-start weeks. */
.month-row.has-month-marker .month-events-overlay {
top: 30px;
}
/* Events overlay — pointer-events:none so clicks pass to columns */
.month-events-overlay {
position: absolute; top: 30px; left: 0; right: 0; bottom: 0;
pointer-events: none; overflow: hidden; z-index: 2;
}
.month-more {
position: absolute;
font-size: 11px; color: var(--text-2); padding: 0 4px;
cursor: pointer; font-weight: 500;
pointer-events: all;
white-space: nowrap; overflow: hidden;
}
.month-more:hover { color: var(--primary); }
/* Overflow popup ("+N weitere") */
.month-overflow-popup {
position: fixed; z-index: 800;
background: var(--bg-surface);
border: 1px solid var(--border);
border-radius: 12px;
box-shadow: var(--shadow-lg);
padding: 10px 0;
min-width: 220px; max-width: 300px;
overflow: hidden;
user-select: none;
}
.mop-header {
font-size: 12px; font-weight: 600;
color: var(--text-2);
padding: 0 12px 8px;
border-bottom: 1px solid var(--border);
margin-bottom: 4px;
}
.mop-row {
display: flex; align-items: center; gap: 7px;
padding: 4px 12px; cursor: pointer;
border-radius: 6px; margin: 0 4px;
}
.mop-row:hover { background: var(--hover-highlight); }
.mop-dot {
width: 8px; height: 8px; border-radius: 50%;
flex-shrink: 0;
}
.mop-time {
font-size: 11px; color: var(--text-2);
min-width: 42px; flex-shrink: 0;
}
.mop-title {
font-size: 12px; font-weight: 500; color: var(--text-1);
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* All-day event bars in overflow popup — pointed ends via clip-path */
.mop-bar {
display: block;
margin: 2px 8px; padding: 3px 8px;
border-radius: 4px;
font-size: 11px; font-weight: 500; color: #fff;
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
cursor: pointer;
}
.mop-bar:hover { filter: brightness(1.15); }
.mop-bar.continues-left {
clip-path: polygon(10px 0, 100% 0, 100% 100%, 10px 100%, 0 50%);
border-radius: 0; padding-left: 16px;
}
.mop-bar.continues-right {
clip-path: polygon(0 0, calc(100% - 10px) 0, 100% 50%, calc(100% - 10px) 100%, 0 100%);
border-radius: 0; padding-right: 16px;
}
.mop-bar.continues-left.continues-right {
clip-path: polygon(10px 0, calc(100% - 10px) 0, 100% 50%, calc(100% - 10px) 100%, 10px 100%, 0 50%);
}
/* ── Week / Day Views ───────────────────────────────────── */
.week-view, .day-view { display: flex; flex-direction: column; flex: 1; min-height: 0; overflow-y: scroll; }
.week-head-sticky {
flex-shrink: 0; position: sticky; top: 0; z-index: 10;
background: var(--bg-app);
}
.week-header-row {
display: flex; border-bottom: 1px solid var(--border);
}
/* KW badge in week view header gutter */
.week-kw-badge {
font-size: 14px; font-weight: 700; color: var(--text-3);
display: flex; align-items: flex-end; justify-content: center;
padding-bottom: 6px;
text-transform: uppercase; letter-spacing: .3px;
user-select: none;
}
.week-time-gutter {
width: 56px; flex-shrink: 0;
display: flex; flex-direction: column; align-items: stretch;
}
.week-day-header {
flex: 1; padding: 8px 4px; text-align: center;
border-left: 1px solid var(--border); cursor: pointer;
transition: background var(--transition);
}
.week-day-header:hover { background: var(--day-hover-color); }
.week-day-header .day-name {
font-size: 11px; font-weight: 600; text-transform: uppercase;
letter-spacing: .5px; color: var(--text-2);
}
.week-day-header .day-num {
font-size: 22px; font-weight: 400; color: var(--text-2);
width: 44px; height: 44px;
display: flex; align-items: center; justify-content: center;
border-radius: 50%; margin: 2px auto;
}
.week-day-header.today .day-num {
background: var(--today-color);
color: #fff; font-weight: 700;
}
.week-day-header.today .day-name { color: var(--today-color); }
/* All-day row */
.week-allday-row { display: flex; border-bottom: 1px solid var(--border); flex-shrink: 0; }
.allday-gutter { width: 56px; flex-shrink: 0; display: flex; align-items: flex-start; justify-content: flex-end; padding: 6px 6px 0; font-size: 10px; color: var(--text-3); }
.allday-cols-wrap { flex: 1; position: relative; display: flex; }
.allday-col-bg { flex: 1; border-left: 1px solid var(--border); }
.allday-spans-layer { position: absolute; inset: 0; pointer-events: none; }
.allday-span {
position: absolute;
height: 18px; line-height: 18px;
font-size: 11px; font-weight: 500;
padding: 0 6px; border-radius: 3px;
cursor: pointer; pointer-events: all;
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.allday-span:hover { filter: brightness(1.12); }
.allday-span.past { opacity: .45; }
.allday-span.continues-left { border-top-left-radius: 0; border-bottom-left-radius: 0; padding-left: 3px; }
.allday-span.continues-right { border-top-right-radius: 0; border-bottom-right-radius: 0; padding-right: 3px; }
.allday-span.multiday-timed { opacity: .88; border-left: 3px solid rgba(255,255,255,.4); }
.col-span-tint { position: absolute; inset: 0; pointer-events: none; z-index: 0; }
/* Time grid */
.week-time-area { display: flex; flex-shrink: 0; }
.week-time-col { width: 56px; flex-shrink: 0; position: relative; }
.time-label {
height: var(--hour-h, 60px); display: flex; align-items: flex-start; justify-content: flex-end;
padding-right: 8px; padding-top: 6px;
font-size: 10px; color: var(--text-3);
}
.week-days-col { flex: 1; display: flex; position: relative; }
.week-day-col {
flex: 1; border-left: 1px solid var(--border);
position: relative;
min-height: calc(var(--hour-h, 60px) * 24);
}
.hour-line {
position: absolute; left: 0; right: 0;
border-top: 1px solid var(--border-light);
height: var(--hour-h, 60px);
}
.hour-line:first-child { border-top: none; }
.half-line {
position: absolute; left: 0; right: 0;
border-top: 1px dashed var(--border-light);
top: calc(var(--hour-h, 60px) / 2);
}
/* Current time indicator */
.now-line {
position: absolute; left: 0; right: 0;
border-top: 2px solid var(--accent);
z-index: 5; pointer-events: none;
}
.now-dot {
position: absolute; left: -5px; top: -5px;
width: 10px; height: 10px; border-radius: 50%;
background: var(--accent);
}
/* Timed events */
.timed-event {
position: absolute; border-radius: 4px;
padding: 2px 4px; cursor: pointer; overflow: hidden;
font-size: 11px; font-weight: 500;
border-left: 3px solid rgba(0,0,0,.25);
transition: filter var(--transition);
z-index: 3;
}
.timed-event:hover { filter: brightness(1.12); z-index: 4; }
.timed-event.past { opacity: .45; }
.timed-event .ev-time { font-size: 10px; opacity: .85; }
.timed-event .ev-title { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.timed-event .ev-loc { font-size: 10px; opacity: .75; white-space: nowrap; overflow: hidden; }
/* Short events: time and title on one line so the title stays visible. */
.timed-event.short { display: flex; flex-direction: row; align-items: baseline; gap: 4px; }
.timed-event.short .ev-time { flex-shrink: 0; }
.timed-event.short .ev-title { flex: 1; min-width: 0; }
/* Day view specifics */
.day-view .week-day-col { flex: 1; }
/* ── Quarter View ───────────────────────────────────────── */
.quarter-view {
display: flex;
gap: 16px;
padding: 16px;
flex: 1;
min-height: 0;
box-sizing: border-box;
overflow-y: auto;
}
.qtr-month {
flex: 1;
display: flex;
flex-direction: column;
min-width: 0;
background: var(--bg-2);
border: 1px solid var(--border);
border-radius: 8px;
overflow: hidden;
}
.qtr-month-name {
font-size: 13px;
font-weight: 600;
color: var(--text-1);
padding: 10px 12px 8px;
border-bottom: 1px solid var(--border);
letter-spacing: .3px;
}
.qtr-month-grid { padding: 6px 8px 8px; }
.qtr-header {
display: grid;
grid-template-columns: repeat(7, 1fr);
margin-bottom: 2px;
}
.qtr-dow {
font-size: 10px;
font-weight: 600;
text-transform: uppercase;
color: var(--text-3);
text-align: center;
padding: 3px 0;
}
.qtr-cells {
display: grid;
grid-template-columns: repeat(7, 1fr);
grid-template-rows: repeat(6, auto);
}
.qtr-cell {
padding: 3px 2px;
text-align: center;
cursor: pointer;
border-radius: 4px;
min-height: 36px;
}
.qtr-cell:hover { background: var(--day-hover-color); }
.qtr-cell.today .qtr-day-num {
background: var(--today-color, var(--primary));
color: #fff;
border-radius: 50%;
}
.qtr-day-num {
font-size: 12px;
font-weight: 500;
color: var(--text-2);
width: 22px;
height: 22px;
line-height: 22px;
margin: 0 auto 2px;
}
.qtr-cell.other-month .qtr-day-num { color: var(--text-3); opacity: .45; }
.qtr-cell.today .qtr-day-num { color: #fff; }
.qtr-dots {
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: 2px;
min-height: 6px;
}
.qtr-dot {
display: inline-block;
width: 6px;
height: 6px;
border-radius: 50%;
flex-shrink: 0;
cursor: pointer;
}
.qtr-dot.past { opacity: .45; }
.qtr-dot-more {
font-size: 9px;
color: var(--text-3);
line-height: 6px;
}
/* ── Agenda View ────────────────────────────────────────── */
.agenda-view { padding: 16px; flex: 1; overflow-y: auto; min-height: 0; }
.agenda-day { margin-bottom: 16px; }
.agenda-date {
font-size: 13px; font-weight: 600; color: var(--text-2);
padding: 8px 0 4px;
border-bottom: 1px solid var(--border);
margin-bottom: 8px;
display: flex; align-items: center; gap: 10px;
}
.agenda-date-num {
font-size: 22px; font-weight: 300; color: var(--text-1);
width: 44px; text-align: center;
}
.agenda-date-label { display: flex; flex-direction: column; }
.agenda-date-label .wd { font-size: 11px; text-transform: uppercase; letter-spacing: .5px; color: var(--text-2); }
.agenda-date-label .mo { font-size: 13px; color: var(--text-2); }
.agenda-date.today .agenda-date-num { color: var(--today-color); font-weight: 600; }
.agenda-event {
display: flex; align-items: flex-start; gap: 12px;
padding: 8px 12px; border-radius: var(--radius-sm);
cursor: pointer; transition: background var(--transition);
margin-left: 54px; margin-bottom: 4px;
}
.agenda-event:hover { background: var(--day-hover-color); }
.agenda-event.past { opacity: .45; }
.agenda-ev-color { width: 10px; height: 10px; border-radius: 50%; margin-top: 4px; flex-shrink: 0; }
.agenda-ev-info { flex: 1; }
.agenda-ev-title { font-size: 14px; color: var(--text-1); }
.agenda-ev-meta { font-size: 12px; color: var(--text-2); }
.agenda-empty { text-align: center; padding: 48px; color: var(--text-3); font-size: 15px; }
/* ── Modals ─────────────────────────────────────────────── */
.modal-overlay {
position: fixed; inset: 0; z-index: 500;
background: rgba(0,0,0,.6);
display: flex; align-items: center; justify-content: center;
padding: 16px;
}
.modal-card {
background: var(--bg-surface);
border: 1px solid var(--border);
border-radius: 20px;
width: 100%;
max-height: 90vh;
overflow: hidden;
display: flex; flex-direction: column;
box-shadow: var(--shadow-lg);
}
.modal-header {
display: flex; align-items: center;
padding: 16px 20px; border-bottom: 1px solid var(--border);
gap: 8px;
}
.modal-header h3 { font-size: 18px; font-weight: 500; flex: 1; }
.modal-close { font-size: 24px; }
.modal-body { padding: 20px; overflow-y: auto; flex: 1; scrollbar-width: none; }
.modal-body::-webkit-scrollbar { display: none; }
.modal-body p { margin: 0 0 14px; font-size: 14px; color: var(--text-1); }
.modal-body p:last-child { margin-bottom: 0; }
.modal-body a { color: var(--primary); text-decoration: none; }
.modal-body a:hover { text-decoration: underline; }
.modal-footer {
display: flex; align-items: center; gap: 8px;
padding: 12px 20px; border-top: 1px solid var(--border);
}
/* ── Recurrence UI ─────────────────────────────────────── */
.rec-weekdays { display: flex; gap: 4px; margin-top: 8px; }
.rec-day-btn {
width: 36px; height: 36px; border-radius: 50%;
border: 1px solid var(--border); background: var(--bg-card);
color: var(--text-2); cursor: pointer; font-size: 12px;
display: flex; align-items: center; justify-content: center;
transition: background var(--transition), color var(--transition);
}
.rec-day-btn:hover { background: var(--hover-highlight); }
.rec-day-btn.active { background: var(--primary); color: #fff; border-color: var(--primary); }
/* ── Day Context Menu ──────────────────────────────────── */
.cal-context-menu {
position: fixed; z-index: 1000;
background: var(--bg-surface); border: 1px solid var(--border);
border-radius: var(--radius-sm); box-shadow: 0 4px 16px rgba(0,0,0,.5);
min-width: 180px; padding: 4px 0;
}
.ctx-item {
padding: 8px 16px; font-size: 13px; color: var(--text-1); cursor: pointer;
}
.ctx-item:hover { background: var(--hover-highlight); }
/* ── Event Popup ──────────────────────────────────────────
Layout: Color-Dot + Title links, kleine Icon-Toolbar rechts oben.
Icons sind im Ruhezustand transparent (nur das SVG selbst sichtbar),
bekommen erst beim Hover einen runden farbigen Hintergrund. Wirkt
modern und lässt dem Titel die meiste Breite. */
.event-popup {
position: fixed; z-index: 600;
width: 320px;
background: var(--bg-surface); /* fallback for no color-mix */
background: color-mix(in srgb, var(--bg-surface) 86%, transparent);
-webkit-backdrop-filter: blur(22px) saturate(1.6);
backdrop-filter: blur(22px) saturate(1.6);
border: 1px solid color-mix(in srgb, var(--border) 80%, transparent);
border-radius: 16px;
box-shadow:
inset 0 1px 0 rgba(255,255,255,.05),
0 12px 40px rgba(0,0,0,.55),
0 2px 8px rgba(0,0,0,.4);
overflow: hidden;
transform-origin: top left;
animation: popupIn .18s cubic-bezier(.2,.8,.2,1);
}
@keyframes popupIn {
from { opacity: 0; transform: translateY(6px) scale(.97); }
to { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
.event-popup { animation: none; }
}
.popup-header {
position: relative;
display: flex; align-items: flex-start; gap: 11px;
padding: 14px 10px 13px 18px;
background: linear-gradient(180deg,
color-mix(in srgb, var(--ev-color, var(--primary)) 13%, transparent), transparent);
}
.ep-dragging { user-select: none; }
/* Slim accent strip in the event's colour. */
.popup-header::before {
content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 4px;
background: var(--ev-color, var(--primary));
}
.popup-color-dot {
width: 10px; height: 10px; border-radius: 50%;
background: var(--ev-color, var(--primary));
flex-shrink: 0; margin-top: 6px;
box-shadow: 0 0 0 3px color-mix(in srgb, var(--ev-color, var(--primary)) 22%, transparent);
}
.popup-header h4 {
flex: 1;
font-size: 15px; font-weight: 600;
line-height: 1.35; letter-spacing: -.01em;
color: var(--text-1);
word-break: break-word;
padding-top: 1px;
}
.popup-toolbar {
display: flex;
gap: 2px;
flex-shrink: 0;
margin-left: 4px;
}
.popup-icon-btn {
width: 32px; height: 32px;
border-radius: 10px;
display: inline-flex; align-items: center; justify-content: center;
background: transparent;
border: none;
cursor: pointer;
color: var(--text-3);
-webkit-tap-highlight-color: transparent;
transition:
background var(--transition),
color var(--transition),
transform .12s ease;
}
.popup-icon-btn svg { width: 16px; height: 16px; fill: currentColor; flex-shrink: 0; }
.popup-icon-btn:hover {
background: rgba(66,133,244,.16);
background: color-mix(in srgb, var(--primary) 16%, transparent);
color: var(--primary);
}
.popup-icon-btn-danger:hover {
background: rgba(234,67,53,.16);
background: color-mix(in srgb, var(--accent) 16%, transparent);
color: var(--accent);
}
.popup-icon-btn-close:hover {
background: var(--bg-hover);
color: var(--text-1);
}
.popup-icon-btn:active { transform: scale(.88); }
.popup-body { padding: 12px 16px 14px; display: flex; flex-direction: column; gap: 9px; -webkit-user-select: text; user-select: text; }
.popup-row { display: flex; align-items: flex-start; gap: 10px; font-size: 13px; line-height: 1.45; color: var(--text-2); }
.popup-row-icon { width: 16px; height: 16px; flex-shrink: 0; margin-top: 1px; fill: var(--text-3); }
#popup-time { color: var(--text-1); font-weight: 500; }
.popup-row-desc { color: var(--text-1); }
.popup-row-desc span { white-space: pre-wrap; }
#popup-description { overflow-wrap: anywhere; }
#popup-description a { color: var(--primary); text-decoration: underline; }
#popup-description p { margin: 0 0 6px; }
#popup-description ul, #popup-description ol { margin: 4px 0; padding-left: 20px; }
#popup-creator { font-style: italic; }
.popup-copy-menu {
border-top: 1px solid color-mix(in srgb, var(--border) 70%, transparent);
padding: 6px;
}
.popup-copy-label {
font-size: 11px; font-weight: 600; text-transform: uppercase;
letter-spacing: .5px; color: var(--text-3);
padding: 4px 10px 6px;
}
.popup-copy-item {
display: flex; align-items: center; gap: 9px;
padding: 8px 10px; cursor: pointer; font-size: 13px; color: var(--text-1);
border-radius: 10px;
transition: background var(--transition);
}
.popup-copy-item:hover { background: var(--hover-highlight); }
.popup-copy-dot { width: 10px; height: 10px; border-radius: 50%; flex-shrink: 0; }
.popup-copy-edit-toggle {
display: flex; align-items: center; gap: 8px;
padding: 6px 10px 8px;
font-size: 12px; color: var(--text-2);
cursor: pointer;
border-bottom: 1px solid color-mix(in srgb, var(--border) 70%, transparent);
margin-bottom: 4px;
}
.popup-copy-edit-toggle input[type="checkbox"] { margin: 0; cursor: pointer; }
/* ── Settings Page ──────────────────────────────────────── */
#modal-settings.modal-overlay {
align-items: stretch; justify-content: stretch; padding: 0; background: var(--bg-app);
/* Full-screen opaque "page". Sit BELOW real modals (z-index 500) so dialogs
opened from inside settings — share, add-account, color picker — appear on
top instead of behind this page (that's why the Share button "did nothing"). */
z-index: 400;
}
.settings-page-card {
width: 100%; height: 100%;
display: flex; flex-direction: column;
background: var(--bg-app); overflow: hidden;
}
.settings-page-header {
display: flex; align-items: center; gap: 8px;
padding: 14px 20px; border-bottom: 1px solid var(--border);
flex-shrink: 0;
background: var(--bg-topbar);
}
.settings-page-header h3 { font-size: 16px; font-weight: 600; color: var(--text-1); margin: 0; }
.settings-page-body {
display: flex; flex: 1; overflow: hidden;
}
.settings-nav {
width: 200px; flex-shrink: 0;
border-right: 1px solid var(--border);
padding: 12px 8px;
display: flex; flex-direction: column; gap: 2px;
background: var(--bg-sidebar);
}
.settings-nav-btn {
display: block; width: 100%; text-align: left;
padding: 9px 14px; border-radius: var(--radius-sm);
font-size: 14px; color: var(--text-2);
background: none; border: none; cursor: pointer;
transition: background .15s, color .15s;
}
.settings-nav-btn:hover { background: var(--hover-highlight); color: var(--text-1); }
.settings-nav-btn.active { background: var(--primary-dim); color: var(--primary); font-weight: 600; }
.settings-panels {
flex: 1; overflow-y: auto; padding: 24px 28px;
}
.settings-panel { display: none; }
/* Constrain content to a comfortable reading column so fields don't stretch
edge-to-edge on wide screens. */
.settings-panel.active { display: block; max-width: 680px; }
/* …except the Kalender panel, whose wide multi-column table needs the full
width (otherwise it's squeezed into a horizontal scroll). */
#settings-panel-accounts { max-width: none; }
/* Panel typography */
.panel-title {
font-size: 14px; font-weight: 600; color: var(--text-1); margin: 0 0 4px;
}
.panel-desc {
font-size: 12px; color: var(--text-3); margin: 0 0 12px;
}
/* Contrast / option selectors — segmented pill */
.contrast-selector {
display: inline-flex;
border: 1px solid var(--border);
border-radius: 20px;
overflow: hidden;
background: var(--bg-surface);
}
.contrast-btn {
display: flex; flex-direction: column; align-items: center; gap: 4px;
padding: 8px 14px; min-width: 64px;
background: transparent; border: none;
border-right: 1px solid var(--border);
cursor: pointer; color: var(--text-2);
transition: background var(--transition), color var(--transition);
}
.contrast-btn:last-child { border-right: none; }
.contrast-btn:hover { background: var(--hover-highlight); color: var(--text-1); }
.contrast-btn.active { background: var(--primary); color: #fff; }
.contrast-btn span { font-size: 18px; font-weight: 700; line-height: 1; }
.contrast-btn.active span { color: #fff !important; }
.contrast-lbl { font-size: 11px; white-space: nowrap; }
.contrast-btn.active .contrast-lbl { color: #fff; }
.line-preview {
display: block; width: 36px; height: 0;
border-top: 2px solid; border-radius: 1px;
margin: 4px 0;
}
.hour-preview {
font-size: 14px; line-height: 1; color: var(--text-2);
}
.contrast-btn.active .hour-preview { color: #fff; }
/* ── Settings sync table (Sync-Icon | Name | Wert) ─────────── */
.sync-global-row {
display: flex; align-items: center; justify-content: space-between; gap: 16px;
padding: 12px 14px; margin-bottom: 12px;
background: var(--bg-surface); border: 1px solid var(--border); border-radius: 12px;
}
.sync-global-text { display: flex; flex-direction: column; gap: 2px; }
.sync-global-title { font-size: 14px; font-weight: 600; color: var(--text-1); }
.sync-global-row .panel-desc { margin: 0; }
.settings-table { display: flex; flex-direction: column; }
.theme-io-row { display: flex; align-items: center; gap: 8px; margin-top: 16px; flex-wrap: wrap; }
.theme-io-help {
display: inline-flex; align-items: center; justify-content: center;
width: 20px; height: 20px; border-radius: 50%;
background: var(--bg-hover); color: var(--text-2);
font-size: 12px; font-weight: 700; text-decoration: none;
}
.theme-io-help:hover { background: var(--hover-highlight); color: var(--text-1); }
/* Custom instance logo (replaces the glyph+text). Hard-capped so it can only
scale DOWN and never pushes the topbar/auth layout. */
.topbar-logo-img { max-height: 40px; max-width: 150px; width: auto; height: auto; object-fit: contain; display: block; }
.auth-logo-img { max-height: 56px; max-width: 220px; width: auto; height: auto; object-fit: contain; display: block; }
/* Admin panel: default-theme editor + branding */
.admin-theme-grid { display: flex; flex-direction: column; gap: 8px; margin-top: 8px; }
.admin-theme-row { display: grid; grid-template-columns: 1fr auto; align-items: center; gap: 12px; }
.admin-theme-name { font-size: 13px; color: var(--text-2); }
.admin-theme-actions { display: flex; gap: 8px; margin-top: 14px; }
.admin-brand-row { display: flex; align-items: center; gap: 12px; margin-top: 12px; flex-wrap: wrap; }
.admin-brand-label { width: 70px; font-size: 13px; color: var(--text-2); flex-shrink: 0; }
.admin-brand-preview {
width: 48px; height: 48px; flex-shrink: 0;
display: flex; align-items: center; justify-content: center;
background: var(--bg-hover); border: 1px solid var(--border-light);
border-radius: var(--radius-sm); overflow: hidden;
}
/* Logo preview mirrors its real topbar footprint (max 150×40). */
.admin-brand-preview-logo { width: 150px; height: 40px; }
.admin-brand-preview img { max-width: 100%; max-height: 100%; object-fit: contain; }
.admin-brand-controls { display: flex; flex-direction: column; gap: 4px; }
.admin-brand-btns { display: flex; gap: 8px; }
.admin-brand-dims { font-size: 11px; color: var(--text-3); }
.settings-table-section {
font-size: 12px; font-weight: 600; letter-spacing: .04em; text-transform: uppercase;
color: var(--text-3); margin: 18px 0 6px; padding: 0 2px;
}
.settings-table-section:first-child { margin-top: 0; }
.settings-row {
display: grid; grid-template-columns: 40px 1fr minmax(140px, auto);
align-items: center; gap: 12px;
padding: 10px 4px; border-bottom: 1px solid var(--border-light);
}
.settings-row:last-child { border-bottom: none; }
.settings-row-name { font-size: 14px; color: var(--text-1); }
.settings-row-value { display: flex; align-items: center; justify-content: flex-end; gap: 8px; }
.settings-row-value select {
background: var(--bg-app);
border: 1px solid var(--border);
border-radius: 8px;
padding: 8px 12px;
color: var(--text-1);
outline: none;
cursor: pointer;
color-scheme: dark;
min-width: 130px; max-width: 100%;
transition: border-color var(--transition);
}
.settings-row-value select:hover:not(:focus) { border-color: var(--text-3); }
.settings-row-value select:focus { border-color: var(--primary); }
/* Sync toggle switch — used per row and (larger) globally */
.sync-toggle {
position: relative; flex: 0 0 auto;
width: 34px; height: 20px; padding: 0;
border: none; border-radius: 999px; cursor: pointer;
background: var(--bg-active); transition: background var(--transition);
}
.sync-toggle::after {
content: ''; position: absolute; top: 2px; left: 2px;
width: 16px; height: 16px; border-radius: 50%;
background: #fff; transition: transform var(--transition);
}
.sync-toggle.on { background: var(--primary); }
.sync-toggle.on::after { transform: translateX(14px); }
.sync-toggle-lg { width: 44px; height: 26px; }
.sync-toggle-lg::after { width: 22px; height: 22px; }
.sync-toggle-lg.on::after { transform: translateX(18px); }
.settings-row .sync-toggle { justify-self: center; }
/* Per-row sync toggle icon: ON = primary + pill, OFF = muted + slashed icon */
.sync-icon {
display: inline-flex; align-items: center; justify-content: center;
width: 32px; height: 28px; padding: 0;
border: none; border-radius: 8px; cursor: pointer;
background: transparent; color: var(--text-3);
transition: color var(--transition), background var(--transition);
justify-self: center;
}
.sync-icon:hover { background: var(--hover-highlight); color: var(--text-2); }
.sync-icon.on { color: var(--primary); background: var(--primary-dim); }
.sync-icon .si-on, .sync-icon .si-off { align-items: center; }
.sync-icon .si-on { display: none; }
.sync-icon .si-off { display: inline-flex; }
.sync-icon.on .si-off { display: none; }
.sync-icon.on .si-on { display: inline-flex; }
/* Per-row colour control: swatch + hex + reset, right-aligned */
.settings-color-ctl { display: flex; align-items: center; gap: 12px; }
.settings-color-ctl .ev-color-hex { width: 92px; }
.settings-color-ctl .ev-color-preview { margin-left: 2px; }
.settings-color-ctl .ev-color-reset {
display: inline-flex; align-items: center; justify-content: center;
width: 28px; height: 28px; padding: 0; color: var(--text-3);
}
/* Inline share-icon picker inside a value cell — one even row */
.settings-icon-ctl { display: flex; flex-wrap: nowrap; gap: 6px; justify-content: flex-end; }
@media (max-width: 640px) {
.settings-row { grid-template-columns: 34px 1fr; grid-auto-rows: auto; }
.settings-row-value { grid-column: 1 / -1; justify-content: flex-start; padding-left: 46px; }
}
/* ── Settings (legacy) ──────────────────────────────────── */
.settings-section { margin-bottom: 28px; }
.settings-section h4 { font-size: 14px; font-weight: 600; color: var(--text-1); margin-bottom: 16px; display: flex; align-items: center; gap: 8px; }
.badge-admin {
font-size: 10px; padding: 2px 6px;
background: rgba(66,133,244,.2); color: var(--primary);
border-radius: 10px; font-weight: 600;
}
.users-list-item {
display: flex; align-items: center; justify-content: space-between;
padding: 8px 0; border-bottom: 1px solid var(--border-light);
}
.users-list-item .uname { font-weight: 500; }
.users-list-item .uemail { font-size: 12px; color: var(--text-2); }
.users-list-item .ubadge { font-size: 11px; color: var(--text-3); background: var(--bg-hover); padding: 2px 6px; border-radius: 10px; }
/* ── Profile ───────────────────────────────────────────── */
.profile-avatar-section {
display: flex; align-items: center; gap: 20px;
margin-bottom: 28px; padding-bottom: 20px;
border-bottom: 1px solid var(--border);
}
.profile-avatar {
width: 80px; height: 80px; border-radius: 50%;
background: var(--primary); display: flex;
align-items: center; justify-content: center;
font-size: 32px; font-weight: 700; color: #fff;
flex-shrink: 0; overflow: hidden; position: relative;
}
.profile-avatar img {
width: 100%; height: 100%; object-fit: cover;
position: absolute; inset: 0;
}
.profile-avatar-actions { display: flex; flex-direction: column; gap: 6px; }
.profile-username { font-size: 18px; font-weight: 600; color: var(--text-1); }
.btn-sm { padding: 6px 14px; font-size: 12px; }
.input-disabled { opacity: .5; cursor: not-allowed; }
.text-muted { font-size: 13px; color: var(--text-2); margin-bottom: 12px; }
.text-success { font-size: 13px; color: #34a853; margin-bottom: 12px; font-weight: 500; }
.totp-qr-wrapper {
display: flex; justify-content: center;
margin: 16px 0; padding: 16px;
background: #fff; border-radius: var(--radius);
width: fit-content;
}
.totp-qr-wrapper img { width: 200px; height: 200px; }
.totp-secret-row {
display: flex; align-items: center; gap: 8px;
background: var(--bg-app); border: 1px solid var(--border);
border-radius: var(--radius-sm); padding: 8px 12px;
}
.totp-secret-row code {
font-family: monospace; font-size: 14px; color: var(--text-1);
word-break: break-all; flex: 1;
}
.profile-cal-item {
display: flex; align-items: center; gap: 10px;
padding: 8px 0; border-bottom: 1px solid var(--border-light);
}
.profile-cal-dot {
width: 12px; height: 12px; border-radius: 3px; flex-shrink: 0;
}
.profile-cal-name { font-size: 13px; color: var(--text-1); }
.profile-cal-account { font-size: 11px; color: var(--text-3); }
/* ── Avatar Crop ───────────────────────────────────────── */
.crop-container { max-height: 400px; overflow: hidden; background: #000; }
.crop-container img { display: block; max-width: 100%; }
/* ── Toast ──────────────────────────────────────────────── */
.toast {
position: fixed; bottom: 24px; left: 50%; transform: translateX(-50%);
background: var(--bg-surface); border: 1px solid var(--border);
border-radius: 24px; padding: 10px 24px;
font-size: 14px; color: var(--text-1);
box-shadow: var(--shadow-lg); z-index: 9999;
transition: opacity .3s;
}
.toast.error { border-color: rgba(234,67,53,.5); background: rgba(234,67,53,.15); color: #f28b82; }
/* ── Loading Spinner ────────────────────────────────────── */
.spinner {
width: 32px; height: 32px; border: 3px solid var(--border);
border-top-color: var(--primary); border-radius: 50%;
animation: spin .7s linear infinite; margin: 32px auto;
}
@keyframes spin { to { transform: rotate(360deg); } }
.loading-view { display: flex; justify-content: center; align-items: center; height: 200px; }
/* ── Accounts Panel ──────────────────────────────────────── */
.accounts-section { margin-bottom: 24px; }
.accounts-section-heading {
font-size: 11px; font-weight: 600; text-transform: uppercase;
letter-spacing: .5px; color: var(--text-3);
padding: 0 0 8px;
border-bottom: 1px solid var(--border-light);
margin-bottom: 10px;
}
.accounts-section-empty {
font-size: 13px; color: var(--text-3); padding: 4px 0; display: block;
}
.accounts-row {
display: flex; align-items: center;
justify-content: space-between;
padding: 8px 0;
border-bottom: 1px solid var(--border-light);
}
.accounts-row:last-child { border-bottom: none; }
.accounts-row-info { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.accounts-row-name { font-size: 13px; color: var(--text-1); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.accounts-row-sub { font-size: 11px; color: var(--text-3); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.accounts-row-actions { display: flex; gap: 6px; flex-shrink: 0; margin-left: 8px; }
.accounts-local-dot {
width: 10px; height: 10px; border-radius: 50%; flex-shrink: 0; display: inline-block;
}
/* ── Calendar Management Table ──────────────────────────── */
.accounts-add-row { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 4px; }
.cal-manage-table { width: 100%; border-collapse: collapse; font-size: 13px; }
.cal-manage-table th {
text-align: left; font-size: 11px; font-weight: 600; text-transform: uppercase;
letter-spacing: .4px; color: var(--text-3); padding: 0 8px 8px 0;
border-bottom: 1px solid var(--border-light);
}
.cal-manage-table td { padding: 6px 8px 6px 0; border-bottom: 1px solid var(--border-light); vertical-align: middle; }
/* Fixed layout + narrow drags must clip, not overlap the next column (Excel-like). */
.cal-manage-table td { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Full-width detail/section rows (account headers, CalDAV boxes, empty state) wrap normally. */
.cal-manage-table td[colspan] { overflow: visible; white-space: normal; }
.cal-manage-table tbody tr:last-child td { border-bottom: none; }
/* Drag-resizable columns: a grab handle on each header's right edge. */
.cal-manage-table th { position: relative; }
.cal-manage-table th .col-resizer {
position: absolute; top: 0; right: 0; width: 8px; height: 100%;
cursor: col-resize; user-select: none; touch-action: none;
}
.cal-manage-table th .col-resizer:hover { background: var(--border); }
.ct-acc-row td { padding-top: 14px; background: none; }
.ct-acc-row td:first-child { font-size: 13px; }
.ct-cal-row .ct-indent { padding-left: 16px; }
.ct-src { font-size: 11px; color: var(--text-3); white-space: nowrap; }
.ct-badge {
display: inline-block; font-size: 10px; font-weight: 600; padding: 1px 5px;
border-radius: 3px; background: var(--surface-2); color: var(--text-3);
margin-left: 6px; vertical-align: middle;
}
.ct-badge-g { background: #e8f0fe; color: #1a73e8; }
.ct-badge-ha { background: #e8f5e9; color: #2e7d32; }
.ct-dot { width: 9px; height: 9px; border-radius: 50%; display: inline-block; margin-right: 5px; vertical-align: middle; flex-shrink: 0; }
.ct-empty { color: var(--text-3); font-size: 13px; padding: 16px 0; text-align: center; }
.ct-toggle { cursor: pointer; }
.ct-dav-toggle.on { color: var(--primary); }
.ct-dav-row td { padding-top: 4px; padding-bottom: 12px; }
.ct-dav-box { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.ct-dav-label { font-size: 12px; color: var(--text-3); }
.ct-dav-url {
flex: 1; min-width: 220px; font-size: 12px; padding: 5px 8px;
border: 1px solid var(--border); border-radius: 6px;
background: var(--surface-2); color: var(--text-1);
}
.ct-dav-hint { font-size: 11px; color: var(--text-3); margin-top: 6px; max-width: 640px; }
/* Row (not the column inherited from .form-group) so the "Erstellen" button
sits inline to the right of the name field instead of centred below it. */
.app-pw-create { display: flex; flex-direction: row; gap: 8px; align-items: center; }
.app-pw-create input { flex: 1; }
/* Consistent placement for a section's action button: right-aligned, matching
the sticky header save and the app-password create row. */
.settings-actions { display: flex; justify-content: flex-end; margin-top: 10px; }
.app-pw-new { margin: 8px 0; }
.app-pw-item { display: flex; align-items: center; gap: 10px; padding: 6px 0; border-top: 1px solid var(--border); }
.app-pw-name { font-weight: 500; }
.app-pw-meta { font-size: 11px; color: var(--text-3); margin-left: auto; }
.ct-eye, .ct-bell { opacity: .45; transition: opacity .15s; }
.ct-eye[data-ct-visible="1"], .ct-bell[data-ct-on="1"] { opacity: 1; }
.ct-eye:hover, .ct-bell:hover { opacity: 1; }
/* ── Month View (spanning bars) ─────────────────────────── */
.month-body {
display: flex; flex-direction: column; flex: 1; overflow: hidden;
}
.month-row {
display: flex; flex: 1; position: relative; min-height: 100px;
border-bottom: 1px solid var(--border);
}
.month-row:last-child { border-bottom: none; }
/* row-right: flex row containing 7 full-height column divs + events overlay */
.month-row-right {
margin-left: 38px; display: flex; flex: 1; position: relative; min-width: 0;
}
.month-span-event {
position: absolute;
height: 18px; line-height: 18px;
border-radius: 3px; padding: 0 6px;
font-size: 11px; font-weight: 500;
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
cursor: pointer; color: #fff;
transition: filter var(--transition);
box-sizing: border-box;
pointer-events: all;
}
.month-span-event:hover { filter: brightness(1.15); }
.month-span-event.past { opacity: .45; }
.month-span-event.continues-left {
border-top-left-radius: 0; border-bottom-left-radius: 0; padding-left: 3px;
}
.month-span-event.continues-right {
border-top-right-radius: 0; border-bottom-right-radius: 0; padding-right: 3px;
}
/* ── Responsive ─────────────────────────────────────────── */
@media (max-width: 768px) {
:root { --sidebar-w: 0px; }
.sidebar { position: fixed; left: 0; top: var(--topbar-h); bottom: 0; z-index: 200; width: 256px; transform: translateX(-100%); }
.sidebar.open { transform: translateX(0); }
.topbar-left { width: auto; }
.view-switcher .view-btn { padding: 6px 8px; font-size: 12px; }
.logo-text { display: none; }
.view-title { font-size: 16px; }
}
/* ── Custom Date/Time Display Field ─────────────────────── */
.dt-display {
display: flex; align-items: center; justify-content: space-between;
background: var(--bg-app);
border: 1px solid var(--border);
border-radius: var(--radius-sm);
padding: 10px 12px;
color: var(--text-1);
cursor: pointer;
transition: border-color var(--transition);
user-select: none;
min-height: 42px;
}
.dt-display:hover, .dt-display:focus { border-color: var(--primary); outline: none; }
.dt-display-text { font-size: 14px; }
.dt-display-icon { color: var(--text-3); flex-shrink: 0; margin-left: 6px; }
/* ── Date/Time Picker Card ───────────────────────────────── */
.dtp-overlay {
position: fixed; inset: 0; z-index: 700;
}
.dtp-card {
position: fixed; z-index: 701;
background: var(--bg-surface);
border: 1px solid var(--border);
border-radius: var(--radius);
box-shadow: var(--shadow-lg);
padding: 16px;
width: 272px;
user-select: none;
}
/* Calendar header */
.dtp-cal-header {
display: flex; align-items: center; justify-content: space-between;
margin-bottom: 10px;
}
.dtp-month-label {
font-size: 14px; font-weight: 600; color: var(--text-1);
}
.dtp-nav-btn {
background: none; border: none; cursor: pointer;
color: var(--text-2); font-size: 22px; line-height: 1;
padding: 2px 6px; border-radius: var(--radius-sm);
transition: background var(--transition), color var(--transition);
}
.dtp-nav-btn:hover { background: var(--hover-highlight); color: var(--text-1); }
/* Day-of-week headers */
.dtp-grid {
display: grid; grid-template-columns: repeat(7, 1fr);
gap: 2px; margin-bottom: 4px;
}
.dtp-dow {
text-align: center; font-size: 11px; font-weight: 600;
color: var(--text-3); padding: 4px 0; text-transform: uppercase;
}
/* Day cells */
.dtp-day {
display: flex; align-items: center; justify-content: center;
height: 34px; border-radius: 6px;
font-size: 13px; font-weight: 500; color: var(--text-1);
cursor: pointer; transition: background var(--transition);
}
.dtp-day:hover { background: var(--day-hover-color); }
.dtp-day.other { color: var(--text-3); }
.dtp-day.other:hover { background: var(--day-hover-color); }
.dtp-day.today { color: var(--primary); font-weight: 700; }
.dtp-day.selected {
background: var(--primary) !important;
color: #fff !important; font-weight: 700;
}
/* Time picker */
.dtp-time-row {
display: flex; align-items: center; justify-content: center;
gap: 4px; margin: 12px 0 8px;
border-top: 1px solid var(--border-light);
padding-top: 12px;
}
.dtp-colon {
font-size: 22px; font-weight: 600; color: var(--text-2);
padding: 0 2px; line-height: 1;
align-self: center;
}
.dtp-tc-wrap {
position: relative; width: 64px;
}
.dtp-tc {
height: calc(3 * 40px); /* 120px = 3 visible items */
overflow-y: scroll;
scroll-snap-type: y mandatory;
scrollbar-width: none;
padding: 40px 0; /* top/bottom padding so first/last can center */
box-sizing: content-box;
}
.dtp-tc::-webkit-scrollbar { display: none; }
.dtp-ti {
height: 40px; line-height: 40px;
text-align: center; font-size: 20px; font-weight: 500;
scroll-snap-align: center;
border-radius: 8px;
cursor: pointer;
color: var(--text-2);
transition: background .1s, color .1s;
}
.dtp-ti:hover { color: var(--text-1); }
.dtp-ti.selected {
background: var(--primary);
color: #fff;
}
/* Actions */
.dtp-actions {
display: flex; justify-content: flex-end; gap: 8px;
margin-top: 12px; padding-top: 10px;
border-top: 1px solid var(--border-light);
}
/* ── Mobile / PWA additions ─────────────────────────────────
Additive only — does not modify any existing rules above. */
/* Backdrop element exists in DOM but is hidden by default on desktop */
.sidebar-backdrop { display: none; }
/* Mobile-only UI elements: hidden on desktop ───────────── */
.view-mobile-wrapper { position: relative; display: none; }
.settings-nav-toggle { display: none; }
.settings-nav-backdrop { display: none; }
.dropdown-item-mobile-only { display: none; }
.create-fab { display: none; }
/* View-title spans: visual space between main and year on desktop */
.view-title-year { margin-left: 6px; }
@media (max-width: 768px) {
html, body { overflow-x: hidden; max-width: 100vw; }
/* ── Sidebar slides in as overlay on mobile ─────────────── */
.sidebar {
position: fixed;
top: var(--topbar-h);
left: 0;
bottom: 0;
width: min(85vw, 320px);
z-index: 600;
transform: translateX(-100%);
transition: transform .25s ease;
box-shadow: var(--shadow-lg);
margin-right: 0 !important;
}
body.sidebar-open .sidebar { transform: translateX(0); }
/* Neutralize the desktop .collapsed shift on mobile so the JS toggle
never creates a second hidden state to fight with .sidebar-open */
.sidebar.collapsed { transform: translateX(-100%); margin-right: 0 !important; }
body.sidebar-open .sidebar.collapsed { transform: translateX(0); }
.sidebar-backdrop {
display: block;
position: fixed;
inset: 0;
background: rgba(0,0,0,.55);
z-index: 500;
opacity: 0;
pointer-events: none;
transition: opacity .2s ease;
}
body.sidebar-open .sidebar-backdrop {
opacity: 1;
pointer-events: auto;
}
/* ── Topbar tightening + scrollable view switcher ────────── */
.topbar { padding: 0 8px; gap: 4px; }
.topbar-left { width: auto; flex-shrink: 0; }
.topbar-center {
min-width: 0;
overflow: hidden;
}
.topbar-center .view-title {
font-size: 14px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.topbar-right {
min-width: 0;
/* no overflow:hidden — would clip the user dropdown on tap */
}
.view-switcher {
overflow-x: auto;
overflow-y: hidden;
flex-wrap: nowrap;
max-width: 100%;
-webkit-overflow-scrolling: touch;
scrollbar-width: none;
}
.view-switcher::-webkit-scrollbar { display: none; }
.view-switcher .view-btn { flex: 0 0 auto; }
/* ── 44px minimum tap targets ────────────────────────────── */
.icon-btn {
min-width: 44px;
min-height: 44px;
}
.btn { min-height: 44px; }
.view-switcher .view-btn { min-height: 40px; }
/* ── Month view: events keep text, just smaller ──────────── */
.month-span-event {
height: 14px !important;
line-height: 14px !important;
padding: 0 4px !important;
font-size: 9px !important;
font-weight: 500;
}
.month-more {
font-size: 9px;
padding: 0 2px;
}
.cell-day { font-size: 11px; }
/* ── Week view collapses to single day on mobile when today
is in the visible week. Falls back to default 7-col layout
for other weeks (use day view there). ──────────────────── */
.week-header-row:has(.week-day-header.today) .week-day-header:not(.today) { display: none; }
.week-header-row:has(.week-day-header.today) .week-day-header.today { flex: 1 1 100%; width: 100%; }
.week-days-col:has(.week-day-col.today) .week-day-col:not(.today) { display: none; }
.week-days-col:has(.week-day-col.today) .week-day-col.today { flex: 1 1 100%; width: 100%; }
.week-allday-row:has(.week-day-col.today) .week-day-col:not(.today) { display: none; }
/* ── Modals: full-screen on mobile ───────────────────────── */
.modal-overlay { padding: 0; }
.modal-card {
max-width: 100% !important;
width: 100% !important;
height: 100%;
max-height: 100%;
border-radius: 0;
display: flex;
flex-direction: column;
}
.modal-body {
flex: 1;
overflow-y: auto;
-webkit-overflow-scrolling: touch;
}
.modal-footer { flex-shrink: 0; }
/* Settings page modal: also full-screen */
.settings-page-card {
max-width: 100% !important;
width: 100% !important;
height: 100%;
max-height: 100%;
border-radius: 0;
}
/* ── Misc safety: prevent overflow on flex topbar items ──── */
.main-view { width: 100%; min-width: 0; }
#view-container { max-width: 100%; overflow-x: hidden; }
/* ── Long-press / text-selection / image-save fixes ──────── */
/* Calendar UI shouldn't be selectable on touch — long-press
should reach our handlers, not trigger iOS text selection. */
.topbar, .sidebar, .main-view,
.month-view, .month-row, .month-col, .cell-day, .month-events-overlay, .month-span-event,
.week-view, .day-view, .week-day-col, .week-day-header, .week-allday-row,
.quarter-view, .agenda-view,
.view-switcher, .view-btn, .btn, .icon-btn, .user-avatar, .user-dropdown, .dropdown-item {
-webkit-user-select: none;
user-select: none;
-webkit-touch-callout: none;
-webkit-tap-highlight-color: transparent;
}
/* Faster taps, no double-tap zoom on interactive elements */
.icon-btn, .btn, .view-btn, .user-avatar, .month-col, .week-day-col, .dropdown-item,
.sidebar-copyright, .impressum-link, .modal-close, [data-modal] {
touch-action: manipulation;
}
/* Avatar long-press: don't show "Save Image" — taps reach parent */
.user-avatar img {
-webkit-touch-callout: none;
pointer-events: none;
}
/* ── Calendar weeks (KW) shown as a small bubble, not a column ── */
.month-header {
grid-template-columns: repeat(7, 1fr) !important;
}
.month-kw-header { display: none !important; }
.month-row-right {
margin-left: 0 !important;
}
.month-kw-cell {
position: absolute;
/* Bottom-left: away from the day-number (top-left) */
left: 3px; bottom: 3px;
top: auto; right: auto;
width: auto; height: auto;
padding: 1px 6px;
background: var(--bg-active);
border: none !important;
border-radius: 10px;
font-size: 9px; font-weight: 600;
color: var(--text-2);
z-index: 5;
display: inline-flex;
align-items: center;
pointer-events: none;
}
/* ── Status-bar safe area inside full-screen modals (PWA) ── */
.modal-card .modal-header,
.settings-page-header {
padding-top: calc(16px + env(safe-area-inset-top, 0px));
}
.modal-footer,
.settings-page-body {
padding-bottom: calc(12px + env(safe-area-inset-bottom, 0px));
}
/* ── Topbar: hide desktop view-switcher + settings, show
mobile view-toggle and let the title breathe ──────────── */
.topbar .view-switcher { display: none; }
.topbar #btn-settings { display: none; }
.view-mobile-wrapper { display: inline-block; }
.dropdown-item-mobile-only { display: flex; }
/* Heute-Button bleibt im Topbar-Center, kompakter Stil für Mobile */
.topbar #btn-today {
padding: 6px 10px;
font-size: 13px;
min-height: 36px;
flex-shrink: 0;
}
/* Sidebar create-button: auf Mobile durch den runden FAB ersetzt */
#btn-create-event { display: none; }
/* Floating action button — bottom-right round button */
.create-fab {
display: flex;
position: fixed;
bottom: calc(20px + env(safe-area-inset-bottom, 0px));
right: 20px;
width: 56px; height: 56px;
border-radius: 50%;
background: var(--primary);
color: #fff;
align-items: center;
justify-content: center;
box-shadow: 0 4px 14px rgba(0,0,0,.5);
z-index: 450;
transition: filter var(--transition), transform var(--transition);
-webkit-tap-highlight-color: transparent;
touch-action: manipulation;
}
.create-fab:active { transform: scale(.95); }
.create-fab:hover { filter: brightness(1.1); }
/* The title is the most important info — let it grow */
.topbar-center { flex: 1; min-width: 0; }
.topbar-center .view-title {
font-size: 15px;
font-weight: 500;
padding-left: 4px;
flex: 1;
line-height: 1.1;
display: flex;
flex-direction: column;
align-items: flex-start;
overflow: hidden;
}
.view-title-main {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
max-width: 100%;
}
.view-title-year {
font-size: 11px;
font-weight: 400;
color: var(--text-2);
line-height: 1.1;
margin-left: 0;
}
.topbar-left { gap: 0; }
.topbar-right { gap: 0; }
/* Event-Popup auf Mobile: an Viewport-Breite anpassen */
.event-popup { width: min(94vw, 360px); max-width: 94vw; }
.popup-header { padding: 12px 8px 11px 16px; }
.popup-header h4 { font-size: 14.5px; }
.popup-icon-btn { width: 36px; height: 36px; }
.popup-icon-btn svg { width: 17px; height: 17px; }
/* Monatsansicht: Startzeit ausblenden — nur Titel anzeigen ──── */
.month-event-time { display: none; }
/* ── Settings modal: nav becomes a slide-in overlay ──────── */
.settings-nav-toggle { display: inline-flex !important; }
.settings-page-body { position: relative; }
.settings-nav {
position: absolute;
top: 0; left: 0; bottom: 0;
width: min(75vw, 280px);
z-index: 50;
background: var(--bg-app);
border-right: 1px solid var(--border);
transform: translateX(-100%);
transition: transform .25s ease;
box-shadow: var(--shadow-lg);
}
.settings-page-card.nav-open .settings-nav {
transform: translateX(0);
}
.settings-nav-backdrop {
display: block;
position: absolute; inset: 0;
background: rgba(0,0,0,.5);
z-index: 40;
opacity: 0;
pointer-events: none;
transition: opacity .2s ease;
}
.settings-page-card.nav-open .settings-nav-backdrop {
opacity: 1;
pointer-events: auto;
}
.settings-panels { padding: 16px; }
/* Modal headers: tighter on mobile */
.modal-header { padding: 12px 16px; }
.modal-body { padding: 16px; }
.modal-footer { padding: 12px 16px; }
}
/* iOS notch / home-indicator safe areas (PWA standalone) */
@supports (padding: env(safe-area-inset-top)) {
.topbar {
padding-top: env(safe-area-inset-top);
height: calc(var(--topbar-h) + env(safe-area-inset-top));
}
.sidebar { padding-bottom: env(safe-area-inset-bottom); }
/* The main content sits below the (now taller) topbar and must not
extend behind the home indicator at the bottom. */
.content-wrapper {
margin-top: calc(var(--topbar-h) + env(safe-area-inset-top));
height: calc(100vh - var(--topbar-h) - env(safe-area-inset-top) - env(safe-area-inset-bottom));
}
/* On mobile the slide-in sidebar also needs to start below the larger topbar */
@media (max-width: 768px) {
.sidebar { top: calc(var(--topbar-h) + env(safe-area-inset-top)); }
}
}
/* ── Collaboration: sharing badges & user picker ───────────── */
.cal-badge {
display: inline-block;
font-size: 11px;
padding: 2px 8px;
border-radius: 999px;
background: var(--bg-surface);
color: var(--text-2);
border: 1px solid var(--border);
white-space: nowrap;
}
.cal-badge-shared {
background: rgba(66, 133, 244, 0.15);
color: var(--primary);
border-color: transparent;
}
.share-user-picker {
margin-top: 8px;
max-height: 220px;
overflow-y: auto;
border: 1px solid var(--border);
border-radius: 10px;
}
.share-user-item {
display: flex; align-items: center; gap: 10px;
padding: 10px 14px;
cursor: pointer;
border-bottom: 1px solid var(--border);
}
.share-user-item:last-child { border-bottom: none; }
.share-user-item:hover { background: var(--bg-surface); }
.share-user-item input[type=checkbox] {
flex-shrink: 0; width: 16px; height: 16px; accent-color: var(--primary); cursor: pointer;
}
/* Add-user row: match the app's dark inputs instead of raw white browser
controls, with a subtle focus ring for a modern feel. */
#share-user-search,
#share-permission {
background: var(--bg-app);
border: 1px solid var(--border);
border-radius: 10px;
padding: 10px 12px;
color: var(--text-1);
font-size: 14px;
outline: none;
transition: border-color var(--transition), box-shadow var(--transition);
}
#share-user-search::placeholder { color: var(--text-3); }
#share-permission { cursor: pointer; }
#share-user-search:focus,
#share-permission:focus {
border-color: var(--primary);
box-shadow: 0 0 0 3px rgba(66, 133, 244, 0.15);
}
/* "Shared with me" section header row inside the calendar-management table */
.ct-section-row td {
padding-top: 14px; font-size: 12px; font-weight: 600;
color: var(--text-3); text-transform: uppercase; letter-spacing: .04em;
}
/* Higher specificity than the global ".form-group label" (uppercase / spaced /
12px) so a checkbox label reads as normal inline text next to its box, not a
stretched uppercase column. */
.form-group label.checkbox-row,
.checkbox-row {
display: flex; align-items: center; justify-content: flex-start; gap: 8px;
cursor: pointer; text-transform: none; letter-spacing: normal;
font-size: 14px; font-weight: 400; color: var(--text-1);
}
/* Undo the global ".form-group input { width:100%; padding; border }" so the
checkbox stays a small native box instead of a full-width field that shoves
the label text into a narrow, wrapping column. */
.checkbox-row input[type=checkbox] {
flex: none; width: 16px; height: 16px; margin: 0; padding: 0;
border: 0; border-radius: 0; background: none; accent-color: var(--primary);
}
/* .popup-creator styling moved into the .popup-row / #popup-creator rules above. */
/* ── Groups ─────────────────────────────────────────────────── */
.group-view-banner {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
padding: 8px 16px;
background: var(--bg-surface); /* fallback for browsers without color-mix */
background: color-mix(in srgb, var(--accent) 15%, var(--bg-app));
border-bottom: 1px solid var(--accent);
font-size: 14px;
color: var(--text-1);
}
/* Group-member rows in the sidebar (colour dot = per-user colour, checkbox =
show/hide). Reuse the calendar-list item styling. */
.gm-row .gm-dot { cursor: pointer; }
.group-item-active {
background: var(--bg-surface);
background: color-mix(in srgb, var(--accent) 18%, transparent);
border-radius: 8px;
}
.group-item .cal-item-name { cursor: pointer; flex: 1; }
.cal-list-empty {
padding: 6px 4px;
font-size: 13px;
color: var(--text-3);
}
/* Group member picker rows — checkbox left, name left, one per line. */
.group-member-item {
display: flex;
align-items: center;
justify-content: flex-start;
gap: 10px;
padding: 10px 14px;
cursor: pointer;
border-bottom: 1px solid var(--border);
text-align: left;
text-transform: none;
}
.group-member-item:last-child { border-bottom: none; }
.group-member-item:hover { background: var(--bg-surface); }
.group-member-item input[type="checkbox"] { flex: 0 0 auto; margin: 0; }
.group-member-name { flex: 1 1 auto; color: var(--text-1); }
/* Calendar radio list (group-visible selection in settings). */
.cal-radio-list {
border: 1px solid var(--border);
border-radius: 10px;
overflow: hidden;
}
.cal-radio-item {
display: flex;
align-items: center;
gap: 10px;
padding: 10px 14px;
cursor: pointer;
border-bottom: 1px solid var(--border);
}
.cal-radio-item:last-child { border-bottom: none; }
.cal-radio-item:hover { background: var(--bg-surface); }
.cal-radio-item .cal-item-dot { border-radius: 50%; flex: 0 0 auto; }
/* Picker rows (group-visible calendar radio + group member checkboxes).
Deliberately NOT <label> elements, so the global ".form-group label"
uppercase/grey styling never applies. */
.cal-radio-list,
#group-member-picker {
border: 1px solid var(--border);
border-radius: 10px;
overflow: hidden;
max-height: 260px;
overflow-y: auto;
}
.pick-row {
display: flex;
align-items: center;
justify-content: flex-start;
gap: 10px;
padding: 10px 14px;
cursor: pointer;
border-bottom: 1px solid var(--border);
text-align: left;
text-transform: none;
letter-spacing: normal;
font-size: 14px;
color: var(--text-1);
}
.pick-row:last-child { border-bottom: none; }
.pick-row:hover { background: var(--bg-surface); }
.pick-row-sel { box-shadow: inset 3px 0 0 var(--accent); }
.pick-mark {
flex: 0 0 auto;
width: 18px; height: 18px;
border: 2px solid var(--text-3);
display: inline-flex; align-items: center; justify-content: center;
font-size: 12px; line-height: 1; color: #fff;
}
.pick-check { border-radius: 4px; }
.pick-radio { border-radius: 50%; }
.pick-mark.on { background: var(--accent); border-color: var(--accent); }
.pick-dot { flex: 0 0 auto; width: 12px; height: 12px; border-radius: 50%; }
.pick-dot-empty { background: transparent; }
.pick-name { flex: 1 1 auto; text-align: left; }
/* Flat calendar list: inline source label + drag handle. */
.cal-source {
margin-left: auto;
font-size: 11px;
color: var(--text-3);
white-space: nowrap;
max-width: 45%;
overflow: hidden;
text-overflow: ellipsis;
padding-left: 8px;
}
.cal-drag-handle {
flex: 0 0 auto;
cursor: grab;
color: var(--text-3);
font-size: 14px;
user-select: none;
}
.cal-item.cal-dragging { opacity: .5; }
/* Group emoji + icon picker */
.group-emoji { flex: 0 0 auto; font-size: 16px; cursor: pointer; line-height: 1; }
.cal-shared-flag { flex: 0 0 auto; font-size: 12px; opacity: .8; }
/* Read-only (shared with me) indicator: a struck-through pencil. */
.cal-readonly-flag { color: var(--icon-inactive-color); opacity: .7; margin-left: 2px; }
.group-icon-picker { display: flex; flex-wrap: wrap; gap: 6px; }
.group-icon-opt {
width: 38px; height: 38px;
display: inline-flex; align-items: center; justify-content: center;
font-size: 18px; line-height: 1;
background: var(--bg-app);
border: 1px solid var(--border);
border-radius: 8px;
cursor: pointer;
}
.group-icon-opt { color: var(--text-1); }
.group-icon-opt:hover { background: var(--bg-surface); }
.group-icon-opt.on { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent) inset; color: var(--accent); }
/* SVG group icons render as block so they centre cleanly (vs emoji baseline). */
.group-emoji svg, .cal-shared-flag svg, .group-icon-opt svg { display: block; }