<script lang="ts">
	import '../app.css';
	import { page, navigating } from '$app/state';
	import { goto } from '$app/navigation';
	import type { Snippet } from 'svelte';
	import type { LayoutData } from './$types';
	import { audioStore } from '$lib/audio.svelte';
	import { env } from '$env/dynamic/public';
	import { Button } from '$lib/components/ui/button';
	import { cn } from '$lib/utils';

	let { children, data }: { children: Snippet; data: LayoutData } = $props();

	// Mobile nav drawer state
	let menuOpen = $state(false);

	// Chapter list drawer state for the mini-player
	let chapterDrawerOpen = $state(false);

	// The single <audio> element that persists across navigations.
	// AudioPlayer components in chapter pages control it via audioStore.
	let audioEl = $state<HTMLAudioElement | null>(null);

	// Apply persisted settings once on mount (server-loaded data).
	let settingsApplied = false;
	$effect(() => {
		if (!settingsApplied && data.settings) {
			settingsApplied = true;
			audioStore.autoNext = data.settings.autoNext;
			audioStore.voice = data.settings.voice;
			audioStore.speed = data.settings.speed;
		}
	});

	// ── Persist settings changes (debounced 800ms) ──────────────────────────
	let settingsSaveTimer = 0;
	$effect(() => {
		// Subscribe to the three settings fields
		const autoNext = audioStore.autoNext;
		const voice = audioStore.voice;
		const speed = audioStore.speed;

		// Skip saving until settings have been applied from the server
		if (!settingsApplied) return;

		clearTimeout(settingsSaveTimer);
		settingsSaveTimer = setTimeout(() => {
			fetch('/api/settings', {
				method: 'PUT',
				headers: { 'Content-Type': 'application/json' },
				body: JSON.stringify({ autoNext, voice, speed })
			}).catch(() => {});
		}, 800) as unknown as number;
	});

	// Keep the audio element's playback rate in sync with the store speed.
	$effect(() => {
		if (audioEl) audioEl.playbackRate = audioStore.speed;
	});

	// When audioUrl changes, load the new source.
	// Use a local variable to track which URL is currently loaded so we never
	// compare against audioEl.src (browsers normalise it, causing false mismatches).
	let loadedUrl = '';
	$effect(() => {
		if (!audioEl) return;
		const url = audioStore.audioUrl;
		if (url && url !== loadedUrl) {
			loadedUrl = url;
			audioEl.src = url;
			audioEl.load();
			audioEl.playbackRate = audioStore.speed;
			audioEl.play().catch(() => {});
		} else if (!url) {
			loadedUrl = '';
		}
	});

	// Handle toggle requests from AudioPlayer controller.
	$effect(() => {
		// Read toggleRequest to subscribe; ignore value 0 (initial).
		const _req = audioStore.toggleRequest;
		if (!audioEl || _req === 0) return;
		if (audioStore.isPlaying) {
			audioEl.pause();
		} else {
			audioEl.play().catch(() => {});
		}
	});

	// Handle seek requests from AudioPlayer controller.
	$effect(() => {
		const t = audioStore.seekRequest;
		if (!audioEl || t === null) return;
		audioEl.currentTime = t;
		audioStore.seekRequest = null;
	});

	// ── Save audio time on pause/end (debounced 2s) ─────────────────────────
	let audioTimeSaveTimer = 0;
	function saveAudioTime() {
		if (!audioStore.slug || !audioStore.chapter) return;
		const slug = audioStore.slug;
		const chapter = audioStore.chapter;
		const currentTime = audioStore.currentTime;
		clearTimeout(audioTimeSaveTimer);
		audioTimeSaveTimer = setTimeout(() => {
			fetch('/api/progress/audio-time', {
				method: 'PATCH',
				headers: { 'Content-Type': 'application/json' },
				body: JSON.stringify({ slug, chapter, audioTime: currentTime })
			}).catch(() => {});
		}, 2000) as unknown as number;
	}

	function formatTime(s: number): string {
		if (!isFinite(s) || s < 0) return '0:00';
		const m = Math.floor(s / 60);
		const sec = Math.floor(s % 60);
		return `${m}:${sec.toString().padStart(2, '0')}`;
	}

	function togglePlay() {
		if (!audioEl) return;
		if (audioStore.isPlaying) {
			audioEl.pause();
		} else {
			audioEl.play().catch(() => {});
		}
	}

	function seek(e: Event) {
		if (!audioEl) return;
		audioEl.currentTime = parseFloat((e.target as HTMLInputElement).value);
	}

	function skipBack() {
		if (!audioEl) return;
		audioEl.currentTime = Math.max(0, audioEl.currentTime - 15);
	}

	function skipForward() {
		if (!audioEl) return;
		audioEl.currentTime = Math.min(audioEl.duration || 0, audioEl.currentTime + 30);
	}

	const speedSteps = [0.5, 0.75, 1.0, 1.25, 1.5, 1.75, 2.0];

	function cycleSpeed() {
		const idx = speedSteps.indexOf(audioStore.speed);
		audioStore.speed = speedSteps[(idx + 1) % speedSteps.length];
	}

	function dismiss() {
		if (audioEl) {
			audioEl.pause();
			audioEl.src = '';
		}
		audioStore.status = 'idle';
		audioStore.audioUrl = '';
		audioStore.slug = '';
		audioStore.chapter = 0;
		audioStore.isPlaying = false;
		audioStore.currentTime = 0;
		audioStore.duration = 0;
	}
