<script lang="ts">
	import { invoke } from '@tauri-apps/api/core';
	import { emit, listen } from '@tauri-apps/api/event';
	import { messages, currentInput, isProcessing, addMessage, currentSessionId, messageToDb, queuedMessage, messageQueue, agentMode, pendingChanges, permissionMode, type Message, type QuickAction, type FileChange, type PermissionMode } from '$lib/stores/app';
	import { currentTool, processingPhase } from '$lib/stores/events';
	import { marked, type Tokens } from 'marked';
	import { tick, onDestroy, onMount } from 'svelte';
	import { get } from 'svelte/store';
	import CommandPalette from './CommandPalette.svelte';
	import DiffView from './DiffView.svelte';
	import FileMention from './FileMention.svelte';
	import QuickActions from './QuickActions.svelte';
	import MessageList from './MessageList.svelte';
	import ConversationBanner from './ConversationBanner.svelte';
	import ApprovalBar from './ApprovalBar.svelte';
	import { startConversation, stopConversation, conversationActive } from '$lib/voice/conversationEngine';
	// ChatStatusBar entfernt (Phase 9): wandert in globale StatusBar im +layout

	// Props
	let { detached = false }: { detached?: boolean } = $props();

	// Input-Referenz für Focus-Shortcuts
	let inputTextarea: HTMLTextAreaElement;

	// Custom Renderer für Code-Blöcke mit Wrapper
	const renderer = new marked.Renderer();
	renderer.code = function ({ text, lang }: Tokens.Code): string {
		const language = lang || '';
		const escapedCode = text
			.replace(/&/g, '&amp;')
			.replace(/</g, '&lt;')
			.replace(/>/g, '&gt;');
		return `<div class="code-block-wrapper" data-lang="${language}"><pre><code class="language-${language}">${escapedCode}</code></pre></div>`;
	};

	marked.setOptions({ breaks: true, gfm: true, renderer });

	// Collapse: Nachrichten mit > X Zeilen werden eingeklappt (rollenabhängig)
	const COLLAPSE_LINES_USER = 10;
	const COLLAPSE_LINES_ASSISTANT = 25;
	let expandedMessages = $state<string[]>([]);

	function toggleExpand(msgId: string) {
		if (expandedMessages.includes(msgId)) {
			expandedMessages = expandedMessages.filter(id => id !== msgId);
		} else {
			expandedMessages = [...expandedMessages, msgId];
		}
	}

	function shouldCollapse(content: string, role: string = 'assistant'): boolean {
		const limit = role === 'user' ? COLLAPSE_LINES_USER : COLLAPSE_LINES_ASSISTANT;
		return content.split('\n').length > limit;
	}

	function getCollapseLimit(role: string): number {
		return role === 'user' ? COLLAPSE_LINES_USER : COLLAPSE_LINES_ASSISTANT;
	}

	function renderMarkdown(text: string): string {
		try {
			// Thinking-Blöcke erkennen und in <details> packen
			const processed = collapseThinkingBlocks(text);
			return marked.parse(processed) as string;
		} catch {
			return text;
		}
	}

	/**
	 * Erkennt "Denk-Blöcke" im Text und zeigt sie als kompakte Inline-Elemente.
	 * Zwei Quellen:
	 * 1. SDK Extended-Thinking (kommt als <div class="thinking-inline"> von Bridge)
	 * 2. Text-basierte Patterns (Lass mich analysieren..., Ich schaue mir...)
	 */
	function collapseThinkingBlocks(text: string): string {
		// Bereits von Bridge als inline-div geliefert? Nicht nochmal wrappen.
		if (text.includes('<div class="thinking-inline">')) return text;

		// Legacy: Falls noch alte <details> vorhanden, konvertieren
		if (text.includes('<details class="thinking-block">')) {
			return text.replace(
				/<details class="thinking-block">.*?<div class="thinking-content">([\s\S]*?)<\/div><\/details>/g,
				(_match, content) => `<div class="thinking-inline"><span class="thinking-label">\u{1F4AD}</span><span class="thinking-text">${content}</span></div>`
			);
		}

		// Pattern: Text beginnt mit Analyse/Überlegungs-Block, dann kommt die Antwort
		const thinkingPatterns = [
			/^((?:(?:Lass mich|Let me|Ich (?:schaue|prüfe|analysiere|untersuche|überleg|werde)|OK,? (?:lass|ich)|Gut,? (?:lass|ich)|Hmm|Also,? |Zunächst|Zuerst|Schauen wir|Jetzt (?:schaue|prüfe|check)).*?\n(?:.*\n)*?))((?:\n(?:#{1,3} |(?:\*\*|Die |Das |Hier |Zusammen|Fertig|Erledigt|Done|✅|---)).*[\s\S]*))/m,
		];

		for (const pattern of thinkingPatterns) {
			const match = text.match(pattern);
			if (match && match[1] && match[1].split('\n').length > 5) {
				const thinkingPart = match[1].trim().replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
				const answerPart = match[2].trim();
				return `<div class="thinking-inline"><span class="thinking-label">\u{1F4AD}</span><span class="thinking-text">${thinkingPart}</span></div>\n\n${answerPart}`;
			}
		}

		return text;
	}

	// Tool-Aktivitätsanzeige Hilfsfunktionen
	function getToolIcon(tool: string): string {
		const icons: Record<string, string> = {
			'Read': '\u{1F4D6}', 'Write': '\u{270F}\u{FE0F}', 'Edit': '\u{270F}\u{FE0F}',
			'Bash': '\u{26A1}', 'Grep': '\u{1F50D}', 'Glob': '\u{1F50D}',
			'Task': '\u{1F916}', 'Agent': '\u{1F916}',
		};
		return icons[tool] || '\u{2699}\u{FE0F}';
	}

	function getToolLabel(tool: string, input: Record<string, unknown> | null): string {
		if (!input) return `${tool}...`;
		switch(tool) {
			case 'Read': return `Liest ${(input.file_path as string)?.split('/').pop() || 'Datei'}...`;
			case 'Write': return `Schreibt ${(input.file_path as string)?.split('/').pop() || 'Datei'}...`;
			case 'Edit': return `Bearbeitet ${(input.file_path as string)?.split('/').pop() || 'Datei'}...`;
			case 'Bash': return `Führt aus: ${((input.command as string) || '').substring(0, 40)}...`;
			case 'Grep': return `Sucht: ${(input.pattern as string) || ''}...`;
			case 'Glob': return `Sucht Dateien: ${(input.pattern as string) || ''}...`;
			case 'Task': case 'Agent': return `Delegiert: ${((input.description as string) || (input.prompt as string) || '').substring(0, 40)}...`;
			default: return `${tool}...`;
		}
	}

	// Phasen-basierte Status-Anzeige
	function getPhaseIcon(phase: string): string {
		switch(phase) {
			case 'thinking': return '\u{1F9E0}';     // 🧠
			case 'streaming': return '\u{270D}\u{FE0F}'; // ✍️
			case 'tool-use': return '\u{1F527}';      // 🔧
			case 'subagent': return '\u{1F916}';      // 🤖
			default: return '\u{2699}\u{FE0F}';       // ⚙️
		}
	}

	function getPhaseLabel(phase: string): string {
		switch(phase) {
			case 'thinking': return 'Denkt nach';
			case 'streaming': return 'Schreibt Antwort';
			case 'tool-use': return 'Arbeitet';
			case 'subagent': return 'Subagent aktiv';
			default: return 'Verarbeitet';
		}
	}

	// Svelte Action: Copy-Buttons zu Code-Blöcken hinzufügen
	function addCopyButtons(node: HTMLElement) {
		function processCodeBlocks() {
			const wrappers = node.querySelectorAll('.code-block-wrapper:not([data-copy-added])');
			wrappers.forEach((wrapper) => {
				wrapper.setAttribute('data-copy-added', 'true');

				const lang = wrapper.getAttribute('data-lang') || '';
				const codeEl = wrapper.querySelector('code');
				const codeText = codeEl?.textContent || '';

				// Header mit Sprache und Copy-Button erstellen
				const header = document.createElement('div');
				header.className = 'code-header';

				if (lang) {
					const langSpan = document.createElement('span');
					langSpan.className = 'code-lang';
					langSpan.textContent = lang;
					header.appendChild(langSpan);
				}

				const copyBtn = document.createElement('button');
				copyBtn.className = 'copy-btn';
				copyBtn.title = 'Code kopieren';
				copyBtn.innerHTML = '📋';
				copyBtn.onclick = async () => {
					try {
						await navigator.clipboard.writeText(codeText);
						copyBtn.innerHTML = '<span class="copied">✓</span>';
						setTimeout(() => (copyBtn.innerHTML = '📋'), 2000);
					} catch (err) {
						console.error('Kopieren fehlgeschlagen:', err);
					}
				};
				header.appendChild(copyBtn);

				wrapper.insertBefore(header, wrapper.firstChild);
			});
		}

		// Initial verarbeiten
		processCodeBlocks();

		// MutationObserver für dynamische Inhalte (Streaming)
		const observer = new MutationObserver(processCodeBlocks);
		observer.observe(node, { childList: true, subtree: true });

		return {
			destroy() {
				observer.disconnect();
			}
		};
	}

	let messagesContainer: HTMLDivElement;

	// Edit-Modus State
	let editingMessageId: string | null = $state(null);
	let editingContent: string = $state('');

	// Auto-Compacting State
	let lastMessageCount = 0;
	let compactingWarningShown = false;
	let showCompactingDialog = $state(false);
	let estimatedTokens = $state(0);
	const TOKEN_WARNING_THRESHOLD = 40000; // ~40k Token = Warnung zeigen
	const KEEP_LAST_MESSAGES = 30;

	// Voice-Interface State
	let isRecording = $state(false);
	let audioLevel = $state(0);
	let liveTranscript = $state('');
	let mediaRecorder: MediaRecorder | null = null;
	let audioContext: AudioContext | null = null;
	let analyser: AnalyserNode | null = null;
	let audioChunks: Blob[] = [];
	let levelAnimationFrame: number | null = null;

	// Quick-Actions Palette (Ctrl+K)
	let showQuickActions = $state(false);

	// File-Drop State
	let isDragOver = $state(false);
	let dragCounter = 0;  // Verhindert Flackern bei verschachtelten Elementen

	function handleDragEnter(e: DragEvent) {
		e.preventDefault();
		dragCounter++;
		if (e.dataTransfer?.types.includes('Files')) {
			isDragOver = true;
		}
	}

	function handleDragLeave(e: DragEvent) {
		e.preventDefault();
		dragCounter--;
		if (dragCounter <= 0) {
			isDragOver = false;
			dragCounter = 0;
		}
	}

	function handleDragOver(e: DragEvent) {
		e.preventDefault();
		if (e.dataTransfer) {
			e.dataTransfer.dropEffect = 'copy';
		}
	}

	async function handleDrop(e: DragEvent) {
		e.preventDefault();
		isDragOver = false;
		dragCounter = 0;

		const files = e.dataTransfer?.files;
		if (!files || files.length === 0) return;

		const fileContents: string[] = [];

		for (const file of Array.from(files)) {
			try {
				// Bilder: als Base64 einbetten (Claude kann Bilder analysieren)
				if (file.type.startsWith('image/')) {
					const base64 = await fileToBase64(file);
					fileContents.push(`📎 **${file.name}** (${formatSize(file.size)}, ${file.type})\n\n![${file.name}](${base64})`);
					continue;
				}

				// Textdateien: Inhalt lesen
				if (file.size > 500_000) {
					fileContents.push(`📎 **${file.name}** (${formatSize(file.size)}) — Datei zu groß für direkten Chat (max 500KB). Bitte über Dateipfad referenzieren.`);
					continue;
				}

				const text = await file.text();
				const ext = file.name.split('.').pop() || '';
				const lang = extToLang(ext);
				fileContents.push(`📎 **${file.name}** (${formatSize(file.size)})\n\`\`\`${lang}\n${text}\n\`\`\``);
			} catch (err) {
				fileContents.push(`📎 **${file.name}** — Fehler beim Lesen: ${err}`);
			}
		}

		if (fileContents.length > 0) {
			const plural = files.length > 1 ? `${files.length} Dateien` : 'Datei';
			const prefix = `Ich habe dir ${plural} in den Chat gezogen. Analysiere bitte:\n\n`;
			$currentInput = prefix + fileContents.join('\n\n---\n\n');
			inputTextarea?.focus();
		}
	}

	function fileToBase64(file: File): Promise<string> {
		return new Promise((resolve, reject) => {
			const reader = new FileReader();
			reader.onload = () => resolve(reader.result as string);
			reader.onerror = reject;
			reader.readAsDataURL(file);
		});
	}

	function formatSize(bytes: number): string {
		if (bytes < 1024) return bytes + ' B';
		if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB';
		return (bytes / (1024 * 1024)).toFixed(1) + ' MB';
	}

	function extToLang(ext: string): string {
		const map: Record<string, string> = {
			ts: 'typescript', js: 'javascript', py: 'python', rs: 'rust',
			svelte: 'svelte', html: 'html', css: 'css', json: 'json',
			yaml: 'yaml', yml: 'yaml', toml: 'toml', md: 'markdown',
			sh: 'bash', sql: 'sql', php: 'php', nix: 'nix', xml: 'xml',
			vue: 'vue', tsx: 'tsx', jsx: 'jsx', go: 'go', java: 'java',
		};
		return map[ext.toLowerCase()] || ext;
	}

	// Slash-Command Autocomplete State
	let showCommandPalette = $state(false);
	let commandQuery = $state('');
	let commandPaletteRef: CommandPalette | undefined = $state(undefined);

	// @-Mention Autocomplete State
	let showFileMention = $state(false);
	let mentionQuery = $state('');
	let fileMentionRef: FileMention | undefined = $state(undefined);

	// Slash-Command und @-Mention Erkennung im Input
	$effect(() => {
		const text = $currentInput;
		if (text.startsWith('/')) {
			showCommandPalette = true;
			commandQuery = text.slice(1);
			showFileMention = false;
		} else {
			showCommandPalette = false;
			commandQuery = '';
		}

		// @-Mention: Suche das letzte @ im Text
		const atMatch = text.match(/@([\w.\-/]+)$/);
		if (atMatch && atMatch[1].length > 0) {
			showFileMention = true;
			mentionQuery = atMatch[1];
		} else {
			showFileMention = false;
			mentionQuery = '';
		}
	});

	// @-Mention: Datei ausgewaehlt → @query durch @dateiname ersetzen
	function handleFileSelect(file: { name: string; path: string; full_path: string }) {
		// Ersetze das letzte @query durch @dateiname
		const text = $currentInput;
		const atIdx = text.lastIndexOf('@');
		if (atIdx >= 0) {
			$currentInput = text.substring(0, atIdx) + `@${file.path} `;
		}
		showFileMention = false;
	}

	// Command auswählen: Text ersetzen
	function handleCommandSelect(cmd: { name: string; description: string; category: string }) {
		if (!cmd.name) {
			// Escape gedrückt — Palette schliessen, Text behalten
			showCommandPalette = false;
			return;
		}
		$currentInput = '/' + cmd.name + ' ';
		showCommandPalette = false;
		// Focus zurück aufs Input
		inputTextarea?.focus();
	}

	// VAD (Voice Activity Detection) — automatisches Stoppen nach Sprechpause
	const VAD_SILENCE_THRESHOLD = 15;     // Pegel unter dem als Stille gilt
	const VAD_SILENCE_DURATION = 1500;    // ms Stille vor Auto-Stopp
	let silenceStartTime: number | null = null;
	let vadEnabled = $state(true);        // VAD ein/aus

	// Scroll wird komplett von MessageList verwaltet (hat den echten scroll-Container).
	// ChatPanel.scrollToBottom() war auf messagesContainer (Wrapper ohne overflow) und
	// tat nichts — entfernt um Konflikte mit MessageList zu vermeiden.

	// Bei Session-Wechsel: Compacting-Flag + KB-Hints zurücksetzen
	$effect(() => {
		if ($currentSessionId) {
			compactingWarningShown = false;
			showCompactingDialog = false;
			// KB-Hints Session-Topic zurücksetzen damit neue Hints kommen
			invoke('reset_kb_session').catch(() => {});
		}
	});

	// Token-Schätzung: ~4 Zeichen pro Token
	function estimateTokensForMessages(msgs: Message[]): number {
		return msgs.reduce((total, msg) => total + Math.ceil(msg.content.length / 4), 0);
	}

	// Nachricht in DB speichern
	async function saveMessageToDb(msg: Message) {
		const sessionId = get(currentSessionId);
		if (!sessionId) return;

		try {
			const dbMsg = messageToDb(msg, sessionId);
			await invoke('save_message', { message: dbMsg });
		} catch (err) {
			console.error('Fehler beim Speichern der Nachricht:', err);
		}
	}

	// Neue Nachrichten automatisch speichern + Token-Warnung
	const unsubscribe = messages.subscribe(async (msgs) => {
		if (msgs.length > lastMessageCount && lastMessageCount > 0) {
			// Neue Nachricht(en) hinzugefügt
			const newMessages = msgs.slice(lastMessageCount);
			for (const msg of newMessages) {
				// Nur speichern wenn Nachricht Content hat (nicht die leere Streaming-Nachricht)
				if (msg.content && msg.content.trim()) {
					await saveMessageToDb(msg);
				}
			}
		}

		// Token-Schätzung aktualisieren
		estimatedTokens = estimateTokensForMessages(msgs);

		// Warnung zeigen wenn Token-Schwelle überschritten (einmalig pro Session)
		if (!compactingWarningShown && estimatedTokens > TOKEN_WARNING_THRESHOLD && !$isProcessing) {
			compactingWarningShown = true;
			showCompactingDialog = true;
		}

		lastMessageCount = msgs.length;
	});

	async function performCompacting() {
		const sessionId = get(currentSessionId);
		if (!sessionId) return;

		showCompactingDialog = false;

		try {
			// Zuerst: Kritischen Kontext extrahieren und archivieren
			const currentMessages = get(messages);
			const messagesJson = JSON.stringify(currentMessages.map(m => ({
				role: m.role,
				content: m.content
			})));

			try {
				const extracted = await invoke('extract_context_before_compacting', {
					sessionId,
					messagesJson
				});
				console.log('📦 Kontext extrahiert vor Compacting:', extracted);
			} catch (extractErr) {
				console.warn('Context-Extraction fehlgeschlagen (nicht kritisch):', extractErr);
			}

			// Dann: Compacting durchführen
			const compacted: number = await invoke('compact_session', {
				sessionId,
				keepLast: KEEP_LAST_MESSAGES
			});

			if (compacted > 0) {
				addMessage('system', `📦 Compacting: ${compacted} ältere Nachrichten wurden zusammengefasst. Die letzten ${KEEP_LAST_MESSAGES} bleiben erhalten. Kritischer Kontext wurde archiviert.`);
			}
		} catch (err) {
			console.error('Compacting fehlgeschlagen:', err);
			addMessage('system', `⚠️ Compacting fehlgeschlagen: ${err}`);
		}
	}

	function dismissCompactingDialog() {
		showCompactingDialog = false;
		// Warnung für diese Session nicht erneut zeigen
	}

	// ============ Voice Interface ============

	// getUserMedia mit Timeout — WebKitGTK hängt manchmal endlos statt zu fehlern
	function getUserMediaWithTimeout(constraints: MediaStreamConstraints, timeoutMs = 5000): Promise<MediaStream> {
		return new Promise((resolve, reject) => {
			const timer = setTimeout(() => {
				reject(new Error(`getUserMedia Timeout nach ${timeoutMs}ms — GStreamer-Pipeline hängt`));
			}, timeoutMs);

			navigator.mediaDevices.getUserMedia(constraints)
				.then((stream) => {
					clearTimeout(timer);
					resolve(stream);
				})
				.catch((err) => {
					clearTimeout(timer);
					reject(err);
				});
		});
	}

	async function startRecording() {
		try {
			let stream: MediaStream;

			// Prüfe zuerst ob mediaDevices überhaupt verfügbar ist
			if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) {
				throw new Error('MediaDevices API nicht verfügbar — WebKitGTK braucht GStreamer + PipeWire');
			}

			try {
				stream = await getUserMediaWithTimeout({ audio: true });
			} catch (initialErr) {
				// WebKitGTK wirft verschiedene Fehler: OverconstrainedError, NotFoundError,
				// TypeError("Invalid constraint"), Timeout. Bei JEDEM Fehler Fallback versuchen.
				console.warn('getUserMedia({audio:true}) fehlgeschlagen, versuche Fallback:', initialErr);

				try {
					const devices = await navigator.mediaDevices.enumerateDevices();
					const audioInput = devices.find(d => d.kind === 'audioinput');

					if (audioInput) {
						console.log('Audio-Device gefunden:', audioInput.label || audioInput.deviceId);
						stream = await getUserMediaWithTimeout({
							audio: { deviceId: { exact: audioInput.deviceId } }
						});
					} else {
						// Letzter Versuch: komplett ohne Constraints
						stream = await getUserMediaWithTimeout({ audio: {} });
					}
				} catch (fallbackErr) {
					throw new Error(
						'Mikrofon-Zugriff fehlgeschlagen. Mögliche Ursachen:\n' +
						'• GStreamer-Plugins fehlen (gst-plugin-pipewire)\n' +
						'• PipeWire läuft nicht\n' +
						'• App wurde nicht über den Nix-Wrapper gestartet\n' +
						`Original: ${initialErr instanceof Error ? initialErr.message : initialErr}`
					);
				}
			}

			// Audio-Analyse für Pegel-Anzeige
			audioContext = new AudioContext();
			analyser = audioContext.createAnalyser();
			const source = audioContext.createMediaStreamSource(stream);
			source.connect(analyser);
			analyser.fftSize = 256;

			// Pegel-Animation starten
			updateAudioLevel();

			// MediaRecorder für Aufnahme
			mediaRecorder = new MediaRecorder(stream, { mimeType: 'audio/webm' });
			audioChunks = [];

			mediaRecorder.ondataavailable = (event) => {
				if (event.data.size > 0) {
					audioChunks.push(event.data);
				}
			};

			mediaRecorder.onstop = async () => {
				// Aufnahme beendet — Audio an Whisper senden
				const audioBlob = new Blob(audioChunks, { type: 'audio/webm' });
				await transcribeAudio(audioBlob);

				// Stream stoppen
				stream.getTracks().forEach(track => track.stop());
			};

			mediaRecorder.start(100); // Chunks alle 100ms
			isRecording = true;
			liveTranscript = '';
			silenceStartTime = null; // VAD-Timer zurücksetzen
			console.log('🎤 Aufnahme gestartet' + (vadEnabled ? ' (VAD aktiv)' : ''));
		} catch (err) {
			console.error('Mikrofon-Zugriff fehlgeschlagen:', err);
			const hint = (err instanceof DOMException && err.name === 'OverconstrainedError')
				? ' WebKitGTK (Tauri/Linux) unterstützt ggf. kein Audio-Capture — prüfe PipeWire/GStreamer-Plugins.'
				: '';
			addMessage('system', `⚠️ Mikrofon-Zugriff fehlgeschlagen: ${err instanceof Error ? err.message : err}${hint}`);
		}
	}

	function stopRecording() {
		if (mediaRecorder && mediaRecorder.state !== 'inactive') {
			mediaRecorder.stop();
		}

		// Pegel-Animation stoppen
		if (levelAnimationFrame) {
			cancelAnimationFrame(levelAnimationFrame);
			levelAnimationFrame = null;
		}

		// Audio-Context schließen
		if (audioContext) {
			audioContext.close();
			audioContext = null;
		}

		isRecording = false;
		audioLevel = 0;
		console.log('🎤 Aufnahme gestoppt');
	}

	function updateAudioLevel() {
		if (!analyser || !isRecording) return;

		const dataArray = new Uint8Array(analyser.frequencyBinCount);
		analyser.getByteFrequencyData(dataArray);

		// Durchschnittspegel berechnen
		const average = dataArray.reduce((a, b) => a + b, 0) / dataArray.length;
		audioLevel = Math.min(100, average * 1.5); // Normalisieren auf 0-100

		// VAD: Stille erkennen und nach Pause automatisch stoppen
		if (vadEnabled && audioChunks.length > 0) {
			if (audioLevel < VAD_SILENCE_THRESHOLD) {
				// Stille beginnt oder dauert an
				if (silenceStartTime === null) {
					silenceStartTime = Date.now();
				} else if (Date.now() - silenceStartTime > VAD_SILENCE_DURATION) {
					// Lange genug still — Aufnahme automatisch stoppen
					console.log('🔇 VAD: Stille erkannt, stoppe Aufnahme');
					stopRecording();
					return;
				}
			} else {
				// Sprache erkannt — Stille-Timer zurücksetzen
				silenceStartTime = null;
			}
		}

		levelAnimationFrame = requestAnimationFrame(updateAudioLevel);
	}

	async function transcribeAudio(audioBlob: Blob) {
		liveTranscript = 'Transkribiere...';

		try {
			// Audio als Base64 für Tauri-Command
			const arrayBuffer = await audioBlob.arrayBuffer();
			const base64 = btoa(String.fromCharCode(...new Uint8Array(arrayBuffer)));

			// An Backend senden für Whisper-Transkription
			const transcript: string = await invoke('transcribe_audio', {
				audioBase64: base64,
				format: 'webm'
			});

			if (transcript && transcript.trim()) {
				// Transkript in Input-Feld einfügen
				$currentInput = ($currentInput + ' ' + transcript).trim();
				liveTranscript = '';
				console.log('📝 Transkript:', transcript);
			} else {
				liveTranscript = '';
			}
		} catch (err) {
			console.error('Transkription fehlgeschlagen:', err);
			liveTranscript = `Fehler: ${err}`;
			// Nach 3s ausblenden
			setTimeout(() => { liveTranscript = ''; }, 3000);
		}
	}

	function toggleRecording() {
		if (isRecording) {
			stopRecording();
		} else {
			startRecording();
		}
	}

	// Mic-Button: zwei Modi
	//   - Kurzer Klick (<450ms loslassen) = Diktat (alt: Audio in Textbox)
	//   - Lang halten (>=450ms) = Konversationsmodus (TTS, Barge-In)
	// Wenn Konversation bereits aktiv ist: jeder Klick beendet sie.
	const LONG_PRESS_MS = 450;
	let micPressTimer: ReturnType<typeof setTimeout> | null = null;
	let micWasLongPress = false;
	let micPressed = false;  // Guard: nur true nach pointerdown

	function onMicPointerDown(_e: PointerEvent) {
		// Wenn Konversation laeuft → erster Klick beendet
		if (get(conversationActive)) {
			stopConversation();
			return;
		}
		micPressed = true;
		micWasLongPress = false;
		micPressTimer = setTimeout(() => {
			micWasLongPress = true;
			micPressTimer = null;
			// Falls gerade Diktat laeuft, vorher stoppen
			if (isRecording) stopRecording();
			startConversation().catch((err) => console.error('Konversation-Start fehlgeschlagen:', err));
		}, LONG_PRESS_MS);
	}

	function onMicPointerUp(_e: PointerEvent) {
		if (!micPressed) return;  // Kein pointerdown vorher → ignorieren (Hover-Leave)
		micPressed = false;
		if (micPressTimer) {
			clearTimeout(micPressTimer);
			micPressTimer = null;
		}
		// Wenn nicht zum Long-Press eskaliert → Diktat
		if (!micWasLongPress && !get(conversationActive)) {
			toggleRecording();
		}
		micWasLongPress = false;
	}

	onDestroy(() => {
		unsubscribe();
		// Voice-Aufnahme stoppen falls aktiv
		if (isRecording) {
			stopRecording();
		}
	});

	// Quick-Action ausführen (Callback von QuickActions-Komponente)
	function handleQuickAction(action: QuickAction) {
		if (action.command) {
			// Als Nachricht an Claude senden
			$currentInput = action.command;
			sendMessage();
		} else if (action.id === 'settings') {
			// Navigation: Settings-Tab aktivieren (Event an Hauptfenster)
			emit('navigate-tab', { panel: 'right', tab: 'settings' });
		} else if (action.id === 'monitor') {
			emit('navigate-tab', { panel: 'middle', tab: 'monitor' });
		} else if (action.id === 'voice-check') {
			// Ergebnis als System-Message
			invoke('check_voice_availability').then((result) => {
				addMessage('system', `🎤 Voice-Status: ${JSON.stringify(result, null, 2)}`);
			}).catch((err) => {
				addMessage('system', `⚠️ Voice-Check fehlgeschlagen: ${err}`);
			});
		}
	}

	// Globale Keyboard Shortcuts
	function handleGlobalKeydown(event: KeyboardEvent) {
		// Ctrl+K: Quick-Actions Palette öffnen/schliessen
		if (event.ctrlKey && event.key === 'k') {
			event.preventDefault();
			showQuickActions = !showQuickActions;
			return;
		}

		// Ctrl+Shift+K: Input leeren und Focus
		if (event.ctrlKey && event.shiftKey && event.key === 'K') {
			event.preventDefault();
			$currentInput = '';
			inputTextarea?.focus();
			return;
		}
	}

	onMount(async () => {
		window.addEventListener('keydown', handleGlobalKeydown);

		// Global Hotkey: Super+C fokussiert das Input-Feld
		const unlistenFocus = await listen('focus-chat-input', () => {
			inputTextarea?.focus();
		});

		// Clipboard-Watch Events: Vorschlag im Chat anzeigen
		const unlistenClipboard = await listen<{ content: string; content_type: string; suggestion: string }>('clipboard-changed', (event) => {
			const { content, content_type, suggestion } = event.payload;
			const preview = content.length > 200 ? content.substring(0, 200) + '...' : content;
			addMessage('system', `📋 Clipboard (${content_type}): ${suggestion}\n\`\`\`\n${preview}\n\`\`\``);
		});

		// Legacy-Queue Subscriber (Sicherheitsnetz — Hauptlogik ist jetzt in der Bridge)
		const unsubProcessing = isProcessing.subscribe(() => {});

		// Phase 11: Permission-Modus aus Settings wiederherstellen, damit der
		// Toggle-Knopf links vom Textfeld den letzten Stand zeigt und die
		// Bridge ihn beim ersten send_message direkt verwendet.
		try {
			const savedMode = await invoke<string>('get_permission_mode');
			if (savedMode === 'default' || savedMode === 'acceptEdits' || savedMode === 'bypassPermissions') {
				permissionMode.set(savedMode);
				if (savedMode !== 'default') {
					invoke('set_permission_mode', { mode: savedMode }).catch(() => {});
				}
			}
		} catch (e) {
			console.debug('Permission-Modus laden fehlgeschlagen:', e);
		}

		return () => {
			window.removeEventListener('keydown', handleGlobalKeydown);
			unsubProcessing();
			unlistenFocus();
			unlistenClipboard();
		};
	});

	function cancelQueued() {
		// Legacy: Queue-Cancel (Bridge hat jetzt eigene Pending-Queue)
		messageQueue.set([]);
		$queuedMessage = null;
	}

	// Accept/Reject Datei-Aenderungen
	async function acceptChange(toolId: string) {
		try {
			await invoke('accept_change', { toolId });
			pendingChanges.update((changes) => changes.filter((c) => c.toolId !== toolId));
			console.log('✅ Aenderung akzeptiert:', toolId);
		} catch (err) {
			console.error('Accept fehlgeschlagen:', err);
		}
	}

	async function rejectChange(toolId: string) {
		try {
			const result = await invoke<string>('reject_change', { toolId });
			pendingChanges.update((changes) => changes.filter((c) => c.toolId !== toolId));
			addMessage('system', `↩️ ${result}`);
			console.log('↩️ Aenderung abgelehnt:', toolId);
		} catch (err) {
			console.error('Reject fehlgeschlagen:', err);
			addMessage('system', `Fehler beim Zuruecksetzen: ${err}`);
		}
	}

	async function sendMessage() {
		const text = $currentInput.trim();
		if (!text) return;

		// Input sofort leeren — Text ist in `text` gesichert.
		// Muss VOR dispatchMessage() passieren, damit die Textbox auch bei
		// Fehlern (Session-Erstellung, DB-Save) zuverlaessig geleert wird.
		// Svelte 5 + writable-Store + bind:value aktualisiert den DOM-Wert
		// erst nach dem naechsten tick — DOM hart leeren damit der User
		// sofort sieht dass die Nachricht weg ist und kein Race entsteht.
		$currentInput = '';
		if (inputTextarea) {
			inputTextarea.value = '';
			inputTextarea.style.height = 'auto';  // auto-resize zuruecksetzen
		}
		await tick();

		// Nachricht IMMER sofort senden — auch während Claude arbeitet.
		// Die Bridge puffert die Nachricht intern und verarbeitet sie
		// automatisch nach dem aktuellen Turn (wie in Claude Code/VS Code Extension).
		await dispatchMessage(text);
	}

	// Den eigentlichen Send-Flow — sendet immer sofort an die Bridge.
	// Wenn eine query() laeuft, puffert die Bridge die Nachricht intern.
	async function dispatchMessage(text: string) {
		// Auto-Session erstellen falls keine aktiv
		let sessionId = get(currentSessionId);
		if (!sessionId) {
			try {
				const title = `Session ${new Date().toLocaleDateString('de-DE')} ${new Date().toLocaleTimeString('de-DE', { hour: '2-digit', minute: '2-digit' })}`;
				const newSession = await invoke<{ id: string }>('create_session', { title });
				sessionId = newSession.id;
				$currentSessionId = sessionId;
				console.log('📂 Auto-Session erstellt:', title);
				// SessionList benachrichtigen
				await emit('session-created', { id: sessionId });
			} catch (err) {
				console.error('Session-Erstellung fehlgeschlagen:', err);
				addMessage('system', `Fehler: Konnte keine Session erstellen - ${err}`);
				return;
			}
		}

		// @-Mentions aufloesen: @pfad/datei.ts durch Dateiinhalt ersetzen
		let resolvedText = text;
		const mentionPattern = /@([\w.\-/]+(?:#\d+(?:-\d+)?)?)/g;
		const mentions = [...text.matchAll(mentionPattern)];
		for (const match of mentions) {
			const ref = match[1];
			const [filePath, lineRange] = ref.split('#');
			try {
				const fullPath = filePath.startsWith('/') ? filePath : await invoke<string>('resolve_file_path', { relativePath: filePath });
				const content = await invoke<string>('read_file_content', { filePath: fullPath, lineRange: lineRange || null });
				const ext = filePath.split('.').pop() || '';
				resolvedText = resolvedText.replace(
					match[0],
					`\n\`\`\`${ext} (${filePath})\n${content}\n\`\`\`\n`
				);
			} catch {
				// Datei nicht gefunden — @-Mention unverändert lassen
			}
		}

		// User-Nachricht sofort im Chat anzeigen + in DB speichern
		const msgId = crypto.randomUUID();
		const msg: Message = {
			id: msgId,
			role: 'user',
			content: text,
			timestamp: new Date(),
		};
		messages.update((msgs) => [...msgs, msg]);
		await saveMessageToDb(msg);

		// isProcessing nur setzen wenn nicht schon aktiv
		// (bei gepufferten Nachrichten laeuft Claude ja schon)
		if (!$isProcessing) {
			$isProcessing = true;
		}

		try {
			// Aufgeloesten Text an Claude senden (mit eingebetteten Datei-Inhalten)
			await invoke('send_message', { message: resolvedText });
		} catch (err) {
			console.error('Fehler beim Senden:', err);
			addMessage('system', `Fehler: ${err}`);
			// Nur auf false setzen wenn keine weiteren Nachrichten pending
			$isProcessing = false;
		}
	}

	function handleKeydown(event: KeyboardEvent) {
		// CommandPalette hat Vorrang bei Tastatur-Events
		if (showCommandPalette && commandPaletteRef) {
			const handled = commandPaletteRef.handleKey(event);
			if (handled) return;
		}

		// FileMention hat Vorrang bei @-Autocomplete
		if (showFileMention && fileMentionRef) {
			const handled = fileMentionRef.handleKey(event);
			if (handled) return;
		}

		// Ctrl+Enter: Immer senden (auch bei mehrzeiligem Text)
		if (event.key === 'Enter' && event.ctrlKey) {
			event.preventDefault();
			sendMessage();
			return;
		}
		// Enter (ohne Shift): Senden
		if (event.key === 'Enter' && !event.shiftKey) {
			event.preventDefault();
			sendMessage();
		}
	}

	// Streaming-Message-ID fuer MessageList (ohne findLast — kompatibel)
	const streamingMessageId = $derived.by(() => {
		if (!$isProcessing) return null;
		for (let i = $messages.length - 1; i >= 0; i--) {
			const m = $messages[i];
			if (m.role === 'assistant' && !m.content) return m.id;
		}
		return null;
	});

	// Wrapper fuer MessageList: ID → Message bzw. Index aufloesen
	function handleEditById(id: string) {
		const m = $messages.find(x => x.id === id);
		if (m) startEdit(m);
	}
	function handleRegenerateById(id: string) {
		const idx = $messages.findIndex(x => x.id === id);
		if (idx >= 0) regenerateResponse(idx);
	}
	function handleRewindById(id: string) {
		// Rewind ist heute noch nicht ueber UI verdrahtet — Platzhalter
		console.log('Rewind angefordert fuer Message', id);
	}

	// Edit-Funktionen
	function startEdit(message: Message) {
		editingMessageId = message.id;
		editingContent = message.content;
	}

	function cancelEdit() {
		editingMessageId = null;
		editingContent = '';
	}

	async function confirmEdit() {
		if (!editingMessageId || !editingContent.trim()) return;

		const msgIndex = $messages.findIndex((m) => m.id === editingMessageId);
		if (msgIndex === -1) return;

		const updatedMessage = {
			...$messages[msgIndex],
			content: editingContent.trim(),
			timestamp: new Date()
		};

		// Nachricht aktualisieren und alle folgenden entfernen
		// (da sie auf der alten Nachricht basieren)
		messages.update((msgs) => {
			const newMsgs = [...msgs.slice(0, msgIndex), updatedMessage];
			return newMsgs;
		});

		// Nachricht in DB aktualisieren
		await saveMessageToDb(updatedMessage);

		// Edit-Modus beenden
		const newContent = editingContent.trim();
		editingMessageId = null;
		editingContent = '';

		// Nachricht neu an Claude senden
		$isProcessing = true;
		try {
			await invoke('send_message', { message: newContent });
		} catch (err) {
			console.error('Fehler beim Senden:', err);
			addMessage('system', `Fehler: ${err}`);
			$isProcessing = false;
		}
	}

	function handleEditKeydown(event: KeyboardEvent) {
		if (event.key === 'Enter' && !event.shiftKey) {
			event.preventDefault();
			confirmEdit();
		} else if (event.key === 'Escape') {
			cancelEdit();
		}
	}

	// Regenerate: Antwort neu generieren
	async function regenerateResponse(assistantMsgIndex: number) {
		if ($isProcessing) return;

		// Vorherige User-Nachricht finden
		let userMsg: Message | null = null;
		for (let i = assistantMsgIndex - 1; i >= 0; i--) {
			if ($messages[i].role === 'user') {
				userMsg = $messages[i];
				break;
			}
		}

		if (!userMsg) {
			console.error('Keine User-Nachricht zum Regenerieren gefunden');
			return;
		}

		// Alle Nachrichten ab der Assistant-Nachricht entfernen
		messages.update((msgs) => msgs.slice(0, assistantMsgIndex));

		// User-Nachricht erneut senden
		$isProcessing = true;
		try {
			await invoke('send_message', { message: userMsg.content });
		} catch (err) {
			console.error('Fehler beim Regenerieren:', err);
			addMessage('system', `Fehler: ${err}`);
			$isProcessing = false;
		}
	}

	// Prüfen ob eine Nachricht die letzte Assistant-Nachricht ist
	function isLastAssistantMessage(index: number): boolean {
		// Finde die letzte Assistant-Nachricht
		for (let i = $messages.length - 1; i >= 0; i--) {
			if ($messages[i].role === 'assistant' && $messages[i].content) {
				return i === index;
			}
		}
		return false;
	}

	// "Das merken" - Speichern in Wissensbasis
	let rememberDialogOpen = $state(false);
	let rememberContent = $state('');
	let rememberEntry = $state({
		category: 'pattern',
		title: '',
		tags: '',
		priority: 2,
	});
	let rememberSaving = $state(false);
	let rememberError = $state('');

	const knowledgeCategories = [
		{ id: 'dolibarr', label: 'Dolibarr' },
		{ id: 'fints', label: 'FinTS/Banking' },
		{ id: 'pattern', label: 'Pattern/Code' },
		{ id: 'projekt', label: 'Projekt' },
		{ id: 'setup', label: 'Setup/Config' },
		{ id: 'ids', label: 'IDs/Referenzen' },
	];

	let copyFeedback = $state<string | null>(null);

	async function copyMessage(message: Message) {
		try {
			await navigator.clipboard.writeText(message.content);
			copyFeedback = message.id;
			setTimeout(() => {
				if (copyFeedback === message.id) copyFeedback = null;
			}, 1500);
		} catch (err) {
			console.error('Kopieren fehlgeschlagen:', err);
		}
	}

	function openRememberDialog(message: Message) {
		rememberContent = message.content;
		rememberEntry = {
			category: 'pattern',
			title: '',
			tags: '',
			priority: 2,
		};
		rememberError = '';
		rememberDialogOpen = true;
	}

	function closeRememberDialog() {
		rememberDialogOpen = false;
		rememberContent = '';
	}

	async function saveToKnowledge() {
		if (!rememberEntry.title.trim() || !rememberContent.trim()) {
			rememberError = 'Titel und Inhalt sind erforderlich';
			return;
		}

		rememberSaving = true;
		rememberError = '';

		try {
			await invoke('save_knowledge', {
				entry: {
					category: rememberEntry.category,
					title: rememberEntry.title.trim(),
					content: rememberContent.trim(),
					tags: rememberEntry.tags.trim() || null,
					priority: rememberEntry.priority,
					status: 'active',
					source: 'chat',
					related_ids: null,
				}
			});
			closeRememberDialog();
		} catch (err) {
			rememberError = `Fehler: ${err}`;
		} finally {
			rememberSaving = false;
		}
	}
</script>

<!-- svelte-ignore a11y_no_static_element_interactions -->
<div class="chat-panel" class:drag-over={isDragOver}
	ondragenter={handleDragEnter}
	ondragleave={handleDragLeave}
	ondragover={handleDragOver}
	ondrop={handleDrop}>

	{#if isDragOver}
		<div class="drop-overlay">
			<div class="drop-icon">📎</div>
			<p>Dateien hier ablegen</p>
			<p class="drop-hint">Code, Text, Bilder — Claude analysiert alles</p>
		</div>
	{/if}

	<!-- Konversations-Banner: nur sichtbar wenn Voice-Konversation laeuft -->
	<ConversationBanner />

	<!-- Phase 9: Lokaler Header entfernt — Brand+Stats sind in der globalen
	     Titlebar / StatusBar. Detach-Button als kleine Icon-Action im Tab-
	     Bereich (oben rechts), realisiert ueber kompakte Toolbar. -->
	<div class="chat-toolbar">
		{#if !detached}
			<button class="tool-btn" onclick={() => invoke('chat_window_open')} title="Chat herauslösen">&#x29C9;</button>
		{:else}
			<button class="tool-btn" onclick={() => invoke('chat_window_close')} title="Zurück ins Hauptfenster">&#x29C7;</button>
		{/if}
	</div>

	<div class="chat-messages-wrap" bind:this={messagesContainer}>
		<MessageList
			sessionId={$currentSessionId}
			{streamingMessageId}
			onEdit={handleEditById}
			onRegenerate={handleRegenerateById}
			onRemember={openRememberDialog}
			onRewind={handleRewindById}
		/>
	</div>

	<!-- Edit-Mode Inline-Editor (legacy, wird nur aktiv wenn editingMessageId gesetzt) -->
	{#if editingMessageId}
		<div class="edit-overlay">
			<textarea
				class="edit-textarea"
				bind:value={editingContent}
				onkeydown={handleEditKeydown}
				rows="3"
				placeholder="Nachricht bearbeiten..."
			></textarea>
			<div class="edit-actions">
				<button class="edit-btn cancel" onclick={cancelEdit}>Abbrechen</button>
				<button class="edit-btn confirm" onclick={confirmEdit} disabled={!editingContent.trim()}>
					Speichern &amp; Senden
				</button>
			</div>
		</div>
	{/if}

	<!-- Sticky Approval-Bar (Phase 9.1): bleibt sichtbar wenn der Chat scrollt,
	     der User verliert offene Datei-Aenderungen nicht aus den Augen. Die
	     eigentliche Diff-Vorschau bleibt inline in der Tool-Karte. -->
	<ApprovalBar />

	<div class="chat-input">
		<CommandPalette
			bind:this={commandPaletteRef}
			query={commandQuery}
			visible={showCommandPalette}
			onSelect={handleCommandSelect}
		/>
		<FileMention
			bind:this={fileMentionRef}
			query={mentionQuery}
			visible={showFileMention}
			onSelect={handleFileSelect}
		/>
		{#if $agentMode && $agentMode !== 'solo'}
			<div class="mode-indicator mode-{$agentMode}">
				<span class="mode-icon">
					{#if $agentMode === 'handlanger'}👷
					{:else if $agentMode === 'experten'}🎓
					{:else if $agentMode === 'auto'}🤖
					{/if}
				</span>
				<span class="mode-label">
					{#if $agentMode === 'handlanger'}Handlanger-Modus
					{:else if $agentMode === 'experten'}Experten-Modus
					{:else if $agentMode === 'auto'}Auto-Modus
					{/if}
				</span>
				{#if $processingPhase !== 'idle'}
					<span class="mode-phase">
						— {#if $processingPhase === 'thinking'}denkt nach...
						{:else if $processingPhase === 'streaming'}schreibt...
						{:else if $processingPhase === 'tool-use'}nutzt Tool...
						{:else if $processingPhase === 'subagent'}delegiert...
						{/if}
					</span>
				{/if}
			</div>
		{/if}
		{#if liveTranscript}
			<div class="live-transcript">
				<span class="transcript-icon">🎤</span>
				<span class="transcript-text">{liveTranscript}</span>
			</div>
		{/if}
		<div class="input-prefix">
			<button
				class="perm-toggle"
				class:active={$permissionMode !== 'default'}
				class:yolo={$permissionMode === 'bypassPermissions'}
				onclick={() => {
					const next: PermissionMode =
						$permissionMode === 'default' ? 'acceptEdits'
						: $permissionMode === 'acceptEdits' ? 'bypassPermissions'
						: 'default';
					permissionMode.set(next);
					invoke('set_permission_mode', { mode: next }).catch((e) => console.warn('set_permission_mode:', e));
				}}
				title={$permissionMode === 'default'
					? 'Approval-Modus: Nachfragen vor jedem Edit/Bash. Klick: Edits automatisch.'
					: $permissionMode === 'acceptEdits'
						? 'Approval-Modus: Edits automatisch, Bash fragt nach. Klick: alles automatisch (Yolo).'
						: 'Yolo: alles laeuft ohne Nachfrage. Klick: Approval-Modus aus.'}
			>
				{#if $permissionMode === 'default'}
					🔒
				{:else if $permissionMode === 'acceptEdits'}
					🔓
				{:else}
					⚡
				{/if}
			</button>
		</div>
		<textarea
			bind:this={inputTextarea}
			bind:value={$currentInput}
			onkeydown={handleKeydown}
			placeholder={$isProcessing ? 'Weiter tippen — wird nach aktuellem Turn verarbeitet...' : 'Nachricht eingeben... (Ctrl+K = Quick-Actions, Ctrl+Enter = Senden)'}
			disabled={isRecording}
			rows="3"
		></textarea>
		<div class="input-buttons">
			<button
				class="mic-button"
				class:recording={isRecording}
				class:conversation={$conversationActive}
				onpointerdown={onMicPointerDown}
				onpointerup={onMicPointerUp}
				onpointercancel={onMicPointerUp}
				onpointerleave={onMicPointerUp}
				title={$conversationActive
					? 'Konversation aktiv (Esc oder Klick = beenden)'
					: isRecording
						? 'Aufnahme stoppen'
						: 'Klick: Diktat ins Textfeld · Lang drücken: Konversationsmodus'}
			>
				{#if $conversationActive}
					<span class="mic-icon conv">🎙️</span>
				{:else if isRecording}
					<span class="mic-icon recording">⏹</span>
					<div class="audio-level" style="height: {audioLevel}%"></div>
				{:else}
					<span class="mic-icon">🎤</span>
				{/if}
			</button>
			<button
				class="send-button"
				onclick={sendMessage}
				disabled={!$currentInput.trim() || isRecording}
			>
				{#if $isProcessing}
					📬
				{:else}
					➤
				{/if}
			</button>
		</div>
	</div>

	<!-- ChatStatusBar entfernt (Phase 9): globale StatusBar in +layout uebernimmt -->
</div>

<!-- Quick-Actions Palette (Ctrl+K) -->
<QuickActions bind:visible={showQuickActions} onExecute={handleQuickAction} />

<!-- "Das merken" Dialog -->
{#if rememberDialogOpen}
	<div class="modal-backdrop" onclick={closeRememberDialog}>
		<div class="modal-dialog" onclick={(e) => e.stopPropagation()}>
			<div class="modal-header">
				<h3>💡 Das merken</h3>
				<button class="close-btn" onclick={closeRememberDialog}>✕</button>
			</div>
			<div class="modal-body">
				<div class="form-group">
					<label for="rem-title">Titel *</label>
					<input
						type="text"
						id="rem-title"
						bind:value={rememberEntry.title}
						placeholder="Kurze Beschreibung der Erkenntnis"
					/>
				</div>

				<div class="form-row">
					<div class="form-group">
						<label for="rem-category">Kategorie</label>
						<select id="rem-category" bind:value={rememberEntry.category}>
							{#each knowledgeCategories as cat}
								<option value={cat.id}>{cat.label}</option>
							{/each}
						</select>
					</div>
					<div class="form-group">
						<label for="rem-priority">Priorität</label>
						<select id="rem-priority" bind:value={rememberEntry.priority}>
							<option value={1}>1 - Kritisch</option>
							<option value={2}>2 - Wichtig</option>
							<option value={3}>3 - Normal</option>
							<option value={4}>4 - Niedrig</option>
						</select>
					</div>
				</div>

				<div class="form-group">
					<label for="rem-tags">Tags (kommagetrennt)</label>
					<input
						type="text"
						id="rem-tags"
						bind:value={rememberEntry.tags}
						placeholder="z.B. rust, tauri, async"
					/>
				</div>

				<div class="form-group">
					<label for="rem-content">Inhalt *</label>
					<textarea
						id="rem-content"
						bind:value={rememberContent}
						rows="8"
						placeholder="Der zu merkende Inhalt..."
					></textarea>
				</div>

				{#if rememberError}
					<div class="form-error">{rememberError}</div>
				{/if}
			</div>
			<div class="modal-footer">
				<button class="btn-secondary" onclick={closeRememberDialog}>Abbrechen</button>
				<button
					class="btn-primary"
					onclick={saveToKnowledge}
					disabled={rememberSaving || !rememberEntry.title.trim()}
				>
					{rememberSaving ? 'Speichern...' : 'In Wissensbasis speichern'}
				</button>
			</div>
		</div>
	</div>
{/if}

<!-- Compacting-Warnung Dialog -->
{#if showCompactingDialog}
	<div class="modal-backdrop" onclick={dismissCompactingDialog}>
		<div class="modal-dialog compact-dialog" onclick={(e) => e.stopPropagation()}>
			<div class="modal-header warning">
				<h3>⚠️ Hohe Token-Anzahl</h3>
				<button class="close-btn" onclick={dismissCompactingDialog}>✕</button>
			</div>
			<div class="modal-body">
				<p class="warning-text">
					Diese Konversation hat bereits <strong>~{(estimatedTokens / 1000).toFixed(0)}k Token</strong>.
				</p>
				<p>
					Um Kosten zu sparen und das Context-Limit nicht zu überschreiten, kannst du ältere Nachrichten zusammenfassen lassen.
				</p>
				<div class="compact-info">
					<div class="info-row">
						<span>Aktuelle Nachrichten:</span>
						<strong>{$messages.length}</strong>
					</div>
					<div class="info-row">
						<span>Nach Compacting behalten:</span>
						<strong>{KEEP_LAST_MESSAGES} neueste</strong>
					</div>
					<div class="info-row">
						<span>Geschätzte Token danach:</span>
						<strong>~{Math.ceil(estimatedTokens * (KEEP_LAST_MESSAGES / $messages.length) / 1000)}k</strong>
					</div>
				</div>
				<p class="hint">
					Die älteren Nachrichten werden zu einer Zusammenfassung komprimiert, bleiben aber in der Datenbank erhalten.
				</p>
			</div>
			<div class="modal-footer">
				<button class="btn-secondary" onclick={dismissCompactingDialog}>Später</button>
				<button class="btn-primary" onclick={performCompacting}>
					📦 Jetzt kompaktieren
				</button>
			</div>
		</div>
	</div>
{/if}

<style>
	.chat-panel {
		display: flex;
		flex-direction: column;
		height: 100%;
		min-height: 0; /* Flex-Kinder korrekt begrenzen (WebKitGTK) */
	}

	.chat-toolbar {
		display: flex;
		justify-content: flex-end;
		align-items: center;
		padding: var(--sp-1) var(--sp-3);
		background: var(--bg-secondary);
		border-bottom: 1px solid var(--border);
		min-height: 28px;
		gap: var(--sp-1);
	}

	.tool-btn {
		display: inline-flex;
		align-items: center;
		justify-content: center;
		width: 22px;
		height: 22px;
		border-radius: var(--r-sm);
		color: var(--text-secondary);
		background: transparent;
		font-size: 14px;
		line-height: 1;
		border: 0;
		cursor: pointer;
		transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
	}
	.tool-btn:hover {
		background: var(--bg-hover);
		color: var(--text-primary);
	}

	.token-count {
		font-size: 0.625rem;
		padding: 0.15rem 0.4rem;
		border-radius: var(--radius-sm);
		background: var(--bg-tertiary);
		color: var(--success);
		font-weight: 500;
	}

	.token-count.warning {
		background: rgba(234, 179, 8, 0.15);
		color: var(--status-warning);
	}

	.token-count.danger {
		background: rgba(239, 68, 68, 0.15);
		color: var(--error);
	}

	.detach-btn {
		padding: 0.2rem 0.45rem;
		background: var(--bg-tertiary, #2a2a3e);
		border: 1px solid var(--border, #333);
		border-radius: var(--radius-sm, 4px);
		color: var(--text-secondary, #aaa);
		cursor: pointer;
		font-size: 0.85rem;
		line-height: 1;
		transition: all 0.15s ease;
	}

	.detach-btn:hover {
		background: var(--accent, #6c8aff);
		color: white;
		border-color: var(--accent, #6c8aff);
	}

	.chat-messages-wrap {
		flex: 1;
		min-height: 0;
		display: flex;
		flex-direction: column;
		position: relative;       /* fuer Back-to-Bottom-Button absolute */
		background: var(--vscode-editor-background);
	}

	.edit-overlay {
		padding: 8px 12px;
		background: var(--vscode-sideBar-background);
		border-top: 1px solid var(--vscode-input-border);
		display: flex;
		flex-direction: column;
		gap: 6px;
	}

	.edit-textarea {
		width: 100%;
		font-family: var(--font-mono);
		font-size: 12.5px;
		background: var(--vscode-input-background);
		color: var(--vscode-input-foreground);
		border: 1px solid var(--vscode-focusBorder);
		border-radius: 3px;
		padding: 6px 8px;
		resize: vertical;
	}

	.edit-actions {
		display: flex;
		justify-content: flex-end;
		gap: 6px;
	}

	.edit-btn {
		font-size: 11.5px;
		padding: 4px 10px;
		border-radius: 2px;
	}
	.edit-btn.cancel {
		background: var(--vscode-button-secondaryBackground);
		color: var(--vscode-button-foreground);
	}
	.edit-btn.cancel:hover { background: var(--vscode-button-secondaryHoverBackground); }
	.edit-btn.confirm {
		background: var(--vscode-button-background);
		color: var(--vscode-button-foreground);
	}
	.edit-btn.confirm:hover { background: var(--vscode-button-hoverBackground); }
	.edit-btn:disabled { opacity: 0.5; cursor: not-allowed; }

	.empty-state {
		display: flex;
		flex-direction: column;
		align-items: center;
		justify-content: center;
		height: 100%;
		color: var(--text-secondary);
		text-align: center;
	}

	.empty-icon {
		font-size: 3rem;
		margin-bottom: var(--spacing-md);
		opacity: 0.5;
	}

	.empty-state .hint {
		font-size: 0.75rem;
		margin-top: var(--spacing-sm);
		color: var(--text-secondary);
		opacity: 0.7;
	}

	.message {
		padding: var(--spacing-sm) var(--spacing-md);
		border-radius: var(--radius-md);
		background: var(--bg-secondary);
		max-width: 85%;
	}

	.message.user {
		background: var(--bg-tertiary);
		margin-left: auto;
	}

	.message.queued {
		opacity: 0.6;
		border-left: 3px solid var(--accent);
		animation: pulse-queued 2s ease-in-out infinite;
	}

	@keyframes pulse-queued {
		0%, 100% { opacity: 0.6; }
		50% { opacity: 0.8; }
	}

	.message.assistant {
		margin-right: auto;
	}

	.message.system {
		background: rgba(233, 69, 96, 0.1);
		border-left: 3px solid var(--accent);
		max-width: 100%;
	}

	.message-header {
		display: flex;
		justify-content: space-between;
		align-items: center;
		margin-bottom: var(--spacing-xs);
	}

	.message-role {
		font-size: 0.7rem;
		font-weight: 600;
		display: flex;
		align-items: center;
		gap: 0.35rem;
	}

	.role-dot {
		width: 6px;
		height: 6px;
		border-radius: 50%;
		display: inline-block;
		flex-shrink: 0;
	}

	.role-dot.user {
		background: var(--accent, #6c8aff);
	}

	.role-dot.assistant {
		background: var(--accent);
		box-shadow: 0 0 6px rgba(167, 139, 250, 0.4);
	}

	.role-dot.system {
		background: var(--text-secondary, #888);
	}

	.role-dot.queued {
		background: var(--status-warning);
		animation: pulse-dot 1.5s infinite;
	}

	@keyframes pulse-dot {
		0%, 100% { opacity: 1; transform: scale(1); }
		50% { opacity: 0.5; transform: scale(0.7); }
	}

	.role-tag {
		font-size: 0.55rem;
		padding: 0.1rem 0.35rem;
		border-radius: 3px;
		background: rgba(245, 158, 11, 0.15);
		color: var(--status-warning);
		font-weight: 500;
	}

	.message-actions {
		display: flex;
		align-items: center;
		gap: var(--spacing-xs);
	}

	.action-btn {
		padding: 0.15rem 0.3rem;
		background: transparent;
		border: none;
		border-radius: var(--radius-sm);
		cursor: pointer;
		opacity: 0;
		transition: all 0.15s ease;
		font-size: 0.7rem;
	}

	.message:hover .action-btn {
		opacity: 0.6;
	}

	.action-btn:hover {
		opacity: 1 !important;
		background: var(--bg-tertiary);
	}

	.message-time {
		font-size: 0.6rem;
		color: var(--text-secondary);
		margin-left: 0.5rem;
		font-variant-numeric: tabular-nums;
	}

	/* Edit-Modus */
	.message.editing {
		border: 1px solid var(--accent);
	}

	.edit-textarea {
		width: 100%;
		min-height: 60px;
		padding: var(--spacing-sm);
		font-size: 0.85rem;
		line-height: 1.5;
		background: var(--bg-primary);
		border: 1px solid var(--border);
		border-radius: var(--radius-sm);
		resize: vertical;
		font-family: inherit;
	}

	.edit-textarea:focus {
		outline: none;
		border-color: var(--accent);
	}

	.edit-actions {
		display: flex;
		justify-content: flex-end;
		gap: var(--spacing-sm);
		margin-top: var(--spacing-xs);
	}

	.edit-btn {
		padding: 0.3rem 0.75rem;
		font-size: 0.75rem;
		border-radius: var(--radius-sm);
		cursor: pointer;
		transition: all 0.15s ease;
	}

	.edit-btn.cancel {
		background: transparent;
		border: 1px solid var(--border);
		color: var(--text-secondary);
	}

	.edit-btn.cancel:hover {
		background: var(--bg-tertiary);
		color: var(--text-primary);
	}

	.edit-btn.confirm {
		background: var(--accent);
		border: 1px solid var(--accent);
		color: white;
	}

	.edit-btn.confirm:hover:not(:disabled) {
		background: var(--accent-hover);
	}

	.edit-btn.confirm:disabled {
		opacity: 0.5;
		cursor: not-allowed;
	}

	.message-content {
		font-size: 0.85rem;
		line-height: 1.6;
	}

	.msg-collapsed {
		overflow: hidden;
	}

	.expand-btn {
		display: block;
		width: 100%;
		padding: 0.35rem;
		margin-top: 0.3rem;
		background: var(--bg-tertiary, #2a2a2a);
		border: 1px solid var(--border, #3a3a3a);
		border-radius: 4px;
		color: var(--accent, #6aa3ff);
		font-size: 0.75rem;
		cursor: pointer;
		text-align: center;
		transition: background 0.15s;
	}

	.expand-btn:hover {
		background: var(--bg-hover, #333);
	}

	/* Thinking-Inline — kompakte, immer sichtbare Denkbloecke */
	.message-content :global(.thinking-inline) {
		display: flex;
		align-items: flex-start;
		gap: 0.4rem;
		padding: 0.4rem 0.6rem;
		margin: 0.3rem 0;
		background: rgba(99, 102, 241, 0.06);
		border-left: 2px solid rgba(99, 102, 241, 0.3);
		border-radius: 0 4px 4px 0;
		font-size: 0.72rem;
		line-height: 1.4;
		color: var(--text-secondary, #9ca3af);
	}

	.message-content :global(.thinking-label) {
		flex-shrink: 0;
		font-size: 0.7rem;
	}

	.message-content :global(.thinking-text) {
		white-space: pre-wrap;
		word-break: break-word;
		font-family: inherit;
		max-height: 200px;
		overflow-y: auto;
	}

	.message-content :global(.thinking-text::-webkit-scrollbar) {
		width: 4px;
	}

	.message-content :global(.thinking-text::-webkit-scrollbar-thumb) {
		background: #374151;
		border-radius: 2px;
	}

	/* Aktivitätsanzeige — kompakte Zeile mit Icon, Label und Dots */
	.activity-indicator {
		display: flex;
		align-items: center;
		gap: 0.5rem;
		padding: 0.3rem 0;
		margin: 0.2rem 0;
		font-size: 0.78rem;
		color: var(--text-secondary, #9ca3af);
		animation: fadeInActivity 0.25s ease;
	}

	.activity-icon {
		font-size: 0.85rem;
		flex-shrink: 0;
	}

	.activity-label {
		font-family: var(--font-mono, monospace);
		font-size: 0.72rem;
		opacity: 0.85;
		white-space: nowrap;
		overflow: hidden;
		text-overflow: ellipsis;
		max-width: 280px;
	}

	.activity-dots {
		display: inline-flex;
		gap: 3px;
		margin-left: 2px;
		flex-shrink: 0;
	}

	.activity-dot {
		width: 4px;
		height: 4px;
		background: currentColor;
		border-radius: 50%;
		opacity: 0.5;
		animation: dotPulse 1.2s infinite ease-in-out;
	}

	.activity-dot:nth-child(1) { animation-delay: 0s; }
	.activity-dot:nth-child(2) { animation-delay: 0.2s; }
	.activity-dot:nth-child(3) { animation-delay: 0.4s; }

	@keyframes dotPulse {
		0%, 60%, 100% { opacity: 0.3; transform: scale(1); }
		30% { opacity: 1; transform: scale(1.3); }
	}

	@keyframes fadeInActivity {
		from { opacity: 0; transform: translateY(-3px); }
		to { opacity: 1; transform: translateY(0); }
	}

	/* Markdown-Styles innerhalb von Nachrichten */
	.message-content :global(p) {
		margin: 0.3em 0;
	}

	.message-content :global(p:first-child) {
		margin-top: 0;
	}

	.message-content :global(p:last-child) {
		margin-bottom: 0;
	}

	.message-content :global(code) {
		font-family: var(--font-mono);
		font-size: 0.8rem;
		padding: 0.1em 0.35em;
		background: var(--bg-tertiary);
		border-radius: var(--radius-sm);
	}

	/* Code-Block mit Header und Copy-Button */
	.message-content :global(.code-block-wrapper) {
		margin: 0.5em 0;
		border-radius: var(--radius-md);
		background: var(--bg-tertiary);
		overflow: hidden;
	}

	.message-content :global(.code-header) {
		display: flex;
		justify-content: space-between;
		align-items: center;
		padding: 0.3rem 0.75rem;
		background: rgba(0, 0, 0, 0.15);
		font-size: 0.65rem;
		gap: 0.5rem;
	}

	.message-content :global(.code-lang) {
		color: var(--text-secondary);
		font-family: var(--font-mono);
		text-transform: uppercase;
		letter-spacing: 0.5px;
	}

	.message-content :global(.copy-btn) {
		margin-left: auto;
		padding: 0.2rem 0.5rem;
		background: transparent;
		border: 1px solid var(--border);
		border-radius: var(--radius-sm);
		color: var(--text-secondary);
		font-size: 0.7rem;
		cursor: pointer;
		transition: all 0.15s ease;
	}

	.message-content :global(.copy-btn:hover) {
		background: var(--bg-secondary);
		color: var(--text-primary);
		border-color: var(--text-secondary);
	}

	.message-content :global(.copy-btn .copied) {
		color: var(--success);
	}

	.message-content :global(.code-block-wrapper pre) {
		margin: 0;
		padding: var(--spacing-sm) var(--spacing-md);
		overflow-x: auto;
		font-size: 0.75rem;
		line-height: 1.5;
	}

	.message-content :global(.code-block-wrapper pre code) {
		padding: 0;
		background: none;
	}

	/* Fallback für inline pre (ohne wrapper) */
	.message-content :global(pre:not(.code-block-wrapper pre)) {
		margin: 0.5em 0;
		padding: var(--spacing-sm) var(--spacing-md);
		background: var(--bg-tertiary);
		border-radius: var(--radius-md);
		overflow-x: auto;
		font-size: 0.75rem;
		line-height: 1.4;
	}

	.message-content :global(pre:not(.code-block-wrapper pre) code) {
		padding: 0;
		background: none;
	}

	.message-content :global(ul), .message-content :global(ol) {
		margin: 0.3em 0;
		padding-left: 1.5em;
	}

	.message-content :global(li) {
		margin: 0.15em 0;
	}

	.message-content :global(strong) {
		color: var(--text-primary);
	}

	.message-content :global(a) {
		color: var(--accent);
		text-decoration: none;
	}

	.message-content :global(a:hover) {
		text-decoration: underline;
	}

	.message-content :global(blockquote) {
		border-left: 3px solid var(--bg-tertiary);
		padding-left: var(--spacing-sm);
		margin: 0.3em 0;
		color: var(--text-secondary);
	}

	.message-content :global(h1), .message-content :global(h2), .message-content :global(h3) {
		margin: 0.5em 0 0.2em;
		font-size: 0.9rem;
	}

	.message-content :global(table) {
		border-collapse: collapse;
		margin: 0.3em 0;
		font-size: 0.75rem;
		width: 100%;
	}

	.message-content :global(th), .message-content :global(td) {
		border: 1px solid var(--bg-tertiary);
		padding: 0.3em 0.5em;
	}

	.message-content :global(th) {
		background: var(--bg-secondary);
		font-weight: 600;
	}

	/* Alte Typing-Animation entfernt — ersetzt durch .activity-indicator */

	/* Input-Bereich */
	/* Pending Changes (Accept/Reject DiffView) */
	.pending-changes {
		border-top: 2px solid var(--accent);
		background: var(--bg-secondary);
		max-height: 300px;
		overflow-y: auto;
		flex-shrink: 0;
	}

	.pending-changes-header {
		display: flex;
		justify-content: space-between;
		align-items: center;
		padding: var(--spacing-xs) var(--spacing-sm);
		font-size: 0.7rem;
		color: var(--text-secondary);
		border-bottom: 1px solid var(--border);
	}

	.btn-accept-all {
		padding: 2px 8px;
		font-size: 0.6rem;
		background: rgba(34, 197, 94, 0.15);
		border: 1px solid var(--success);
		border-radius: var(--radius-sm);
		color: var(--success);
		cursor: pointer;
		font-weight: 600;
	}

	.btn-accept-all:hover {
		background: var(--success);
		color: white;
	}

	.chat-input {
		display: flex;
		gap: var(--spacing-sm);
		padding: var(--spacing-sm) var(--spacing-md);
		background: var(--bg-secondary);
		border-top: 1px solid var(--bg-tertiary);
		position: relative;
		flex-shrink: 0;      /* Nicht schrumpfen — Eingabe bleibt immer sichtbar */
		max-height: 160px;   /* Puffer für mehrzeilige Eingabe */
	}

	.chat-input textarea {
		flex: 1;
		resize: none;
		font-size: 0.85rem;
		line-height: 1.4;
		max-height: 120px;   /* Max ~6 Zeilen, dann scrollen */
		overflow-y: auto;
	}

	/* Phase 11: Toggle-Spalte links vom Textfeld (Approval-Modus). */
	.input-prefix {
		display: flex;
		flex-direction: column;
		gap: var(--spacing-xs);
		align-self: flex-end;
	}
	.perm-toggle {
		width: 36px;
		height: 48px;
		display: flex;
		align-items: center;
		justify-content: center;
		background: var(--bg-secondary);
		border: 1px solid var(--border);
		border-radius: var(--radius-md);
		font-size: 1.15rem;
		cursor: pointer;
		transition: all 0.18s ease;
	}
	.perm-toggle:hover {
		background: var(--bg-tertiary);
	}
	.perm-toggle.active {
		background: rgba(0, 122, 204, 0.15);
		border-color: var(--accent, #007acc);
		box-shadow: 0 0 0 1px var(--accent, #007acc);
	}
	.perm-toggle.yolo {
		background: rgba(244, 135, 113, 0.18);
		border-color: var(--status-error, #f48771);
		box-shadow: 0 0 0 1px var(--status-error, #f48771), 0 0 12px rgba(244, 135, 113, 0.35);
		animation: yolo-pulse 1.6s ease-in-out infinite;
	}
	@keyframes yolo-pulse {
		0%, 100% { box-shadow: 0 0 0 1px var(--status-error, #f48771), 0 0 12px rgba(244, 135, 113, 0.30); }
		50%      { box-shadow: 0 0 0 1px var(--status-error, #f48771), 0 0 20px rgba(244, 135, 113, 0.55); }
	}

	.send-button {
		width: 48px;
		height: 48px;
		display: flex;
		align-items: center;
		justify-content: center;
		background: var(--accent);
		color: white;
		font-size: 1.2rem;
		font-weight: 600;
		border-radius: var(--radius-md);
		transition: all 0.2s ease;
		align-self: flex-end;
	}

	.send-button:hover:not(:disabled) {
		background: var(--accent-hover);
		transform: scale(1.05);
	}

	.send-button:disabled {
		background: var(--bg-tertiary);
		color: var(--text-secondary);
		cursor: not-allowed;
		transform: none;
	}

	/* Voice Interface */
	.input-buttons {
		display: flex;
		flex-direction: column;
		gap: var(--spacing-xs);
	}

	.mic-button {
		width: 48px;
		height: 48px;
		display: flex;
		align-items: center;
		justify-content: center;
		background: var(--bg-secondary);
		border: 1px solid var(--border);
		border-radius: var(--radius-md);
		font-size: 1.25rem;
		cursor: pointer;
		transition: all 0.2s ease;
		position: relative;
		overflow: hidden;
	}

	.mic-button:hover:not(:disabled) {
		background: var(--bg-tertiary);
		border-color: var(--accent);
	}

	.mic-button.recording {
		background: rgba(239, 68, 68, 0.15);
		border-color: var(--status-error);
		animation: pulse-recording 1.5s ease-in-out infinite;
	}

	.mic-button.conversation {
		background: rgba(124, 140, 255, 0.18);
		border-color: var(--accent, #7c8cff);
		animation: pulse-conversation 1.6s ease-in-out infinite;
	}

	@keyframes pulse-recording {
		0%, 100% { box-shadow: 0 0 0 0 rgba(239, 68, 68, 0.4); }
		50% { box-shadow: 0 0 0 8px rgba(239, 68, 68, 0); }
	}
	@keyframes pulse-conversation {
		0%, 100% { box-shadow: 0 0 0 0 rgba(124, 140, 255, 0.45); }
		50%      { box-shadow: 0 0 0 10px rgba(124, 140, 255, 0); }
	}

	.mic-icon {
		z-index: 1;
	}

	.mic-icon.recording {
		color: var(--status-error);
	}

	.audio-level {
		position: absolute;
		bottom: 0;
		left: 0;
		right: 0;
		background: linear-gradient(to top, rgba(239, 68, 68, 0.4), rgba(239, 68, 68, 0.1));
		transition: height 0.05s ease-out;
		pointer-events: none;
	}

	.mic-button:disabled {
		opacity: 0.5;
		cursor: not-allowed;
	}

	.live-transcript {
		position: absolute;
		top: -32px;
		left: 0;
		right: 0;
		display: flex;
		align-items: center;
		gap: var(--spacing-xs);
		padding: var(--spacing-xs) var(--spacing-sm);
		background: rgba(239, 68, 68, 0.1);
		border: 1px solid rgba(239, 68, 68, 0.3);
		border-radius: var(--radius-sm);
		font-size: 0.75rem;
		color: var(--status-error);
	}

	/* Modus-Anzeige im Eingabebereich */
	.mode-indicator {
		display: flex;
		align-items: center;
		gap: var(--spacing-xs);
		padding: 4px var(--spacing-sm);
		margin-bottom: var(--spacing-xs);
		border-radius: var(--radius-sm);
		font-size: 0.72rem;
		font-weight: 600;
		letter-spacing: 0.02em;
		animation: mode-fade-in 0.3s ease;
	}

	@keyframes mode-fade-in {
		from { opacity: 0; transform: translateY(4px); }
		to { opacity: 1; transform: translateY(0); }
	}

	.mode-indicator.mode-handlanger {
		background: rgba(245, 158, 11, 0.12);
		border: 1px solid rgba(245, 158, 11, 0.3);
		color: #fbbf24;
	}

	.mode-indicator.mode-experten {
		background: rgba(139, 92, 246, 0.12);
		border: 1px solid rgba(139, 92, 246, 0.3);
		color: var(--accent);
	}

	.mode-indicator.mode-auto {
		background: rgba(34, 197, 94, 0.12);
		border: 1px solid rgba(34, 197, 94, 0.3);
		color: #4ade80;
	}

	.mode-icon {
		flex-shrink: 0;
		font-size: 0.8rem;
	}

	.mode-label {
		flex-shrink: 0;
	}

	.mode-phase {
		opacity: 0.7;
		font-weight: 400;
	}

	.queued-pill {
		display: flex;
		align-items: center;
		gap: var(--spacing-xs);
		padding: var(--spacing-xs) var(--spacing-sm);
		margin-bottom: var(--spacing-xs);
		background: rgba(96, 165, 250, 0.08);
		border: 1px solid rgba(96, 165, 250, 0.25);
		border-radius: var(--radius-sm);
		font-size: 0.75rem;
		color: #93c5fd;
	}

	.queued-icon {
		flex-shrink: 0;
	}

	.queued-text {
		flex: 1;
		overflow: hidden;
		text-overflow: ellipsis;
		white-space: nowrap;
	}

	.queued-cancel {
		background: none;
		border: none;
		color: inherit;
		cursor: pointer;
		font-size: 0.9rem;
		padding: 0 4px;
		opacity: 0.7;
	}

	.queued-cancel:hover {
		opacity: 1;
	}

	.transcript-icon {
		animation: pulse 1s ease-in-out infinite;
	}

	@keyframes pulse {
		0%, 100% { opacity: 1; }
		50% { opacity: 0.5; }
	}

	.transcript-text {
		flex: 1;
		overflow: hidden;
		text-overflow: ellipsis;
		white-space: nowrap;
	}

	/* Modal Styles */
	.modal-backdrop {
		position: fixed;
		top: 0;
		left: 0;
		right: 0;
		bottom: 0;
		background: rgba(0, 0, 0, 0.6);
		display: flex;
		align-items: center;
		justify-content: center;
		z-index: 1000;
	}

	.modal-dialog {
		background: var(--bg-primary);
		border-radius: var(--radius-md);
		width: 90%;
		max-width: 500px;
		max-height: 85vh;
		overflow: hidden;
		display: flex;
		flex-direction: column;
		box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
	}

	.modal-header {
		display: flex;
		justify-content: space-between;
		align-items: center;
		padding: var(--spacing-md);
		background: var(--bg-secondary);
		border-bottom: 1px solid var(--border);
	}

	.modal-header h3 {
		margin: 0;
		font-size: 0.9rem;
	}

	.close-btn {
		width: 28px;
		height: 28px;
		display: flex;
		align-items: center;
		justify-content: center;
		background: transparent;
		border: none;
		border-radius: var(--radius-sm);
		cursor: pointer;
		color: var(--text-secondary);
		font-size: 1rem;
	}

	.close-btn:hover {
		background: var(--bg-tertiary);
		color: var(--text-primary);
	}

	.modal-body {
		padding: var(--spacing-md);
		overflow-y: auto;
		flex: 1;
	}

	.form-group {
		margin-bottom: var(--spacing-sm);
	}

	.form-group label {
		display: block;
		font-size: 0.75rem;
		font-weight: 500;
		color: var(--text-secondary);
		margin-bottom: 0.25rem;
	}

	.form-group input,
	.form-group select,
	.form-group textarea {
		width: 100%;
		padding: 0.5rem;
		font-size: 0.85rem;
		background: var(--bg-secondary);
		border: 1px solid var(--border);
		border-radius: var(--radius-sm);
		color: var(--text-primary);
	}

	.form-group textarea {
		resize: vertical;
		font-family: var(--font-mono);
		font-size: 0.75rem;
		line-height: 1.5;
	}

	.form-group input:focus,
	.form-group select:focus,
	.form-group textarea:focus {
		outline: none;
		border-color: var(--accent);
	}

	.form-row {
		display: grid;
		grid-template-columns: 1fr 1fr;
		gap: var(--spacing-sm);
	}

	.form-error {
		padding: 0.5rem;
		background: rgba(239, 68, 68, 0.1);
		border: 1px solid var(--error);
		border-radius: var(--radius-sm);
		color: var(--error);
		font-size: 0.75rem;
		margin-top: var(--spacing-sm);
	}

	.modal-footer {
		display: flex;
		justify-content: flex-end;
		gap: var(--spacing-sm);
		padding: var(--spacing-md);
		background: var(--bg-secondary);
		border-top: 1px solid var(--border);
	}

	.btn-secondary {
		padding: 0.5rem 1rem;
		font-size: 0.8rem;
		background: transparent;
		border: 1px solid var(--border);
		border-radius: var(--radius-sm);
		color: var(--text-secondary);
		cursor: pointer;
	}

	.btn-secondary:hover {
		background: var(--bg-tertiary);
		color: var(--text-primary);
	}

	.btn-primary {
		padding: 0.5rem 1rem;
		font-size: 0.8rem;
		background: var(--accent);
		border: 1px solid var(--accent);
		border-radius: var(--radius-sm);
		color: white;
		cursor: pointer;
	}

	.btn-primary:hover:not(:disabled) {
		background: var(--accent-hover);
	}

	.btn-primary:disabled {
		opacity: 0.5;
		cursor: not-allowed;
	}

	/* Compacting Dialog */
	.compact-dialog {
		max-width: 420px;
	}

	.modal-header.warning {
		background: rgba(234, 179, 8, 0.15);
		border-bottom-color: rgba(234, 179, 8, 0.3);
	}

	.modal-header.warning h3 {
		color: var(--status-warning);
	}

	.warning-text {
		font-size: 1rem;
		margin-bottom: var(--spacing-sm);
	}

	.compact-info {
		background: var(--bg-secondary);
		border-radius: var(--radius-sm);
		padding: var(--spacing-sm);
		margin: var(--spacing-sm) 0;
	}

	.info-row {
		display: flex;
		justify-content: space-between;
		padding: 0.25rem 0;
		font-size: 0.8rem;
	}

	.info-row span {
		color: var(--text-secondary);
	}

	.modal-body .hint {
		font-size: 0.75rem;
		color: var(--text-secondary);
		margin-top: var(--spacing-sm);
	}

	/* File-Drop Overlay */
	.chat-panel.drag-over {
		outline: 2px dashed var(--accent);
		outline-offset: -2px;
	}

	.drop-overlay {
		position: absolute;
		inset: 0;
		z-index: 50;
		display: flex;
		flex-direction: column;
		align-items: center;
		justify-content: center;
		gap: 8px;
		background: rgba(124, 58, 237, 0.12);
		backdrop-filter: blur(4px);
		border-radius: inherit;
		pointer-events: none;
	}

	.drop-icon {
		font-size: 3rem;
		animation: dropBounce 0.5s ease;
	}

	@keyframes dropBounce {
		0% { transform: scale(0.5); opacity: 0; }
		60% { transform: scale(1.2); }
		100% { transform: scale(1); opacity: 1; }
	}

	.drop-overlay p {
		margin: 0;
		font-size: 1rem;
		font-weight: 600;
		color: var(--accent);
	}

	.drop-hint {
		font-size: 0.75rem !important;
		font-weight: 400 !important;
		color: var(--text-secondary) !important;
	}
</style>
