<script lang="ts">
	import { api } from '$lib/api';
	import { user } from '$lib/user';
	import { get } from 'svelte/store';
	import { onMount } from 'svelte';
	import { RRule } from 'rrule';
	import { Calendar, TimeGrid, DayGrid } from '@event-calendar/core';
	import '@event-calendar/core/index.css';
	import type { Termin, Gruppe, Verfuegbarkeit, Veranstaltungsort, OrtAusfall } from '$lib/types';

	const isAdmin = () => { const u = get(user); return !u?.rolle || u.rolle === 'admin'; };
	const userId  = () => get(user)?.id as string;

	let termine     = $state<Termin[]>([]);
	let gruppen     = $state<Gruppe[]>([]);
	let alleUser    = $state<any[]>([]);
	let orte        = $state<Veranstaltungsort[]>([]);
	let ausfaelle   = $state<OrtAusfall[]>([]);
	let loading     = $state(true);

	// Ansicht
	type Ansicht = 'liste' | 'woche' | 'monat';
	let ansicht = $state<Ansicht>('liste');
	const calPlugins = [TimeGrid, DayGrid];

	// Formular
	let showForm           = $state(false);
	let editId             = $state<string | null>(null);
	let fTitel             = $state('');
	let fBeschr            = $state('');
	let fBeginn            = $state('');
	let fEnde              = $state('');
	let fOrt               = $state('');
	let fGruppeIds         = $state<string[]>([]);
	let fDurchfuehrenderId = $state('');
	let fOrtId             = $state('');
	let fWiederholung      = $state(false);
	let fRhythmus          = $state<'woechentlich' | 'zweıwoechentlich' | 'monatlich'>('woechentlich');
	let fBis               = $state('');
	let saving             = $state(false);
	let formError          = $state('');
	let showDelete         = $state<string | null>(null);
	let deleteSerieMode    = $state(false);

	const now = new Date();

	const upcoming = $derived(
		termine
			.filter(t => new Date(t.beginn) >= now)
			.sort((a, b) => new Date(a.beginn).getTime() - new Date(b.beginn).getTime())
	);
	const vergangen = $derived(
		termine
			.filter(t => new Date(t.beginn) < now)
			.sort((a, b) => new Date(b.beginn).getTime() - new Date(a.beginn).getTime())
	);

	// Admin-Warnung: Termine ohne Bestätigung
	const offene = $derived(
		upcoming.filter(t => !t.verfuegbarkeit || t.verfuegbarkeit === 'offen' || t.verfuegbarkeit === 'vertretung_gesucht')
	);

	onMount(async () => {
		[termine, gruppen, alleUser, orte, ausfaelle] = await Promise.all([
			api.get<Termin[]>('/termine', { sort: 'beginn' }),
			api.get<Gruppe[]>('/gruppen', { sort: 'name' }),
			isAdmin()
				? api.get<any[]>('/users', { rolle: 'trainer' })
				: Promise.resolve([]),
			api.get<Veranstaltungsort[]>('/orte', { sort: 'name', aktiv: 'true' }),
			api.get<OrtAusfall[]>('/ort-ausfaelle', { sort: 'von' }),
		]);
		loading = false;
	});

	function toLocal(iso: string | undefined): string {
		if (!iso) return '';
		const d = new Date(iso);
		return new Date(d.getTime() - d.getTimezoneOffset() * 60000).toISOString().slice(0, 16);
	}
	function fromLocal(local: string): string {
		return local ? new Date(local).toISOString() : '';
	}

	function neuerTermin() {
		editId = null; fTitel = ''; fBeschr = ''; fBeginn = ''; fEnde = '';
		fOrt = ''; fOrtId = ''; fGruppeIds = []; fDurchfuehrenderId = '';
		fWiederholung = false; fRhythmus = 'woechentlich'; fBis = '';
		formError = ''; showForm = true;
	}

	function bearbeiten(t: Termin) {
		editId = t.id; fTitel = t.titel; fBeschr = t.beschreibung ?? '';
		fBeginn = toLocal(t.beginn); fEnde = toLocal(t.ende);
		fOrt = t.ort ?? ''; fOrtId = t.ort_id ?? ''; fGruppeIds = t.gruppe_ids ?? [];
		fDurchfuehrenderId = t.durchfuehrender_id ?? '';
		fWiederholung = false;
		formError = ''; showForm = true;
	}

	// Ausfall-Check für einen Termin
	function ortAusfall(t: Termin): OrtAusfall | undefined {
		if (!t.ort_id) return undefined;
		const d = t.beginn.slice(0, 10);
		return ausfaelle.find(a => a.ort_id === t.ort_id && a.von <= d && a.bis >= d);
	}

	function ortNameById(id: string | undefined): string {
		if (!id) return '';
		return orte.find(o => o.id === id)?.name ?? '';
	}

	function generiereTerminDaten(beginn: Date, rruleStr: string | null) {
		return {
			titel:              fTitel.trim(),
			beschreibung:       fBeschr.trim() || null,
			ort:                fOrtId ? null : (fOrt.trim() || null),
			ort_id:             fOrtId || null,
			gruppe_ids:         fGruppeIds,
			durchfuehrender_id: fDurchfuehrenderId || null,
			verfuegbarkeit:     fDurchfuehrenderId ? 'offen' : null,
			rrule:              rruleStr,
		};
	}

	async function speichern() {
		if (!fTitel.trim() || !fBeginn) { formError = 'Titel und Beginn sind Pflichtfelder.'; return; }
		if (fWiederholung && !fBis) { formError = 'Bitte ein Enddatum für die Wiederholung angeben.'; return; }
		formError = ''; saving = true;

		try {
			if (fWiederholung && !editId) {
				// Serie anlegen: rrule generieren, Einzeltermine erstellen
				const dtstart = new Date(fBeginn);
				const until   = new Date(fBis + 'T23:59:59');
				const dauer   = fEnde ? new Date(fEnde).getTime() - dtstart.getTime() : 60 * 60 * 1000;

				const freq     = fRhythmus === 'monatlich' ? RRule.MONTHLY : RRule.WEEKLY;
				const interval = fRhythmus === 'zweıwoechentlich' ? 2 : 1;

				const rule = new RRule({ freq, interval, dtstart, until });
				const rruleStr = `FREQ=${fRhythmus === 'monatlich' ? 'MONTHLY' : 'WEEKLY'}${interval === 2 ? ';INTERVAL=2' : ''};UNTIL=${until.toISOString().replace(/[-:]/g, '').slice(0, 15)}Z`;
				const serie_id = crypto.randomUUID();
				const dates    = rule.all();

				const neu = await Promise.all(
					dates.map(d =>
						api.post<Termin>('/termine', {
							...generiereTerminDaten(d, rruleStr),
							beginn:   d.toISOString(),
							ende:     fEnde ? new Date(d.getTime() + dauer).toISOString() : null,
							serie_id,
						}),
					),
				);
				termine = [...termine, ...neu];
			} else {
				const data = {
					...generiereTerminDaten(new Date(fBeginn), null),
					beginn: fromLocal(fBeginn),
					ende:   fEnde ? fromLocal(fEnde) : null,
				};
				if (editId) {
					const updated = await api.put<Termin>('/termine/' + editId, data);
					termine = termine.map(t => t.id === editId ? updated : t);
				} else {
					const neu = await api.post<Termin>('/termine', data);
					termine = [...termine, neu];
				}
			}
			showForm = false;
		} catch (e: unknown) {
			formError = e instanceof Error ? e.message : 'Fehler beim Speichern.';
		} finally {
			saving = false;
		}
	}

	async function loeschen(t: Termin, ganzeSerieLoeschen: boolean) {
		if (ganzeSerieLoeschen && t.serie_id) {
			const serie = termine.filter(x => x.serie_id === t.serie_id);
			await Promise.all(serie.map(s => api.del('/termine/' + s.id)));
			termine = termine.filter(x => x.serie_id !== t.serie_id);
		} else {
			await api.del('/termine/' + t.id);
			termine = termine.filter(x => x.id !== t.id);
		}
		showDelete = null;
	}

	// Vorschau: wie viele Termine werden erzeugt?
	const serieVorschau = $derived(() => {
		if (!fWiederholung || !fBeginn || !fBis) return 0;
		try {
			const dtstart = new Date(fBeginn);
			const until   = new Date(fBis + 'T23:59:59');
			const freq     = fRhythmus === 'monatlich' ? RRule.MONTHLY : RRule.WEEKLY;
			const interval = fRhythmus === 'zweıwoechentlich' ? 2 : 1;
			return new RRule({ freq, interval, dtstart, until }).all().length;
		} catch { return 0; }
	});

	async function setVerfuegbarkeit(t: Termin, v: Verfuegbarkeit) {
		const updated = await api.put<Termin>('/termine/' + t.id, { verfuegbarkeit: v });
		termine = termine.map(x => x.id === t.id ? updated : x);
	}

	function toggleGruppe(id: string) {
		fGruppeIds = fGruppeIds.includes(id)
			? fGruppeIds.filter(g => g !== id)
			: [...fGruppeIds, id];
	}

	function formatDatum(iso: string): string {
		return new Date(iso).toLocaleDateString('de-DE', {
			weekday: 'short', day: '2-digit', month: 'long', year: 'numeric',
		});
	}
	function formatZeit(iso: string): string {
		return new Date(iso).toLocaleTimeString('de-DE', { hour: '2-digit', minute: '2-digit' });
	}
	function gruppenLabel(ids: string[]): string {
		return (ids ?? []).map(id => gruppen.find(g => g.id === id)?.name).filter(Boolean).join(', ');
	}
	function userName(uid: string | undefined): string {
		if (!uid) return '';
		const u = alleUser.find((u: any) => u.id === uid);
		return u?.name ?? '';
	}

	const verfuegbarkeitConfig: Record<Verfuegbarkeit, { label: string; farbe: string }> = {
		offen:              { label: 'Offen',              farbe: 'var(--c-warning)' },
		bestaetigt:         { label: 'Bestätigt',          farbe: 'var(--c-success)' },
		abgesagt:           { label: 'Abgesagt',           farbe: 'var(--c-error)' },
		vertretung_gesucht: { label: 'Vertretung gesucht', farbe: 'var(--c-accent)' },
	};

	function istMeinTermin(t: Termin): boolean {
		return t.durchfuehrender_id === userId();
	}

	function verfuegbarkeitFarbe(t: Termin): string {
		switch (t.verfuegbarkeit) {
			case 'bestaetigt':         return 'var(--c-success)';
			case 'abgesagt':           return 'var(--c-error)';
			case 'vertretung_gesucht': return 'var(--c-accent)';
			default:                   return 'var(--c-primary)';
		}
	}

	const calEvents = $derived(termine.map(t => ({
		id:              t.id,
		title:           t.titel,
		start:           t.beginn,
		end:             t.ende ?? new Date(new Date(t.beginn).getTime() + 60 * 60 * 1000).toISOString(),
		backgroundColor: verfuegbarkeitFarbe(t),
		extendedProps:   { termin: t },
	})));

	const calOptions = $derived({
		view:       ansicht === 'monat' ? 'dayGridMonth' : 'timeGridWeek',
		locale:     'de',
		firstDay:   1,
		height:     ansicht === 'monat' ? 'auto' : '72dvh',
		events:     calEvents,
		slotMinTime: '07:00:00',
		slotMaxTime: '23:00:00',
		allDaySlot:  false,
		headerToolbar: {
			start:  'prev,next today',
			center: 'title',
			end:    '',
		},
		buttonText: { today: 'Heute' },
		eventClick: (info: any) => {
			const t: Termin = info.event.extendedProps.termin;
			if (isAdmin()) bearbeiten(t);
		},
	});