</script>

<svelte:head>
	<meta charset="utf-8" />
	<meta name="viewport" content="width=device-width, initial-scale=1" />
	<title>libnovel</title>
	<!-- Umami analytics — no-op when PUBLIC_UMAMI_WEBSITE_ID is unset -->
	{#if env.PUBLIC_UMAMI_WEBSITE_ID && env.PUBLIC_UMAMI_SCRIPT_URL}
		<script
			defer
			src={env.PUBLIC_UMAMI_SCRIPT_URL}
			data-website-id={env.PUBLIC_UMAMI_WEBSITE_ID}
		></script>
	{/if}
</svelte:head>

<!-- Persistent audio element — always in the DOM, never conditionally unmounted.
     Conditional rendering ({#if}) would destroy/recreate it when reactive state
     changes (e.g. currentTime ticking), triggering onpause and restarting audio. -->
<audio
	bind:this={audioEl}
	bind:currentTime={audioStore.currentTime}
	bind:duration={audioStore.duration}
	onplay={() => (audioStore.isPlaying = true)}
	onpause={() => {
		audioStore.isPlaying = false;
		saveAudioTime();
	}}
	onended={() => {
		audioStore.isPlaying = false;
		saveAudioTime();
		if (audioStore.autoNext && audioStore.nextChapter !== null && audioStore.slug) {
			// Capture values synchronously before any async work — the AudioPlayer
			// component will unmount during navigation, but we've already read what
			// we need.
			const targetSlug = audioStore.slug;
			const targetChapter = audioStore.nextChapter;
			// Store the target chapter number so only the newly-mounted AudioPlayer
			// for that chapter reacts — not the outgoing chapter's component.
			audioStore.autoStartChapter = targetChapter;
			goto(`/books/${targetSlug}/chapters/${targetChapter}`).catch(() => {
				audioStore.autoStartChapter = null;
			});
		}
	}}
	preload="metadata"
	style="display:none"
></audio>

<div class="min-h-screen flex flex-col" class:pb-24={audioStore.active}>
	<!-- Navigation progress bar — shown while SSR is running for any page transition -->
	{#if navigating}
		<div class="fixed top-0 left-0 right-0 z-[100] h-1 bg-zinc-800">
			<div class="h-full bg-amber-400 animate-progress-bar"></div>
		</div>
	{/if}
	<header class="border-b border-zinc-700 bg-zinc-900 sticky top-0 z-50">
		<nav class="max-w-6xl mx-auto px-4 h-14 flex items-center gap-6">
			<a href="/" class="text-amber-400 font-bold text-lg tracking-tight hover:text-amber-300 shrink-0">
				libnovel
			</a>

			{#if page.data.book?.title && /\/books\/[^/]+\/chapters\//.test(page.url.pathname)}
				<span class="text-zinc-400 text-sm truncate min-w-0 flex-1 sm:flex-none sm:max-w-xs">
					{page.data.book.title}
				</span>
			{/if}

			{#if data.user}
				<!-- Desktop nav links (hidden on mobile) -->
				<a
					href="/books"
					class="hidden sm:block text-sm transition-colors {page.url.pathname.startsWith('/books') ? 'text-zinc-100 font-medium' : 'text-zinc-400 hover:text-zinc-100'}"
				>
					Library
				</a>
			<a
				href="/catalogue"
				class="hidden sm:block text-sm transition-colors {page.url.pathname.startsWith('/catalogue') ? 'text-zinc-100 font-medium' : 'text-zinc-400 hover:text-zinc-100'}"
			>
				Discover
			</a>
			<a
				href="https://feedback.libnovel.cc"
				target="_blank"
				rel="noopener noreferrer"
				class="hidden sm:block text-sm transition-colors text-zinc-400 hover:text-zinc-100"
			>
				Feedback
			</a>

				<div class="ml-auto flex items-center gap-4">
					<!-- Desktop: admin + profile + sign out (hidden on mobile) -->
					{#if data.user?.role === 'admin'}
						<a
							href="/admin/scrape"
							class="hidden sm:block text-sm transition-colors {page.url.pathname.startsWith('/admin/scrape') ? 'text-zinc-100 font-medium' : 'text-zinc-400 hover:text-zinc-100'}"
						>
							Scrape
						</a>
						<a
							href="/admin/audio"
							class="hidden sm:block text-sm transition-colors {page.url.pathname.startsWith('/admin/audio') ? 'text-zinc-100 font-medium' : 'text-zinc-400 hover:text-zinc-100'}"
						>
							Audio
						</a>
					{/if}
					<a
						href="/profile"
						class="hidden sm:block text-sm transition-colors {page.url.pathname === '/profile' ? 'text-zinc-100 font-medium' : 'text-zinc-400 hover:text-zinc-100'}"
					>
						{data.user.username}
					</a>
					<form method="POST" action="/logout" class="hidden sm:block">
						<Button type="submit" variant="ghost" size="sm" class="text-zinc-400 hover:text-zinc-100">
							Sign out
						</Button>
					</form>

					<!-- Mobile: hamburger button -->
					<Button
						variant="ghost"
						size="icon"
						onclick={() => (menuOpen = !menuOpen)}
						aria-label="Toggle menu"
						aria-expanded={menuOpen}
						class="sm:hidden -mr-1"
					>
						{#if menuOpen}
							<!-- X icon -->
							<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
								<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
							</svg>
						{:else}
							<!-- Hamburger icon -->
							<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
								<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16" />
							</svg>
						{/if}
					</Button>
				</div>
			{:else}
				<div class="ml-auto">
					<a
						href="/login"
						class="text-sm px-3 py-1.5 rounded bg-amber-400 text-zinc-900 font-semibold hover:bg-amber-300 transition-colors"
					>
						Sign in
					</a>
				</div>
			{/if}
		</nav>

		<!-- Mobile drawer (full-width, below the bar) -->
		{#if data.user && menuOpen}
			<div class="sm:hidden border-t border-zinc-700 bg-zinc-900 px-4 py-3 flex flex-col gap-1">
				<a
					href="/books"
					onclick={() => (menuOpen = false)}
					class="px-3 py-2.5 rounded-lg text-sm font-medium transition-colors {page.url.pathname.startsWith('/books') ? 'bg-zinc-800 text-zinc-100' : 'text-zinc-400 hover:bg-zinc-800 hover:text-zinc-100'}"
				>
					Library
				</a>
			<a
				href="/catalogue"
				onclick={() => (menuOpen = false)}
				class="px-3 py-2.5 rounded-lg text-sm font-medium transition-colors {page.url.pathname.startsWith('/catalogue') ? 'bg-zinc-800 text-zinc-100' : 'text-zinc-400 hover:bg-zinc-800 hover:text-zinc-100'}"
			>
				Discover
			</a>
			<a
				href="https://feedback.libnovel.cc"
				target="_blank"
				rel="noopener noreferrer"
				onclick={() => (menuOpen = false)}
				class="px-3 py-2.5 rounded-lg text-sm font-medium transition-colors text-zinc-400 hover:bg-zinc-800 hover:text-zinc-100"
			>
				Feedback ↗
			</a>
				<a
					href="/profile"
					onclick={() => (menuOpen = false)}
					class="px-3 py-2.5 rounded-lg text-sm font-medium transition-colors {page.url.pathname === '/profile' ? 'bg-zinc-800 text-zinc-100' : 'text-zinc-400 hover:bg-zinc-800 hover:text-zinc-100'}"
				>
					Profile <span class="text-zinc-500 font-normal">({data.user.username})</span>
				</a>
				{#if data.user?.role === 'admin'}
					<div class="my-1 border-t border-zinc-700/60"></div>
					<p class="px-3 pt-1 pb-0.5 text-xs text-zinc-600 uppercase tracking-widest">Admin</p>
					<a
						href="/admin/scrape"
						onclick={() => (menuOpen = false)}
						class="px-3 py-2.5 rounded-lg text-sm font-medium transition-colors {page.url.pathname.startsWith('/admin/scrape') ? 'bg-zinc-800 text-zinc-100' : 'text-zinc-400 hover:bg-zinc-800 hover:text-zinc-100'}"
					>
						Scrape tasks
					</a>
					<a
						href="/admin/audio"
						onclick={() => (menuOpen = false)}
						class="px-3 py-2.5 rounded-lg text-sm font-medium transition-colors {page.url.pathname === '/admin/audio' ? 'bg-zinc-800 text-zinc-100' : 'text-zinc-400 hover:bg-zinc-800 hover:text-zinc-100'}"
					>
						Audio cache
					</a>
					<a
						href="/admin/audio-jobs"
						onclick={() => (menuOpen = false)}
						class="px-3 py-2.5 rounded-lg text-sm font-medium transition-colors {page.url.pathname.startsWith('/admin/audio-jobs') ? 'bg-zinc-800 text-zinc-100' : 'text-zinc-400 hover:bg-zinc-800 hover:text-zinc-100'}"
					>
						Audio jobs
					</a>
				{/if}
			<div class="my-1 border-t border-zinc-700/60"></div>
			<form method="POST" action="/logout">
				<Button
					type="submit"
					variant="ghost"
					class="w-full justify-start px-3 py-2.5 h-auto text-sm font-medium text-red-400 hover:bg-zinc-800 hover:text-red-300"
				>
					Sign out
				</Button>
			</form>
			</div>
		{/if}
	</header>

	<main class="flex-1 max-w-6xl mx-auto w-full px-4 py-8">
		{#key page.url.pathname + page.url.search}
			{@render children()}
		{/key}
	</main>

	<footer class="border-t border-zinc-800 mt-auto">
		<div class="max-w-6xl mx-auto px-4 py-6 flex flex-col items-center gap-4 text-xs text-zinc-600">
			<!-- Top row: site links -->
			<nav class="flex flex-wrap items-center justify-center gap-x-5 gap-y-2">
			<a href="/books" class="hover:text-zinc-400 transition-colors">Library</a>
			<a href="/catalogue" class="hover:text-zinc-400 transition-colors">Discover</a>
			<a
				href="https://feedback.libnovel.cc"
				target="_blank"
				rel="noopener noreferrer"
				class="hover:text-zinc-400 transition-colors flex items-center gap-1"
			>
				Feedback
				<svg class="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
					<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
						d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14" />
				</svg>
			</a>
			<a
				href="https://novelfire.net"
					target="_blank"
					rel="noopener noreferrer"
					class="hover:text-zinc-400 transition-colors flex items-center gap-1"
				>
					novelfire.net
					<svg class="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
						<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
							d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14" />
					</svg>
				</a>
			</nav>
		<!-- Bottom row: legal links + copyright -->
		<div class="flex flex-wrap items-center justify-center gap-x-5 gap-y-2 text-zinc-700">
			<a href="/disclaimer" class="hover:text-zinc-500 transition-colors">Disclaimer</a>
			<a href="/privacy" class="hover:text-zinc-500 transition-colors">Privacy</a>
			<a href="/dmca" class="hover:text-zinc-500 transition-colors">DMCA</a>
			<span>&copy; {new Date().getFullYear()} libnovel</span>
		</div>
		<!-- Build version / commit SHA -->
		<div class="text-zinc-700 tabular-nums font-mono">
			{#if env.PUBLIC_BUILD_VERSION && env.PUBLIC_BUILD_VERSION !== 'dev'}
				<span title="Build version">{env.PUBLIC_BUILD_VERSION}</span>
				{#if env.PUBLIC_BUILD_COMMIT && env.PUBLIC_BUILD_COMMIT !== 'unknown'}
					<span class="text-zinc-800 select-all" title="Commit SHA"
						>+{env.PUBLIC_BUILD_COMMIT.slice(0, 7)}</span
					>
				{/if}
			{:else}
				<span class="text-zinc-800">dev</span>
			{/if}
		</div>
		</div>
	</footer>
</div>

<!-- ── Persistent mini-player bar ─────────────────────────────────────────── -->
{#if audioStore.active}
	<div class="fixed bottom-0 left-0 right-0 z-50 bg-zinc-900 border-t border-zinc-700 shadow-2xl">

		<!-- Chapter list drawer (slides up above the mini-bar) -->
		{#if chapterDrawerOpen && audioStore.chapters.length > 0}
			<div class="border-b border-zinc-700 bg-zinc-900 max-h-[32rem] overflow-y-auto">
				<div class="max-w-6xl mx-auto px-4">
					<div class="flex items-center justify-between py-2 border-b border-zinc-800 sticky top-0 bg-zinc-900">
						<span class="text-xs font-semibold text-zinc-400 uppercase tracking-wider">Chapters</span>
						<Button
							variant="ghost"
							size="icon"
							onclick={() => (chapterDrawerOpen = false)}
							aria-label="Close chapter list"
							class="h-6 w-6 text-zinc-600 hover:text-zinc-300"
						>
							<svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
								<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/>
							</svg>
						</Button>
					</div>
					{#each audioStore.chapters as ch (ch.number)}
						<a
							href="/books/{audioStore.slug}/chapters/{ch.number}"
							onclick={() => (chapterDrawerOpen = false)}
							class="flex items-center gap-2 py-2 text-xs transition-colors hover:text-zinc-100 {ch.number === audioStore.chapter
								? 'text-amber-400 font-semibold'
								: 'text-zinc-400'}"
						>
							<span class="tabular-nums text-zinc-600 w-8 shrink-0 text-right">
								{ch.number}
							</span>
							<span class="truncate">{ch.title || `Chapter ${ch.number}`}</span>
							{#if ch.number === audioStore.chapter}
								<svg class="w-3 h-3 shrink-0 text-amber-400" fill="currentColor" viewBox="0 0 24 24">
									<path d="M8 5v14l11-7z"/>
								</svg>
							{/if}
						</a>
					{/each}
				</div>
			</div>
		{/if}

		<!-- Generation progress bar (sits at very top of the bar) -->
		{#if audioStore.status === 'generating' || audioStore.status === 'loading'}
			<div class="h-0.5 bg-zinc-800">
				<div
					class="h-full bg-amber-400 transition-none"
					style="width: {audioStore.progress}%"
				></div>
			</div>
		{:else if audioStore.status === 'ready'}
			<!-- Seek bar flush at top — tappable on mobile -->
			<div class="px-0">
				<input
					type="range"
					min="0"
					max={audioStore.duration || 0}
					value={audioStore.currentTime}
					oninput={seek}
					class="w-full h-1 accent-amber-400 cursor-pointer block"
					style="margin: 0; border-radius: 0;"
				/>
			</div>
		{/if}

		<div class="max-w-6xl mx-auto px-4 py-2 flex items-center gap-3">

		<!-- Track info (click to open chapter list drawer) -->
			<button
				class="flex-1 min-w-0 text-left rounded px-1 -ml-1 hover:bg-zinc-800 transition-colors"
				onclick={() => { if (audioStore.chapters.length > 0) chapterDrawerOpen = !chapterDrawerOpen; }}
				aria-label={audioStore.chapters.length > 0 ? 'Toggle chapter list' : undefined}
				title={audioStore.chapters.length > 0 ? 'Chapter list' : undefined}
			>
				{#if audioStore.chapterTitle}
					<p class="text-xs text-zinc-100 truncate leading-tight">{audioStore.chapterTitle}</p>
				{/if}
				{#if audioStore.bookTitle}
					<p class="text-xs text-zinc-500 truncate leading-tight">{audioStore.bookTitle}</p>
				{/if}
				{#if audioStore.status === 'generating'}
					<p class="text-xs text-amber-400 leading-tight">
						Generating… {Math.round(audioStore.progress)}%
					</p>
				{:else if audioStore.status === 'ready'}
					<p class="text-xs text-zinc-500 tabular-nums leading-tight">
						{formatTime(audioStore.currentTime)} / {formatTime(audioStore.duration)}
					</p>
				{:else if audioStore.status === 'loading'}
					<p class="text-xs text-zinc-500 leading-tight">Loading…</p>
				{/if}
			</button>

			{#if audioStore.status === 'ready'}
				<!-- Skip back 15s -->
				<Button
					variant="ghost"
					size="icon"
					onclick={skipBack}
					title="Back 15s"
					aria-label="Rewind 15 seconds"
				>
					<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 24 24">
						<path d="M11.99 5V1l-5 5 5 5V7c3.31 0 6 2.69 6 6s-2.69 6-6 6-6-2.69-6-6h-2c0 4.42 3.58 8 8 8s8-3.58 8-8-3.58-8-8-8z"/>
						<text x="8.5" y="14.5" font-size="5" font-family="sans-serif" font-weight="bold" fill="currentColor">15</text>
					</svg>
				</Button>

				<!-- Play / Pause — custom circular amber style, kept as raw button -->
				<button
					onclick={togglePlay}
					class="w-10 h-10 rounded-full bg-amber-400 text-zinc-900 flex items-center justify-center hover:bg-amber-300 transition-colors flex-shrink-0"
					aria-label={audioStore.isPlaying ? 'Pause' : 'Play'}
				>
					{#if audioStore.isPlaying}
						<svg class="w-4 h-4" fill="currentColor" viewBox="0 0 24 24">
							<path d="M6 4h4v16H6V4zm8 0h4v16h-4V4z"/>
						</svg>
					{:else}
						<svg class="w-4 h-4 ml-0.5" fill="currentColor" viewBox="0 0 24 24">
							<path d="M8 5v14l11-7z"/>
						</svg>
					{/if}
				</button>

				<!-- Skip forward 30s -->
				<Button
					variant="ghost"
					size="icon"
					onclick={skipForward}
					title="Forward 30s"
					aria-label="Skip 30 seconds"
				>
					<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 24 24">
						<path d="M12 5V1l5 5-5 5V7c-3.31 0-6 2.69-6 6s2.69 6 6 6 6-2.69 6-6h2c0 4.42-3.58 8-8 8s-8-3.58-8-8 3.58-8 8-8z"/>
						<text x="8.5" y="14.5" font-size="5" font-family="sans-serif" font-weight="bold" fill="currentColor">30</text>
					</svg>
				</Button>

				<!-- Speed control — fixed-width pill, kept as raw button -->
				<button
					onclick={cycleSpeed}
					class="text-xs font-semibold text-zinc-300 hover:text-amber-400 transition-colors px-2 py-1 rounded bg-zinc-800 hover:bg-zinc-700 flex-shrink-0 tabular-nums w-12 text-center"
					title="Change playback speed"
					aria-label="Playback speed {audioStore.speed}x"
				>
					{audioStore.speed}×
				</button>

			<!-- Auto-next toggle — has absolute-positioned status dots, kept as raw button -->
			<button
				onclick={() => (audioStore.autoNext = !audioStore.autoNext)}
				class={cn(
					'relative p-1.5 rounded flex-shrink-0 transition-colors',
					audioStore.autoNext
						? 'text-amber-400 bg-amber-400/15 hover:bg-amber-400/25'
						: 'text-zinc-600 hover:text-zinc-300 hover:bg-zinc-800'
				)}
				title={audioStore.autoNext
					? audioStore.nextStatus === 'prefetched'
						? `Auto-next on — Ch.${audioStore.nextChapter} ready`
						: audioStore.nextStatus === 'prefetching'
							? `Auto-next on — preparing Ch.${audioStore.nextChapter}…`
							: 'Auto-next on'
					: 'Auto-next off'}
				aria-label="Auto-next {audioStore.autoNext ? 'on' : 'off'}"
				aria-pressed={audioStore.autoNext}
			>
				<!-- "skip to end" / auto-advance icon -->
				<svg class="w-4 h-4" fill="currentColor" viewBox="0 0 24 24">
					<path d="M6 18l8.5-6L6 6v12zm8.5-6L23 6v12l-8.5-6z"/>
				</svg>
				<!-- Prefetch status dot -->
				{#if audioStore.autoNext && audioStore.nextStatus === 'prefetching'}
					<span class="absolute top-0.5 right-0.5 w-1.5 h-1.5 rounded-full bg-amber-400 animate-pulse"></span>
				{:else if audioStore.autoNext && audioStore.nextStatus === 'prefetched'}
					<span class="absolute top-0.5 right-0.5 w-1.5 h-1.5 rounded-full bg-green-400"></span>
				{/if}
			</button>
			{:else if audioStore.status === 'generating'}
				<!-- Spinner during generation -->
				<svg class="w-6 h-6 text-amber-400 animate-spin flex-shrink-0" fill="none" viewBox="0 0 24 24">
					<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
					<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"></path>
				</svg>
			{/if}

			<!-- Cover thumbnail / go-to-chapter link -->
			{#if audioStore.slug && audioStore.chapter > 0}
				<a
					href="/books/{audioStore.slug}/chapters/{audioStore.chapter}"
					class="shrink-0 rounded overflow-hidden hover:opacity-80 transition-opacity"
					title="Go to chapter"
					aria-label="Go to chapter"
				>
					{#if audioStore.cover}
						<img
							src={audioStore.cover}
							alt=""
							class="w-8 h-11 object-cover rounded"
						/>
					{:else}
						<!-- Fallback book icon -->
						<div class="w-8 h-11 flex items-center justify-center bg-zinc-800 rounded border border-zinc-700">
							<svg class="w-4 h-4 text-zinc-500" fill="currentColor" viewBox="0 0 24 24">
								<path d="M18 2H6c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm-2 14H8v-2h8v2zm0-4H8v-2h8v2zm0-4H8V6h8v2z"/>
							</svg>
						</div>
					{/if}
				</a>
			{/if}

			<!-- Dismiss -->
			<Button
				variant="ghost"
				size="icon"
				onclick={dismiss}
				title="Close player"
				aria-label="Close player"
				class="text-zinc-600 hover:text-zinc-400 flex-shrink-0"
			>
				<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
					<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
				</svg>
			</Button>
		</div>
	</div>
{/if}
