<script lang="ts">
	import { onMount } from 'svelte';
	import type { ViewerData, ViewerPost } from '$lib/types';

	let data = $state<ViewerData | null>(null);
	let loading = $state(true);
	let error = $state('');

	// View mode
	let viewMode = $state<'list' | 'grid'>('list');

	// Grid search / filter state
	let searchQuery = $state('');
	let showAutocomplete = $state(false);

	interface Filter {
		type: 'tag' | 'user';
		value: string;
	}
	let activeFilters = $state<Filter[]>([]);

	// Lightbox state
	let selectedPost = $state<ViewerPost | null>(null);
	let lightboxIndex = $state(0);
	let touchStartX = 0;

	// List view hashtag filter
	let selectedHashtag = $state<string | null>(null);

	// ── Derived data ────────────────────────────────────────────────────────────

	let posts = $derived(data?.posts ?? []);

	// Mirror the live COMMENTS_ENABLED flag. Missing on older exports → treat as enabled.
	let commentsEnabled = $derived(data?.event.comments_enabled ?? true);

	let allTags = $derived.by(() => {
		// eslint-disable-next-line svelte/prefer-svelte-reactivity -- local throwaway counter inside a $derived.by; never stored in $state.
		const freq = new Map<string, number>();
		for (const p of posts) {
			for (const t of p.tags) {
				const lower = t.toLowerCase();
				freq.set(lower, (freq.get(lower) ?? 0) + 1);
			}
		}
		return [...freq.entries()].sort((a, b) => b[1] - a[1]);
	});

	let allUploaders = $derived([...new Set(posts.map((p) => p.uploader))].sort());

	let suggestions = $derived.by((): Filter[] => {
		const q = searchQuery.trim();
		if (!q) {
			if (!showAutocomplete) return [];
			return [
				...allUploaders.slice(0, 3).map((u) => ({ type: 'user' as const, value: u })),
				...allTags.slice(0, 3).map(([t]) => ({ type: 'tag' as const, value: t }))
			];
		}
		// Once the user has TYPED, every match is offered — no `.slice()`. Capping matters
		// more here than in the live app, for two reasons: this viewer holds the WHOLE event
		// (the export queries are uncapped), so the tag set is far larger than any one feed
		// page; and the keepsake is a frozen artifact — a guest opening it years later has no
		// server to re-query and no "scroll to load more" escape hatch. A silently dropped
		// match would simply be unreachable forever. The dropdown scrolls instead.
		if (q.startsWith('#')) {
			const prefix = q.slice(1).toLowerCase();
			return allTags
				.filter(([t]) => t.startsWith(prefix))
				.map(([t]) => ({ type: 'tag' as const, value: t }));
		}
		const lower = q.toLowerCase();
		return [
			...allUploaders
				.filter((u) => u.toLowerCase().includes(lower))
				.map((u) => ({ type: 'user' as const, value: u })),
			...allTags
				.filter(([t]) => t.includes(lower))
				.map(([t]) => ({ type: 'tag' as const, value: t }))
		];
	});

	// List view: filter by selected hashtag
	let listPosts = $derived.by(() => {
		if (!selectedHashtag) return posts;
		return posts.filter((p) => p.tags.some((t) => t.toLowerCase() === selectedHashtag));
	});

	// Grid view: filter by active filters (OR within type, AND across types)
	let filteredPosts = $derived.by(() => {
		if (activeFilters.length === 0) return posts;
		const tags = activeFilters.filter((f) => f.type === 'tag').map((f) => f.value);
		const users = activeFilters.filter((f) => f.type === 'user').map((f) => f.value);
		return posts.filter((p) => {
			const postTags = p.tags.map((t) => t.toLowerCase());
			const passTag = !tags.length || tags.some((t) => postTags.includes(t));
			const passUser = !users.length || users.includes(p.uploader);
			return passTag && passUser;
		});
	});

	let displayPosts = $derived(viewMode === 'list' ? listPosts : filteredPosts);

	// ── Data loading ────────────────────────────────────────────────────────────

	onMount(async () => {
		try {
			// The keepsake is opened by double-clicking index.html (file://), where a
			// cross-origin `fetch()` is blocked. The export injects the data as a global
			// so it's available without any network request; fall back to fetching
			// data.json only when the viewer is actually served over http(s).
			const injected = (globalThis as { __EXPORT_DATA__?: ViewerData }).__EXPORT_DATA__;
			if (injected) {
				data = injected;
			} else {
				const res = await fetch('./data.json');
				if (!res.ok) throw new Error(`HTTP ${res.status}`);
				data = await res.json();
			}
		} catch {
			error =
				'Daten konnten nicht geladen werden. Stelle sicher, dass data.json im selben Ordner liegt.';
		} finally {
			loading = false;
		}
	});

	// ── Helpers ──────────────────────────────────────────────────────────────────

	function formatDate(iso: string): string {
		const d = new Date(iso);
		return d.toLocaleString('de-DE', {
			day: '2-digit',
			month: '2-digit',
			year: 'numeric',
			hour: '2-digit',
			minute: '2-digit'
		});
	}

	function formatShortDate(iso: string): string {
		return new Date(iso).toLocaleString('de-DE', {
			day: '2-digit',
			month: '2-digit',
			hour: '2-digit',
			minute: '2-digit'
		});
	}

	function initial(name: string): string {
		return name[0]?.toUpperCase() ?? '?';
	}

	const COLORS = [
		'bg-blue-100 text-blue-700',
		'bg-purple-100 text-purple-700',
		'bg-green-100 text-green-700',
		'bg-amber-100 text-amber-700',
		'bg-rose-100 text-rose-700',
		'bg-teal-100 text-teal-700'
	];
	function avatarColor(name: string): string {
		let hash = 0;
		for (const ch of name) hash = (hash * 31 + ch.charCodeAt(0)) & 0xff;
		return COLORS[hash % COLORS.length];
	}

	// ── View switching ──────────────────────────────────────────────────────────

	function switchView(mode: 'list' | 'grid') {
		viewMode = mode;
		if (mode === 'list') {
			searchQuery = '';
			showAutocomplete = false;
		}
	}

	// ── Search / filter ─────────────────────────────────────────────────────────

	function selectSuggestion(item: Filter) {
		if (!activeFilters.some((f) => f.type === item.type && f.value === item.value)) {
			activeFilters = [...activeFilters, item];
		}
		searchQuery = '';
		showAutocomplete = false;
	}

	function removeFilter(item: Filter) {
		activeFilters = activeFilters.filter((f) => !(f.type === item.type && f.value === item.value));
	}

	function clearFilters() {
		activeFilters = [];
		searchQuery = '';
	}

	function selectHashtag(tag: string | null) {
		selectedHashtag = tag;
	}

	// ── Lightbox ────────────────────────────────────────────────────────────────

	function openLightbox(post: ViewerPost) {
		const idx = displayPosts.indexOf(post);
		lightboxIndex = idx >= 0 ? idx : 0;
		selectedPost = post;
	}

	function closeLightbox() {
		selectedPost = null;
	}

	function navigateLightbox(delta: number) {
		const len = displayPosts.length;
		if (len === 0) return;
		lightboxIndex = (lightboxIndex + delta + len) % len;
		selectedPost = displayPosts[lightboxIndex];
	}

	function handleKeydown(e: KeyboardEvent) {
		if (!selectedPost) return;
		if (e.key === 'Escape') closeLightbox();
		else if (e.key === 'ArrowLeft') navigateLightbox(-1);
		else if (e.key === 'ArrowRight') navigateLightbox(1);
	}

	function handleTouchStart(e: TouchEvent) {
		touchStartX = e.touches[0].clientX;
	}

	function handleTouchEnd(e: TouchEvent) {
		const diff = e.changedTouches[0].clientX - touchStartX;
		if (Math.abs(diff) > 50) {
			navigateLightbox(diff > 0 ? -1 : 1);
		}
	}