</script>

<svelte:head><title>Termine — vereins.haus</title></svelte:head>

<div class="top">
	<h1>Termine</h1>
	<div class="top-rechts">
		{#if isAdmin()}
			<a href="/orte" class="btn-orte">Orte</a>
		{/if}
		<div class="ansicht-switcher">
			<button class:aktiv={ansicht === 'liste'} onclick={() => ansicht = 'liste'} title="Listenansicht">☰</button>
			<button class:aktiv={ansicht === 'woche'} onclick={() => ansicht = 'woche'} title="Wochenansicht">W</button>
			<button class:aktiv={ansicht === 'monat'} onclick={() => ansicht = 'monat'} title="Monatsansicht">M</button>
		</div>
		{#if isAdmin()}
			<button class="btn-primary" onclick={neuerTermin}>+ Termin</button>
		{/if}
	</div>
</div>

{#if isAdmin() && offene.length > 0}
	<div class="warnung">
		⚠ {offene.length} {offene.length === 1 ? 'Termin benötigt' : 'Termine benötigen'} eine Bestätigung
	</div>
{/if}

{#if loading}
	<p class="hint">Laden…</p>
{:else if ansicht !== 'liste'}
	<div class="kalender-wrap">
		<Calendar plugins={calPlugins} options={calOptions} />
	</div>
{:else if termine.length === 0}
	<p class="hint">Noch keine Termine geplant.</p>
{:else}
	{#if upcoming.length > 0}
		<ul class="liste">
			{#each upcoming as t (t.id)}
				<li class="karte">
					<div class="karte-datum-col">
						<span class="tag">{new Date(t.beginn).toLocaleDateString('de-DE', { weekday: 'short' })}</span>
						<span class="tag-zahl">{new Date(t.beginn).getDate()}</span>
						<span class="monat">{new Date(t.beginn).toLocaleDateString('de-DE', { month: 'short' })}</span>
					</div>

					<div class="karte-info">
						<div class="karte-titel-zeile">
							<span class="karte-titel">{t.titel}</span>
							{#if t.serie_id}<span class="serie-badge" title="Wiederholungsserie">↻</span>{/if}
						</div>
						<span class="karte-meta">
							{formatZeit(t.beginn)}{t.ende ? ' – ' + formatZeit(t.ende) : ''}{t.ort ? ' · ' + t.ort : ''}
						</span>
						{#if t.ort_id || t.ort}
							<span class="karte-meta">{ortNameById(t.ort_id) || t.ort}</span>
						{/if}
						{#if t.gruppe_ids?.length}
							<span class="karte-sub">{gruppenLabel(t.gruppe_ids)}</span>
						{/if}
						{#if ortAusfall(t)}
							{@const af = ortAusfall(t)!}
							<span class="ausfall-warn">⚠ Ort gesperrt{af.grund ? ': ' + af.grund : ''}</span>
						{/if}

						{#if t.durchfuehrender_id}
							<div class="verfueg-zeile">
								{#if t.verfuegbarkeit && t.verfuegbarkeit !== 'offen'}
									<span class="verfueg-badge" style="color:{verfuegbarkeitConfig[t.verfuegbarkeit].farbe}">
										● {verfuegbarkeitConfig[t.verfuegbarkeit].label}
									</span>
								{:else}
									<span class="verfueg-badge" style="color:var(--c-warning)">● Offen</span>
								{/if}
								{#if isAdmin() && userName(t.durchfuehrender_id)}
									<span class="karte-sub">→ {userName(t.durchfuehrender_id)}</span>
								{/if}
							</div>

							{#if istMeinTermin(t)}
								<div class="meine-aktionen">
									<button
										class="btn-aktion bestaetigen"
										class:aktiv={t.verfuegbarkeit === 'bestaetigt'}
										onclick={() => setVerfuegbarkeit(t, 'bestaetigt')}
									>Ich bin dabei</button>
									<button
										class="btn-aktion absagen"
										class:aktiv={t.verfuegbarkeit === 'abgesagt'}
										onclick={() => setVerfuegbarkeit(t, 'abgesagt')}
									>Kann nicht</button>
									<button
										class="btn-aktion vertretung"
										class:aktiv={t.verfuegbarkeit === 'vertretung_gesucht'}
										onclick={() => setVerfuegbarkeit(t, 'vertretung_gesucht')}
									>Vertretung gesucht</button>
								</div>
							{/if}
						{/if}
					</div>

					{#if isAdmin()}
						<div class="karte-aktionen">
							<button class="btn-icon" onclick={() => bearbeiten(t)} title="Bearbeiten">✎</button>
							<button class="btn-icon btn-icon-red" onclick={() => { showDelete = t.id; deleteSerieMode = false; }} title="Löschen">✕</button>
						</div>
					{/if}
				</li>
			{/each}
		</ul>
	{/if}

	{#if vergangen.length > 0}
		<details class="vergangen">
			<summary>Vergangene Termine ({vergangen.length})</summary>
			<ul class="liste vergangen-liste">
				{#each vergangen as t (t.id)}
					<li class="karte karte-grau">
						<div class="karte-datum-col">
							<span class="tag">{new Date(t.beginn).toLocaleDateString('de-DE', { weekday: 'short' })}</span>
							<span class="tag-zahl">{new Date(t.beginn).getDate()}</span>
							<span class="monat">{new Date(t.beginn).toLocaleDateString('de-DE', { month: 'short' })}</span>
						</div>
						<div class="karte-info">
							<span class="karte-titel">{t.titel}</span>
							<span class="karte-meta">{formatDatum(t.beginn)}{t.ort ? ' · ' + t.ort : ''}</span>
						</div>
						{#if isAdmin()}
							<div class="karte-aktionen">
								<button class="btn-icon btn-icon-red" onclick={() => showDelete = t.id} title="Löschen">✕</button>
							</div>
						{/if}
					</li>
				{/each}
			</ul>
		</details>
	{/if}
{/if}

<!-- Termin-Formular (nur Admin) -->
{#if showForm && isAdmin()}
	<div class="overlay" role="dialog" aria-modal="true">
		<div class="sheet">
			<h2>{editId ? 'Termin bearbeiten' : 'Neuer Termin'}</h2>
			<form onsubmit={(e) => { e.preventDefault(); speichern(); }}>
				<div class="field">
					<label for="ftitel">Titel *</label>
					<input id="ftitel" type="text" bind:value={fTitel} required />
				</div>
				<div class="row">
					<div class="field">
						<label for="fbeginn">Beginn *</label>
						<input id="fbeginn" type="datetime-local" bind:value={fBeginn} required />
					</div>
					<div class="field">
						<label for="fende">Ende</label>
						<input id="fende" type="datetime-local" bind:value={fEnde} />
					</div>
				</div>
				{#if orte.length > 0}
					<div class="field">
						<label for="fort-id">Ort</label>
						<select id="fort-id" bind:value={fOrtId}>
							<option value="">— Freitext —</option>
							{#each orte as o (o.id)}
								<option value={o.id}>{o.name}</option>
							{/each}
						</select>
					</div>
					{#if !fOrtId}
						<div class="field">
							<label for="fort">Ort (Freitext)</label>
							<input id="fort" type="text" bind:value={fOrt} placeholder="z. B. Vereinsheim" />
						</div>
					{/if}
				{:else}
					<div class="field">
						<label for="fort">Ort <a class="ort-link" href="/orte">Orte verwalten →</a></label>
						<input id="fort" type="text" bind:value={fOrt} />
					</div>
				{/if}
				<div class="field">
					<label for="fbeschr">Beschreibung</label>
					<textarea id="fbeschr" bind:value={fBeschr} rows="2"></textarea>
				</div>
				<div class="field">
					<label for="fdurch">Durchführender</label>
					<select id="fdurch" bind:value={fDurchfuehrenderId}>
						<option value="">— nicht zugewiesen —</option>
						{#each alleUser as u (u.id)}
							<option value={u.id}>{u.name}</option>
						{/each}
					</select>
				</div>
				{#if !editId}
					<div class="field">
						<label class="toggle-label">
							<input type="checkbox" bind:checked={fWiederholung} />
							Wiederholt sich
						</label>
					</div>

					{#if fWiederholung}
						<div class="row">
							<div class="field">
								<label for="frhythmus">Rhythmus</label>
								<select id="frhythmus" bind:value={fRhythmus}>
									<option value="woechentlich">Wöchentlich</option>
									<option value="zweıwoechentlich">Zweiwöchentlich</option>
									<option value="monatlich">Monatlich</option>
								</select>
							</div>
							<div class="field">
								<label for="fbis">Bis (Datum)</label>
								<input id="fbis" type="date" bind:value={fBis} required />
							</div>
						</div>
						{#if serieVorschau() > 0}
							<p class="serie-vorschau">→ {serieVorschau()} Termine werden angelegt</p>
						{/if}
					{/if}
				{/if}

			{#if gruppen.length > 0}
					<div class="field">
						<span class="field-label">Für Gruppen</span>
						<div class="checkboxes">
							{#each gruppen as g (g.id)}
								<label class="check-label" class:active={fGruppeIds.includes(g.id)}>
									<input type="checkbox" checked={fGruppeIds.includes(g.id)} onchange={() => toggleGruppe(g.id)} />
									{g.name}
								</label>
							{/each}
						</div>
					</div>
				{/if}
				{#if formError}<p class="error">{formError}</p>{/if}
				<div class="actions">
					<button type="button" class="btn-ghost" onclick={() => showForm = false}>Abbrechen</button>
					<button type="submit" class="btn-primary" disabled={saving}>{saving ? 'Speichern…' : 'Speichern'}</button>
				</div>
			</form>
		</div>
	</div>
{/if}

<!-- Lösch-Dialog -->
{#if showDelete}
	{@const t = termine.find(x => x.id === showDelete)!}
	<div class="overlay" role="dialog" aria-modal="true">
		<div class="dialog">
			<p>Termin löschen?</p>
			{#if t?.serie_id}
				<div class="radio-group">
					<label class="radio-label">
						<input type="radio" bind:group={deleteSerieMode} value={false} />
						Nur diesen Termin
					</label>
					<label class="radio-label">
						<input type="radio" bind:group={deleteSerieMode} value={true} />
						Alle Termine der Serie löschen
					</label>
				</div>
			{:else}
				<p class="dialog-sub">Diese Aktion kann nicht rückgängig gemacht werden.</p>
			{/if}
			<div class="dialog-actions">
				<button class="btn-ghost" onclick={() => showDelete = null}>Abbrechen</button>
				<button class="btn-danger" onclick={() => loeschen(t, deleteSerieMode)}>Löschen</button>
			</div>
		</div>
	</div>
{/if}

<style>
	.top { display: flex; align-items: center; justify-content: space-between; margin-bottom: 1rem; }
	.top .btn-primary { flex: none; padding: 0.45rem 0.9rem; font-size: 0.875rem; }
	.top-rechts { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; }
	h1 { font-size: 1.4rem; font-weight: 700; color: var(--c-text); }
	.btn-orte {
		padding: 0.5rem 0.85rem; background: none;
		border: 1.5px solid var(--c-border); border-radius: 8px;
		font-size: 0.85rem; color: var(--c-text-secondary); text-decoration: none;
	}

	.ansicht-switcher {
		display: flex; border: 1.5px solid var(--c-border); border-radius: 8px; overflow: hidden;
	}
	.ansicht-switcher button {
		padding: 0.4rem 0.75rem; background: none; border: none;
		font-size: 0.82rem; font-weight: 600; color: var(--c-text-muted); cursor: pointer;
		transition: background 0.15s, color 0.15s;
	}
	.ansicht-switcher button + button { border-left: 1px solid var(--c-border); }
	.ansicht-switcher button.aktiv { background: var(--c-primary); color: var(--c-bg-card); }

	.kalender-wrap {
		margin-bottom: 1rem;
		--ec-today-bg-color: var(--c-primary-subtle);
		--ec-event-bg-color: var(--c-primary);
		--ec-border-color: var(--c-border);
		--ec-text-color: var(--c-text);
		--ec-button-bg-color: var(--c-bg-card);
		--ec-button-border-color: var(--c-border);
		--ec-button-text-color: var(--c-text-secondary);
		--ec-active-bg-color: var(--c-primary);
		--ec-active-text-color: var(--c-bg-card);
	}
	.ausfall-warn { font-size: 0.75rem; color: var(--c-error); font-weight: 600; }
	.ort-link { font-size: 0.75rem; color: var(--c-primary); margin-left: 0.5rem; }
	.hint { color: var(--c-text-hint); font-size: 0.95rem; text-align: center; margin-top: 3rem; }

	.warnung {
		background: var(--c-warning-subtle); border: 1px solid var(--c-warning-light);
		border-radius: 8px; padding: 0.65rem 0.9rem;
		font-size: 0.85rem; color: var(--c-warning-dark); margin-bottom: 1rem;
	}

	.liste { list-style: none; padding: 0; display: flex; flex-direction: column; gap: 0.5rem; margin-bottom: 1rem; }

	.karte {
		display: flex; align-items: flex-start; gap: 0.75rem;
		padding: 0.85rem 1rem; background: var(--c-bg-card);
		border: 1px solid var(--c-border); border-radius: 10px;
	}
	.karte-grau { background: var(--c-bg-subtle); opacity: 0.75; }

	.karte-datum-col {
		display: flex; flex-direction: column; align-items: center;
		min-width: 2.2rem; padding-top: 0.1rem;
	}
	.tag      { font-size: 0.65rem; font-weight: 600; color: var(--c-text-hint); text-transform: uppercase; }
	.tag-zahl { font-size: 1.4rem; font-weight: 700; color: var(--c-primary); line-height: 1.1; }
	.monat    { font-size: 0.65rem; color: var(--c-text-hint); text-transform: uppercase; }

	.karte-info { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 0.2rem; }
	.karte-titel-zeile { display: flex; align-items: center; gap: 0.4rem; }
	.karte-titel { font-weight: 600; font-size: 0.95rem; color: var(--c-text); }
	.serie-badge { font-size: 0.75rem; color: var(--c-primary); font-weight: 700; }
	.karte-meta  { font-size: 0.78rem; color: var(--c-text-muted); }
	.karte-sub   { font-size: 0.72rem; color: var(--c-text-hint); }

	.verfueg-zeile { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; margin-top: 0.2rem; }
	.verfueg-badge { font-size: 0.75rem; font-weight: 600; }

	.meine-aktionen {
		display: flex; gap: 0.35rem; flex-wrap: wrap; margin-top: 0.4rem;
	}
	.btn-aktion {
		padding: 0.3rem 0.65rem; border-radius: 20px;
		font-size: 0.75rem; font-weight: 600; cursor: pointer;
		border: 1.5px solid var(--c-border); background: var(--c-bg-card);
		transition: all 0.15s;
	}
	.btn-aktion.bestaetigen        { color: var(--c-success); }
	.btn-aktion.bestaetigen.aktiv  { background: var(--c-success-bg); border-color: var(--c-success); }
	.btn-aktion.absagen            { color: var(--c-error); }
	.btn-aktion.absagen.aktiv      { background: var(--c-error-bg); border-color: var(--c-error); }
	.btn-aktion.vertretung         { color: var(--c-accent); }
	.btn-aktion.vertretung.aktiv   { background: var(--c-accent-subtle); border-color: var(--c-accent); }

	.karte-aktionen { display: flex; gap: 0.35rem; flex-shrink: 0; }
	.btn-icon {
		width: 1.9rem; height: 1.9rem; display: flex; align-items: center;
		justify-content: center; background: none; border: 1px solid var(--c-border);
		border-radius: 6px; color: var(--c-text-muted); font-size: 0.85rem; cursor: pointer;
	}
	.btn-icon:hover { border-color: var(--c-text-hint); color: var(--c-text); }
	.btn-icon-red:hover { border-color: var(--c-error-light); color: var(--c-error); }

	.vergangen summary {
		font-size: 0.85rem; color: var(--c-text-hint); cursor: pointer;
		padding: 0.5rem 0; list-style: none; user-select: none;
	}
	.vergangen-liste { margin-top: 0.5rem; }

	/* Sheet */
	.overlay {
		position: fixed; inset: 0; background: rgba(0,0,0,0.4);
		display: flex; align-items: flex-end; justify-content: center;
		z-index: 100; padding: 1rem;
		padding-bottom: calc(1rem + env(safe-area-inset-bottom));
	}
	.sheet {
		background: var(--c-bg-card); border-radius: 16px; padding: 1.5rem;
		width: 100%; max-width: 480px; max-height: 92dvh; overflow-y: auto;
	}
	h2 { font-size: 1.1rem; font-weight: 700; color: var(--c-text); margin-bottom: 1rem; }
	.row { display: grid; grid-template-columns: 1fr 1fr; gap: 0.75rem; }
	.field { display: flex; flex-direction: column; gap: 0.3rem; margin-bottom: 0.9rem; }
	label, .field-label { font-size: 0.875rem; font-weight: 500; color: var(--c-text-secondary); }
	input, textarea, select {
		padding: 0.65rem 0.85rem; border: 1.5px solid var(--c-border); border-radius: 8px;
		font-size: 1rem; background: var(--c-bg-card); width: 100%;
		box-sizing: border-box; font-family: inherit; resize: vertical;
		transition: border-color 0.15s;
	}
	input:focus, textarea:focus, select:focus { outline: none; border-color: var(--c-primary); }
	.checkboxes { display: flex; flex-wrap: wrap; gap: 0.4rem; margin-top: 0.2rem; }
	.check-label {
		display: flex; align-items: center; gap: 0.35rem;
		padding: 0.35rem 0.7rem; border: 1.5px solid var(--c-border);
		border-radius: 20px; font-size: 0.82rem; cursor: pointer;
	}
	.check-label.active { border-color: var(--c-primary); background: var(--c-primary-light); color: var(--c-primary); }
	.check-label input { display: none; }
	.error { color: var(--c-error); font-size: 0.875rem; margin-bottom: 0.75rem; }
	.actions { display: flex; gap: 0.75rem; margin-top: 0.5rem; }
	.btn-primary {
		flex: 1; padding: 0.75rem; background: var(--c-primary); color: var(--c-bg-card);
		border: none; border-radius: 8px; font-size: 1rem; font-weight: 600;
		cursor: pointer; transition: background 0.15s;
	}
	.btn-primary:hover:not(:disabled) { background: var(--c-primary-dark); }
	.btn-primary:disabled { opacity: 0.55; cursor: not-allowed; }
	.btn-ghost {
		padding: 0.75rem 1rem; background: none;
		border: 1.5px solid var(--c-border); border-radius: 8px;
		font-size: 1rem; color: var(--c-text-muted); cursor: pointer;
	}
	.dialog {
		background: var(--c-bg-card); border-radius: 16px; padding: 1.5rem;
		width: 100%; max-width: 400px;
	}
	.dialog p { font-size: 1rem; color: var(--c-text); margin-bottom: 0.4rem; font-weight: 600; }
	.dialog-sub { font-weight: 400 !important; font-size: 0.875rem; color: var(--c-text-hint); }
	.radio-group { display: flex; flex-direction: column; gap: 0.5rem; margin: 0.75rem 0; }
	.radio-label { display: flex; align-items: center; gap: 0.5rem; font-size: 0.9rem; color: var(--c-text); cursor: pointer; }
	.dialog-actions { display: flex; gap: 0.75rem; margin-top: 1.25rem; }
	.toggle-label { display: flex; align-items: center; gap: 0.5rem; font-size: 0.9rem; color: var(--c-text-secondary); cursor: pointer; }
	.serie-vorschau { font-size: 0.82rem; color: var(--c-primary); margin: -0.4rem 0 0.5rem; }
	.btn-danger {
		flex: 1; padding: 0.75rem; background: var(--c-error); color: var(--c-bg-card);
		border: none; border-radius: 8px; font-size: 0.95rem; font-weight: 600; cursor: pointer;
	}
	.btn-danger:hover { background: var(--c-error-dark); }
</style>