</script>

<svelte:window onkeydown={handleKeydown} />

{#if loading}
	<div class="flex min-h-screen items-center justify-center bg-gray-50">
		<div
			class="inline-block h-8 w-8 animate-spin rounded-full border-2 border-gray-300 border-t-blue-600"
		></div>
	</div>
{:else if error}
	<div class="flex min-h-screen items-center justify-center bg-gray-50 p-4">
		<div class="rounded-xl border border-red-200 bg-red-50 p-6 text-center">
			<p class="text-sm text-red-700">{error}</p>
		</div>
	</div>
{:else if data}
	<div class="min-h-screen bg-gray-50 pb-8">
		<!-- Sticky header -->
		<div class="sticky top-0 z-30 border-b border-gray-200 bg-white/95 backdrop-blur">
			<div class="mx-auto flex max-w-2xl items-center justify-between px-4 py-3">
				<h1 class="text-lg font-bold text-gray-900">{data.event.name}</h1>

				<!-- List / Grid toggle -->
				<div class="flex items-center gap-1 rounded-lg bg-gray-100 p-1">
					<button
						onclick={() => switchView('list')}
						class="rounded-md p-1.5 transition-colors {viewMode === 'list'
							? 'bg-white text-gray-900 shadow-sm'
							: 'text-gray-400 hover:text-gray-600'}"
						aria-label="Listenansicht"
					>
						<svg
							class="h-5 w-5"
							fill="none"
							viewBox="0 0 24 24"
							stroke="currentColor"
							stroke-width="1.5"
						>
							<path
								stroke-linecap="round"
								stroke-linejoin="round"
								d="M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25h16.5"
							/>
						</svg>
					</button>
					<button
						onclick={() => switchView('grid')}
						class="rounded-md p-1.5 transition-colors {viewMode === 'grid'
							? 'bg-white text-gray-900 shadow-sm'
							: 'text-gray-400 hover:text-gray-600'}"
						aria-label="Rasteransicht"
					>
						<svg
							class="h-5 w-5"
							fill="none"
							viewBox="0 0 24 24"
							stroke="currentColor"
							stroke-width="1.5"
						>
							<path
								stroke-linecap="round"
								stroke-linejoin="round"
								d="M3.75 6A2.25 2.25 0 0 1 6 3.75h2.25A2.25 2.25 0 0 1 10.5 6v2.25a2.25 2.25 0 0 1-2.25 2.25H6a2.25 2.25 0 0 1-2.25-2.25V6ZM3.75 15.75A2.25 2.25 0 0 1 6 13.5h2.25a2.25 2.25 0 0 1 2.25 2.25V18a2.25 2.25 0 0 1-2.25 2.25H6A2.25 2.25 0 0 1 3.75 18v-2.25ZM13.5 6a2.25 2.25 0 0 1 2.25-2.25H18A2.25 2.25 0 0 1 20.25 6v2.25A2.25 2.25 0 0 1 18 10.5h-2.25a2.25 2.25 0 0 1-2.25-2.25V6ZM13.5 15.75a2.25 2.25 0 0 1 2.25-2.25H18a2.25 2.25 0 0 1 2.25 2.25V18A2.25 2.25 0 0 1 18 20.25h-2.25A2.25 2.25 0 0 1 13.5 18v-2.25Z"
							/>
						</svg>
					</button>
				</div>
			</div>

			<!-- List view: hashtag chips -->
			{#if viewMode === 'list' && allTags.length > 0}
				<div class="mx-auto max-w-2xl px-4 pb-2">
					<div class="flex gap-2 overflow-x-auto pb-2">
						<button
							onclick={() => selectHashtag(null)}
							class="shrink-0 rounded-full px-3 py-1 text-sm font-medium transition {selectedHashtag ===
							null
								? 'bg-blue-600 text-white'
								: 'bg-gray-200 text-gray-700 hover:bg-gray-300'}"
						>
							Alle
						</button>
						{#each allTags as [tag, count] (tag)}
							<button
								onclick={() => selectHashtag(tag)}
								class="shrink-0 rounded-full px-3 py-1 text-sm font-medium transition {selectedHashtag ===
								tag
									? 'bg-blue-600 text-white'
									: 'bg-gray-200 text-gray-700 hover:bg-gray-300'}"
							>
								#{tag}
								<span class="ml-1 text-xs opacity-70">{count}</span>
							</button>
						{/each}
					</div>
				</div>
			{/if}

			<!-- Grid view: search bar + autocomplete -->
			{#if viewMode === 'grid'}
				<div class="mx-auto max-w-2xl px-4 pb-3">
					<div class="relative">
						<div
							class="flex items-center gap-2 rounded-xl border border-gray-200 bg-gray-50 px-3 py-2 focus-within:border-blue-400 focus-within:bg-white focus-within:ring-1 focus-within:ring-blue-200"
						>
							<svg
								class="h-4 w-4 shrink-0 text-gray-400"
								fill="none"
								viewBox="0 0 24 24"
								stroke="currentColor"
								stroke-width="2"
							>
								<path
									stroke-linecap="round"
									stroke-linejoin="round"
									d="M21 21l-5.197-5.197m0 0A7.5 7.5 0 1 0 5.196 5.196a7.5 7.5 0 0 0 10.607 10.607Z"
								/>
							</svg>
							<input
								type="search"
								placeholder="Nutzer oder #Tag suchen..."
								bind:value={searchQuery}
								onfocus={() => (showAutocomplete = true)}
								onblur={() => setTimeout(() => (showAutocomplete = false), 150)}
								class="min-w-0 flex-1 bg-transparent text-sm text-gray-900 placeholder-gray-400 outline-none"
							/>
							{#if searchQuery}
								<button
									onclick={() => {
										searchQuery = '';
									}}
									class="shrink-0 text-gray-400 hover:text-gray-600"
									aria-label="Suche loschen"
								>
									<svg
										class="h-4 w-4"
										fill="none"
										viewBox="0 0 24 24"
										stroke="currentColor"
										stroke-width="2"
									>
										<path stroke-linecap="round" stroke-linejoin="round" d="M6 18 18 6M6 6l12 12" />
									</svg>
								</button>
							{/if}
						</div>

						<!-- Autocomplete dropdown -->
						{#if showAutocomplete && suggestions.length > 0}
							<!-- `preventDefault` on mousedown suppresses the input's blur, which would
							     otherwise close this dropdown (see the input's `onblur`) before a click
							     could land. That is what lets the commit live on `onclick` — the LAST
							     event — instead of `onmousedown`. Committing on press meant sliding off
							     a suggestion you didn't mean to hit still applied the filter, and
							     `selectSuggestion` sets `showAutocomplete = false`, so the button
							     destroyed itself on the first event of the click sequence. Ported from
							     the live feed page, which fixed this; the viewer never got it. -->
							<div
								class="absolute left-0 right-0 top-full z-50 mt-1 max-h-72 overflow-y-auto overscroll-contain rounded-xl border border-gray-200 bg-white shadow-lg"
								onmousedown={(e) => e.preventDefault()}
								role="listbox"
								tabindex="-1"
							>
								{#each suggestions as item (item.type + ':' + item.value)}
									<button
										class="flex w-full items-center gap-3 px-4 py-2.5 text-left text-sm hover:bg-gray-50"
										onclick={() => selectSuggestion(item)}
									>
										{#if item.type === 'user'}
											<svg
												class="h-4 w-4 shrink-0 text-gray-400"
												fill="none"
												viewBox="0 0 24 24"
												stroke="currentColor"
												stroke-width="1.5"
											>
												<path
													stroke-linecap="round"
													stroke-linejoin="round"
													d="M15.75 6a3.75 3.75 0 1 1-7.5 0 3.75 3.75 0 0 1 7.5 0ZM4.501 20.118a7.5 7.5 0 0 1 14.998 0A17.933 17.933 0 0 1 12 21.75c-2.676 0-5.216-.584-7.499-1.632Z"
												/>
											</svg>
											<span class="font-medium text-gray-900">{item.value}</span>
										{:else}
											<span class="font-medium text-blue-500">#</span>
											<span class="font-medium text-gray-900">{item.value}</span>
										{/if}
									</button>
								{/each}
							</div>
						{/if}
					</div>

					<!-- Active filter chips -->
					{#if activeFilters.length > 0}
						<div class="mt-2 flex flex-wrap items-center gap-1.5">
							{#each activeFilters as filter (filter.type + ':' + filter.value)}
								<span
									class="flex items-center gap-1 rounded-full bg-blue-100 px-2.5 py-0.5 text-xs font-medium text-blue-700"
								>
									{filter.type === 'tag' ? '#' : ''}{filter.value}
									<button
										onclick={() => removeFilter(filter)}
										class="ml-0.5 hover:text-blue-900"
										aria-label="Filter entfernen"
									>
										<svg
											class="h-3 w-3"
											fill="none"
											viewBox="0 0 24 24"
											stroke="currentColor"
											stroke-width="2.5"
										>
											<path
												stroke-linecap="round"
												stroke-linejoin="round"
												d="M6 18 18 6M6 6l12 12"
											/>
										</svg>
									</button>
								</span>
							{/each}
							{#if activeFilters.length >= 2}
								<button onclick={clearFilters} class="text-xs text-gray-400 hover:text-gray-600">
									Alle loschen
								</button>
							{/if}
						</div>
					{/if}
				</div>
			{/if}
		</div>

		<!-- Content -->
		{#if displayPosts.length === 0}
			<div class="py-20 text-center">
				<p class="text-lg text-gray-400">Noch keine Fotos.</p>
				{#if activeFilters.length > 0}
					<button onclick={clearFilters} class="mt-2 text-sm text-blue-600 hover:underline"
						>Filter zurucksetzen</button
					>
				{/if}
			</div>
		{:else if viewMode === 'list'}
			<!-- List view: chronological full-width cards -->
			<div class="mx-auto max-w-2xl">
				{#each displayPosts as post (post.id)}
					<article class="bg-white">
						<!-- Uploader row -->
						<div class="flex items-center gap-3 px-4 py-3">
							<div
								class="flex h-9 w-9 shrink-0 items-center justify-center rounded-full text-sm font-bold
									{avatarColor(post.uploader)}"
							>
								{initial(post.uploader)}
							</div>
							<div class="min-w-0">
								<p class="truncate text-sm font-semibold text-gray-900">{post.uploader}</p>
								<p class="text-xs text-gray-400">{formatDate(post.timestamp)}</p>
							</div>
						</div>

						<!-- Media -->
						<button
							class="block w-full"
							onclick={() => openLightbox(post)}
							aria-label="Bild vergrößern"
						>
							{#if post.media.type === 'video'}
								<div class="relative aspect-video w-full bg-gray-900">
									{#if post.media.thumb}
										<img
											src={post.media.thumb}
											alt=""
											class="h-full w-full object-cover opacity-80"
										/>
									{/if}
									<div class="absolute inset-0 flex items-center justify-center">
										<span
											class="flex h-14 w-14 items-center justify-center rounded-full bg-black/50 text-white"
										>
											<svg class="h-7 w-7 pl-0.5" fill="currentColor" viewBox="0 0 24 24">
												<path d="M8 5v14l11-7z" />
											</svg>
										</span>
									</div>
								</div>
							{:else if post.media.full}
								<img
									src={post.media.full}
									alt=""
									class="w-full object-cover"
									style="max-height: 80svh"
									loading="lazy"
								/>
							{:else}
								<div class="flex aspect-square w-full items-center justify-center bg-gray-100">
									<svg
										class="h-12 w-12 text-gray-300"
										fill="none"
										viewBox="0 0 24 24"
										stroke="currentColor"
									>
										<path
											stroke-linecap="round"
											stroke-linejoin="round"
											stroke-width="1.5"
											d="M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z"
										/>
									</svg>
								</div>
							{/if}
						</button>

						<!-- Stats row (read-only) -->
						<div class="flex items-center gap-4 px-4 py-2">
							<span class="flex items-center gap-1.5 text-sm font-medium text-gray-500">
								<svg
									class="h-5 w-5"
									fill="none"
									viewBox="0 0 24 24"
									stroke="currentColor"
									stroke-width="2"
								>
									<path
										stroke-linecap="round"
										stroke-linejoin="round"
										d="M4.318 6.318a4.5 4.5 0 000 6.364L12 20.364l7.682-7.682a4.5 4.5 0 00-6.364-6.364L12 7.636l-1.318-1.318a4.5 4.5 0 00-6.364 0z"
									/>
								</svg>
								{post.likes}
							</span>
							{#if commentsEnabled}
								<span class="flex items-center gap-1.5 text-sm font-medium text-gray-500">
									<svg
										class="h-5 w-5"
										fill="none"
										viewBox="0 0 24 24"
										stroke="currentColor"
										stroke-width="2"
									>
										<path
											stroke-linecap="round"
											stroke-linejoin="round"
											d="M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z"
										/>
									</svg>
									{post.comments.length}
								</span>
							{/if}
						</div>

						<!-- Caption -->
						{#if post.caption}
							<p class="px-4 pb-3 text-sm text-gray-800 [overflow-wrap:anywhere]">
								{post.caption}
							</p>
						{/if}

						<div class="border-b border-gray-100"></div>
					</article>
				{/each}
			</div>
		{:else}
			<!-- Grid view: 3-col -->
			<div class="mx-auto max-w-2xl">
				<div class="grid grid-cols-3 gap-0.5">
					{#each displayPosts as post (post.id)}
						<div
							class="group relative aspect-square cursor-pointer overflow-hidden rounded-lg bg-gray-100"
						>
							<button
								onclick={() => openLightbox(post)}
								class="block h-full w-full"
								aria-label="Upload anzeigen"
							>
								{#if post.media.type === 'video'}
									<div class="flex h-full items-center justify-center bg-gray-800">
										{#if post.media.thumb}
											<img src={post.media.thumb} alt="" class="h-full w-full object-cover" />
										{/if}
										<div class="absolute inset-0 flex items-center justify-center">
											<svg class="h-10 w-10 text-white/80" fill="currentColor" viewBox="0 0 24 24">
												<path d="M8 5v14l11-7z" />
											</svg>
										</div>
									</div>
								{:else if post.media.thumb}
									<img
										src={post.media.thumb}
										alt=""
										class="h-full w-full object-cover"
										loading="lazy"
									/>
								{:else}
									<div class="flex h-full items-center justify-center text-gray-400">
										<svg class="h-8 w-8" fill="none" viewBox="0 0 24 24" stroke="currentColor">
											<path
												stroke-linecap="round"
												stroke-linejoin="round"
												stroke-width="1.5"
												d="M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z"
											/>
										</svg>
									</div>
								{/if}
							</button>

							<!-- Overlay with name and stats -->
							<div
								class="pointer-events-none absolute inset-x-0 bottom-0 bg-gradient-to-t from-black/60 to-transparent p-2"
							>
								<p class="truncate text-xs font-medium text-white">{post.uploader}</p>
								<div class="mt-0.5 flex items-center gap-3 text-xs text-white/80">
									<span class="flex items-center gap-0.5">
										<svg class="h-3.5 w-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
											<path
												stroke-linecap="round"
												stroke-linejoin="round"
												stroke-width="2"
												d="M4.318 6.318a4.5 4.5 0 000 6.364L12 20.364l7.682-7.682a4.5 4.5 0 00-6.364-6.364L12 7.636l-1.318-1.318a4.5 4.5 0 00-6.364 0z"
											/>
										</svg>
										{post.likes}
									</span>
									{#if commentsEnabled}
										<span class="flex items-center gap-0.5">
											<svg
												class="h-3.5 w-3.5"
												fill="none"
												viewBox="0 0 24 24"
												stroke="currentColor"
											>
												<path
													stroke-linecap="round"
													stroke-linejoin="round"
													stroke-width="2"
													d="M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z"
												/>
											</svg>
											{post.comments.length}
										</span>
									{/if}
								</div>
							</div>
						</div>
					{/each}
				</div>
			</div>
		{/if}

		<!-- Footer -->
		<footer class="mt-8 border-t border-gray-200 py-6 text-center text-xs text-gray-400">
			<p>{data.event.name} &middot; Offline-Galerie &middot; EventSnap</p>
			<p class="mt-1">Exportiert am {formatDate(data.event.exported_at)}</p>
		</footer>
	</div>

	<!-- Lightbox -->
	{#if selectedPost}
		<div
			class="fixed inset-0 z-50 flex items-center justify-center bg-black/80"
			role="dialog"
			tabindex="-1"
			onclick={(e) => {
				if (e.target === e.currentTarget) closeLightbox();
			}}
			ontouchstart={handleTouchStart}
			ontouchend={handleTouchEnd}
		>
			<div
				class="flex max-h-[95vh] w-full max-w-2xl flex-col overflow-hidden rounded-xl bg-white sm:m-4"
			>
				<!-- Media -->
				<div class="relative bg-black">
					<button
						onclick={closeLightbox}
						class="absolute right-2 top-2 z-10 rounded-full bg-black/50 p-1.5 text-white hover:bg-black/70"
					>
						<svg class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
							<path
								stroke-linecap="round"
								stroke-linejoin="round"
								stroke-width="2"
								d="M6 18L18 6M6 6l12 12"
							/>
						</svg>
					</button>

					<!-- Nav arrows -->
					{#if displayPosts.length > 1}
						<button
							onclick={() => navigateLightbox(-1)}
							class="absolute left-2 top-1/2 z-10 -translate-y-1/2 rounded-full bg-black/50 p-1.5 text-white hover:bg-black/70"
							aria-label="Vorheriges"
						>
							<svg
								class="h-5 w-5"
								fill="none"
								viewBox="0 0 24 24"
								stroke="currentColor"
								stroke-width="2"
							>
								<path
									stroke-linecap="round"
									stroke-linejoin="round"
									d="M15.75 19.5 8.25 12l7.5-7.5"
								/>
							</svg>
						</button>
						<button
							onclick={() => navigateLightbox(1)}
							class="absolute right-2 top-1/2 z-10 -translate-y-1/2 rounded-full bg-black/50 p-1.5 text-white hover:bg-black/70"
							aria-label="Nachstes"
						>
							<svg
								class="h-5 w-5"
								fill="none"
								viewBox="0 0 24 24"
								stroke="currentColor"
								stroke-width="2"
							>
								<path
									stroke-linecap="round"
									stroke-linejoin="round"
									d="m8.25 4.5 7.5 7.5-7.5 7.5"
								/>
							</svg>
						</button>
					{/if}

					{#if selectedPost.media.type === 'video'}
						<video
							src={selectedPost.media.full}
							controls
							class="max-h-[50vh] w-full object-contain"
							poster={selectedPost.media.thumb || undefined}
						></video>
					{:else}
						<img src={selectedPost.media.full} alt="" class="max-h-[50vh] w-full object-contain" />
					{/if}
				</div>

				<!-- Info + Comments -->
				<div class="flex flex-1 flex-col overflow-hidden">
					<div class="border-b border-gray-100 p-3">
						<div class="flex items-center justify-between">
							<div>
								<span class="font-medium text-gray-900">{selectedPost.uploader}</span>
								<span class="ml-2 text-xs text-gray-400"
									>{formatShortDate(selectedPost.timestamp)}</span
								>
							</div>
							<span
								class="flex items-center gap-1 rounded-full bg-gray-100 px-2.5 py-1 text-sm text-gray-600"
							>
								<svg class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
									<path
										stroke-linecap="round"
										stroke-linejoin="round"
										stroke-width="2"
										d="M4.318 6.318a4.5 4.5 0 000 6.364L12 20.364l7.682-7.682a4.5 4.5 0 00-6.364-6.364L12 7.636l-1.318-1.318a4.5 4.5 0 00-6.364 0z"
									/>
								</svg>
								{selectedPost.likes}
							</span>
						</div>
						{#if selectedPost.caption}
							<p class="mt-1 text-sm text-gray-700 [overflow-wrap:anywhere]">
								{selectedPost.caption}
							</p>
						{/if}
					</div>

					<!-- Comments list -->
					{#if commentsEnabled}
						<div class="flex-1 overflow-y-auto p-3">
							{#if selectedPost.comments.length === 0}
								<p class="text-center text-sm text-gray-400">Keine Kommentare.</p>
							{:else}
								<div class="space-y-3">
									{#each selectedPost.comments as comment, i (i)}
										<div>
											<span class="text-sm font-medium text-gray-900">{comment.author}</span>
											<span class="ml-1 text-sm text-gray-700">{comment.text}</span>
											<div class="mt-0.5 text-xs text-gray-400">
												{formatShortDate(comment.timestamp)}
											</div>
										</div>
									{/each}
								</div>
							{/if}
						</div>
					{/if}
				</div>
			</div>
		</div>
	{/if}
{/if}
