<script lang="ts">
	import type { PageData } from './$types';

	let { data } = $props<{ data: PageData }>();

	interface Alias {
		id: string;
		alias: string;
		description: string | null;
		is_active: boolean;
	}

	interface Provider {
		id: string;
		alias_id: string;
		priority: number;
		litellm_model: string;
		api_key_env: string;
		is_active: boolean;
		extra_params: Record<string, unknown> | null;
	}

	interface Route {
		job_type: string;
		alias_id: string;
		alias: string;
		description: string | null;
	}

	interface Prompt {
		action: string;
		system_prompt: string;
		description: string | null;
		label: string | null;
		icon: string | null;
		sort_order: number;
		updated_at: string;
	}

	interface UsageRow {
		model_alias: string;
		model_actual: string | null;
		action: string | null;
		call_count: number;
		prompt_tokens: number;
		completion_tokens: number;
		total_tokens: number;
	}

	interface CatalogModel {
		id: string;
		name: string;
		provider: string;
		litellm_prefix: string;
		api_key_env: string;
		context_length: number;
		prompt_price_per_m: number;
		completion_price_per_m: number;
		modality: string;
		max_completion: number | null;
	}

	interface ApiKey {
		name: string;
		label: string;
		configured: boolean;
		has_db_value: boolean;
		is_enabled: boolean;
	}

	let aliases = $state<Alias[]>(data.aliases as Alias[]);
	let providers = $state<Provider[]>(data.providers as Provider[]);
	let routing = $state<Route[]>(data.routing as Route[]);
	let prompts = $state<Prompt[]>(data.prompts as Prompt[]);
	let usage = $state<UsageRow[]>(data.usage as UsageRow[]);

	let saving = $state<string | null>(null);
	let saved = $state<string | null>(null);
	let errorMsg = $state('');
	let configMsg = $state('');
	let editingPrompt = $state<string | null>(null);
	let editPromptText = $state('');
	let editPromptLabel = $state('');
	let editPromptIcon = $state('');
	let expandedAlias = $state<string | null>(null);

	// Alias-redigering
	let editingAlias = $state<string | null>(null);
	let editAliasName = $state('');
	let editAliasDesc = $state('');

	// API-nøkler
	let apiKeys = $state<ApiKey[]>([]);
	let keysLoaded = $state(false);
	let expandedKey = $state<string | null>(null);
	let keyValueInput = $state('');
	let newKey = $state({ env_name: '', label: '', key_value: '' });

	// Modellkatalog
	let catalogModels = $state<CatalogModel[]>([]);
	let catalogLoading = $state(false);
	let catalogLoaded = $state(false);
	let catalogSearch = $state('');
	let expandedProviders = $state<Set<string>>(new Set());
	let addingFromCatalog = $state<string | null>(null);
	let catalogAddAlias = $state('');

	// Katalog-picker i add-provider-form
	let showCatalogPicker = $state(false);
	let catalogPickerSearch = $state('');

	// Extra params redigering
	let editingExtraParams = $state<string | null>(null);
	let editExtraParamsText = $state('');

	// Ny provider-form
	let newProvider = $state<{ alias_id: string; litellm_model: string; api_key_env: string }>({
		alias_id: '',
		litellm_model: '',
		api_key_env: 'OPENROUTER_API_KEY'
	});

	// Ny alias-form
	let newAlias = $state({ alias: '', description: '' });

	// Ny ruting-form
	let newRoute = $state({ job_type: '', alias_id: '', description: '' });

	function providersForAlias(aliasId: string): Provider[] {
		return providers.filter((p) => p.alias_id === aliasId).sort((a, b) => a.priority - b.priority);
	}

	function markSaved(id: string) {
		saved = id;
		setTimeout(() => {
			if (saved === id) saved = null;
		}, 2000);
	}

	function formatCtx(n: number): string {
		if (n >= 1_000_000) return `${(n / 1_000_000).toFixed(0)}M`;
		if (n >= 1000) return `${(n / 1000).toFixed(0)}K`;
		return String(n);
	}

	function formatPrice(n: number | null | undefined): string {
		if (n == null || n < 0) return '\u2014';
		if (n === 0) return '\u2014';
		return `$${n.toFixed(2)}`;
	}

	// API-nøkler
	async function loadKeys() {
		try {
			const res = await fetch('/api/admin/ai/keys');
			if (res.ok) {
				const data = await res.json();
				apiKeys = data.keys;
				keysLoaded = true;
			}
		} catch { /* stille */ }
	}
	loadKeys();

	async function toggleKey(key: ApiKey) {
		errorMsg = '';
		try {
			const res = await fetch('/api/admin/ai/keys', {
				method: 'PATCH',
				headers: { 'Content-Type': 'application/json' },
				body: JSON.stringify({ env_name: key.name, is_enabled: !key.is_enabled })
			});
			if (!res.ok) throw new Error('Feil ved lagring');
			const updated = await res.json();
			Object.assign(key, { is_enabled: updated.is_enabled, configured: updated.configured, has_db_value: updated.has_db_value });
			apiKeys = [...apiKeys];
		} catch {
			errorMsg = 'Kunne ikke oppdatere nøkkel-status';
		}
	}

	async function saveKeyValue(key: ApiKey) {
		errorMsg = '';
		try {
			const res = await fetch('/api/admin/ai/keys', {
				method: 'PATCH',
				headers: { 'Content-Type': 'application/json' },
				body: JSON.stringify({ env_name: key.name, key_value: keyValueInput })
			});
			if (!res.ok) throw new Error('Feil ved lagring');
			const updated = await res.json();
			Object.assign(key, { configured: updated.configured, has_db_value: updated.has_db_value, is_enabled: updated.is_enabled });
			apiKeys = [...apiKeys];
			keyValueInput = '';
			expandedKey = null;
			markSaved(key.name);
		} catch {
			errorMsg = 'Kunne ikke lagre nøkkelverdi';
		}
	}

	async function clearKeyValue(key: ApiKey) {
		errorMsg = '';
		try {
			const res = await fetch('/api/admin/ai/keys', {
				method: 'PATCH',
				headers: { 'Content-Type': 'application/json' },
				body: JSON.stringify({ env_name: key.name, key_value: '' })
			});
			if (!res.ok) throw new Error('Feil');
			const updated = await res.json();
			Object.assign(key, { configured: updated.configured, has_db_value: updated.has_db_value });
			apiKeys = [...apiKeys];
			markSaved(key.name);
		} catch {
			errorMsg = 'Kunne ikke fjerne nøkkelverdi';
		}
	}

	async function addKey() {
		errorMsg = '';
		if (!newKey.env_name || !newKey.label) return;
		try {
			const res = await fetch('/api/admin/ai/keys', {
				method: 'POST',
				headers: { 'Content-Type': 'application/json' },
				body: JSON.stringify(newKey)
			});
			if (!res.ok) {
				const data = await res.json();
				throw new Error(data.message || 'Feil');
			}
			const row = await res.json();
			apiKeys = [...apiKeys, row].sort((a, b) => a.label.localeCompare(b.label));
			newKey = { env_name: '', label: '', key_value: '' };
		} catch (e: any) {
			errorMsg = e.message || 'Kunne ikke legge til nøkkel';
		}
	}

	async function deleteKey(key: ApiKey) {
		errorMsg = '';
		try {
			const res = await fetch('/api/admin/ai/keys', {
				method: 'DELETE',
				headers: { 'Content-Type': 'application/json' },
				body: JSON.stringify({ env_name: key.name })
			});
			if (!res.ok) {
				const data = await res.json();
				throw new Error(data.message || 'Feil');
			}
			apiKeys = apiKeys.filter(k => k.name !== key.name);
		} catch (e: any) {
			errorMsg = e.message || 'Kunne ikke slette nøkkel';
		}
	}

	// Modellkatalog
	async function loadCatalog() {
		catalogLoading = true;
		errorMsg = '';
		try {
			const res = await fetch('/api/admin/ai/models?refresh=1');
			if (!res.ok) throw new Error('Kunne ikke hente modellkatalog');
			catalogModels = await res.json();
			catalogLoaded = true;
		} catch (e: any) {
			errorMsg = e.message;
		} finally {
			catalogLoading = false;
		}
	}

	// Grupper etter api_key_env + provider (f.eks. "google via GEMINI_API_KEY" vs "google via OPENROUTER_API_KEY")
	let groupedByProvider = $derived.by(() => {
		const search = catalogSearch.toLowerCase();
		const filtered = search
			? catalogModels.filter(
					(m) =>
						m.name.toLowerCase().includes(search) ||
						m.id.toLowerCase().includes(search) ||
						m.provider.toLowerCase().includes(search) ||
						m.api_key_env.toLowerCase().includes(search)
				)
			: catalogModels;

		const map = new Map<string, CatalogModel[]>();
		for (const m of filtered) {
			// Grupper per API-nøkkel, med provider som undergruppe
			const groupKey = m.api_key_env === 'OPENROUTER_API_KEY'
				? `${m.provider} (OpenRouter)`
				: m.provider;
			const list = map.get(groupKey) ?? [];
			list.push(m);
			map.set(groupKey, list);
		}

		// Sorter: pris synkende først (ukjent/-1 sist), deretter navn synkende
		for (const [, models] of map) {
			models.sort((a, b) => {
				const aPrice = a.completion_price_per_m;
				const bPrice = b.completion_price_per_m;
				const aHasPrice = aPrice > 0;
				const bHasPrice = bPrice > 0;
				if (aHasPrice !== bHasPrice) return aHasPrice ? -1 : 1;
				if (aPrice !== bPrice) return bPrice - aPrice;
				return b.name.localeCompare(a.name);
			});
		}

		// Direkte API-nøkler først, deretter OpenRouter-grupper
		return [...map.entries()].sort(([a], [b]) => {
			const aOr = a.includes('OpenRouter');
			const bOr = b.includes('OpenRouter');
			if (aOr !== bOr) return aOr ? 1 : -1;
			return a.localeCompare(b);
		});
	});

	let catalogPickerFiltered = $derived.by(() => {
		const search = catalogPickerSearch.toLowerCase();
		if (!search) return catalogModels.slice(0, 20);
		return catalogModels
			.filter(
				(m) =>
					m.name.toLowerCase().includes(search) ||
					m.id.toLowerCase().includes(search)
			)
			.slice(0, 20);
	});

	function toggleCatalogProvider(provider: string) {
		if (expandedProviders.has(provider)) {
			expandedProviders.delete(provider);
		} else {
			expandedProviders.add(provider);
		}
		expandedProviders = new Set(expandedProviders);
	}

	function litellmModelId(model: CatalogModel): string {
		return `${model.litellm_prefix}${model.id}`;
	}

	async function addFromCatalog(model: CatalogModel, aliasId: string) {
		errorMsg = '';
		const maxPri = Math.max(0, ...providersForAlias(aliasId).map((p) => p.priority));
		try {
			const res = await fetch('/api/admin/ai/providers', {
				method: 'POST',
				headers: { 'Content-Type': 'application/json' },
				body: JSON.stringify({
					alias_id: aliasId,
					priority: maxPri + 1,
					litellm_model: litellmModelId(model),
					api_key_env: model.api_key_env
				})
			});
			if (!res.ok) throw new Error('Feil ved opprettelse');
			const row = await res.json();
			providers = [...providers, row];
			addingFromCatalog = null;
			catalogAddAlias = '';
		} catch {
			errorMsg = 'Kunne ikke legge til provider fra katalog';
		}
	}

	function selectFromPicker(model: CatalogModel) {
		newProvider.litellm_model = litellmModelId(model);
		newProvider.api_key_env = model.api_key_env;
		showCatalogPicker = false;
		catalogPickerSearch = '';
	}

	async function toggleAlias(alias: Alias) {
		saving = alias.id;
		errorMsg = '';
		try {
			const res = await fetch(`/api/admin/ai/aliases/${alias.id}`, {
				method: 'PATCH',
				headers: { 'Content-Type': 'application/json' },
				body: JSON.stringify({ is_active: !alias.is_active })
			});
			if (!res.ok) throw new Error('Feil ved lagring');
			const updated = await res.json();
			alias.is_active = updated.is_active;
			markSaved(alias.id);
		} catch {
			errorMsg = 'Kunne ikke oppdatere alias';
		} finally {
			saving = null;
		}
	}

	function startEditAlias(alias: Alias) {
		editingAlias = alias.id;
		editAliasName = alias.alias;
		editAliasDesc = alias.description ?? '';
	}

	function cancelEditAlias() {
		editingAlias = null;
		editAliasName = '';
		editAliasDesc = '';
	}

	async function saveAlias(alias: Alias) {
		saving = alias.id;
		errorMsg = '';
		try {
			const res = await fetch(`/api/admin/ai/aliases/${alias.id}`, {
				method: 'PATCH',
				headers: { 'Content-Type': 'application/json' },
				body: JSON.stringify({ alias: editAliasName, description: editAliasDesc || null })
			});
			if (!res.ok) throw new Error('Feil ved lagring');
			const updated = await res.json();
			alias.alias = updated.alias;
			alias.description = updated.description;
			editingAlias = null;
			markSaved(alias.id);
		} catch {
			errorMsg = 'Kunne ikke oppdatere alias';
		} finally {
			saving = null;
		}
	}

	function estimateCost(row: UsageRow): number | null {
		if (!catalogLoaded || !row.model_actual) return null;
		// model_actual kan være "xai/grok-..." eller "google/gemma-..." — match mot id eller litellm_prefix+id
		const actual = row.model_actual;
		const model = catalogModels.find((m) =>
			m.id === actual || `${m.litellm_prefix}${m.id}` === actual || `${m.provider}/${m.id}` === actual
		);
		if (!model || model.prompt_price_per_m < 0 || model.completion_price_per_m < 0) return null;
		return (
			(row.prompt_tokens / 1_000_000) * model.prompt_price_per_m +
			(row.completion_tokens / 1_000_000) * model.completion_price_per_m
		);
	}

	let totalEstimatedCost = $derived.by(() => {
		if (!catalogLoaded) return null;
		let total = 0;
		let hasAny = false;
		for (const row of usage) {
			const cost = estimateCost(row);
			if (cost !== null) {
				total += cost;
				hasAny = true;
			}
		}
		return hasAny ? total : null;
	});

	function hasWebPlugin(provider: Provider): boolean {
		const plugins = provider.extra_params?.plugins;
		return Array.isArray(plugins) && plugins.some((p: any) => p.id === 'web');
	}

	async function toggleWebPlugin(provider: Provider) {
		const has = hasWebPlugin(provider);
		let newParams: Record<string, unknown> | null;
		if (has) {
			const { plugins, ...rest } = provider.extra_params ?? {};
			newParams = Object.keys(rest).length > 0 ? rest : null;
		} else {
			newParams = { ...(provider.extra_params ?? {}), plugins: [{ id: 'web' }] };
		}
		saving = provider.id;
		errorMsg = '';
		try {
			const res = await fetch(`/api/admin/ai/providers/${provider.id}`, {
				method: 'PATCH',
				headers: { 'Content-Type': 'application/json' },
				body: JSON.stringify({ extra_params: newParams })
			});
			if (!res.ok) throw new Error('Feil');
			const updated = await res.json();
			provider.extra_params = updated.extra_params;
			markSaved(provider.id);
		} catch {
			errorMsg = 'Kunne ikke oppdatere web-plugin';
		} finally {
			saving = null;
		}
	}

	function startEditExtraParams(provider: Provider) {
		editingExtraParams = provider.id;
		editExtraParamsText = provider.extra_params ? JSON.stringify(provider.extra_params, null, 2) : '';
	}

	async function saveExtraParams(provider: Provider) {
		saving = provider.id;
		errorMsg = '';
		try {
			const parsed = editExtraParamsText.trim() ? JSON.parse(editExtraParamsText) : null;
			const res = await fetch(`/api/admin/ai/providers/${provider.id}`, {
				method: 'PATCH',
				headers: { 'Content-Type': 'application/json' },
				body: JSON.stringify({ extra_params: parsed })
			});
			if (!res.ok) throw new Error('Feil');
			const updated = await res.json();
			provider.extra_params = updated.extra_params;
			editingExtraParams = null;
			markSaved(provider.id);
		} catch (e: any) {
			errorMsg = e.message === 'Feil' ? 'Kunne ikke lagre params' : `Ugyldig JSON: ${e.message}`;
		} finally {
			saving = null;
		}
	}

	async function swapProviders(providerA: Provider, providerB: Provider) {
		saving = providerA.id;
		errorMsg = '';
		try {
			const res = await fetch('/api/admin/ai/providers/swap', {
				method: 'POST',
				headers: { 'Content-Type': 'application/json' },
				body: JSON.stringify({ id_a: providerA.id, id_b: providerB.id })
			});
			if (!res.ok) throw new Error('Feil ved bytte');
			const updated: Provider[] = await res.json();
			// Oppdater providers-listen med nye prioriteter
			for (const u of updated) {
				const existing = providers.find(p => p.id === u.id);
				if (existing) existing.priority = u.priority;
			}
			providers = [...providers];
			markSaved(providerA.id);
		} catch {
			errorMsg = 'Kunne ikke bytte rekkefølge';
		} finally {
			saving = null;
		}
	}

	async function toggleProvider(provider: Provider) {
		saving = provider.id;
		errorMsg = '';
		try {
			const res = await fetch(`/api/admin/ai/providers/${provider.id}`, {
				method: 'PATCH',
				headers: { 'Content-Type': 'application/json' },
				body: JSON.stringify({ is_active: !provider.is_active })
			});
			if (!res.ok) throw new Error('Feil ved lagring');
			const updated = await res.json();
			provider.is_active = updated.is_active;
			markSaved(provider.id);
		} catch {
			errorMsg = 'Kunne ikke oppdatere provider';
		} finally {
			saving = null;
		}
	}

	async function addProvider(aliasId: string) {
		errorMsg = '';
		const maxPri = Math.max(0, ...providersForAlias(aliasId).map((p) => p.priority));
		try {
			const res = await fetch('/api/admin/ai/providers', {
				method: 'POST',
				headers: { 'Content-Type': 'application/json' },
				body: JSON.stringify({
					alias_id: aliasId,
					priority: maxPri + 1,
					litellm_model: newProvider.litellm_model,
					api_key_env: newProvider.api_key_env
				})
			});
			if (!res.ok) throw new Error('Feil ved opprettelse');
			const row = await res.json();
			providers = [...providers, row];
			newProvider = { alias_id: '', litellm_model: '', api_key_env: 'OPENROUTER_API_KEY' };
		} catch {
			errorMsg = 'Kunne ikke legge til provider';
		}
	}

	async function deleteProvider(provider: Provider) {
		errorMsg = '';
		try {
			const res = await fetch(`/api/admin/ai/providers/${provider.id}`, { method: 'DELETE' });
			if (!res.ok) throw new Error('Feil');
			providers = providers.filter((p) => p.id !== provider.id);
			// Renummerer prioriteter for gjenværende providers under samme alias
			await renumberPriorities(provider.alias_id);
		} catch {
			errorMsg = 'Kunne ikke slette provider';
		}
	}

	async function renumberPriorities(aliasId: string) {
		const ap = providersForAlias(aliasId);
		let changed = false;
		for (let i = 0; i < ap.length; i++) {
			if (ap[i].priority !== i + 1) {
				ap[i].priority = i + 1;
				changed = true;
			}
		}
		if (!changed) return;
		try {
			await fetch('/api/admin/ai/providers/renumber', {
				method: 'POST',
				headers: { 'Content-Type': 'application/json' },
				body: JSON.stringify(ap.map(p => ({ id: p.id, priority: p.priority })))
			});
			providers = [...providers];
		} catch { /* stille */ }
	}

	async function addAlias() {
		errorMsg = '';
		if (!newAlias.alias) return;
		try {
			const res = await fetch('/api/admin/ai/aliases', {
				method: 'POST',
				headers: { 'Content-Type': 'application/json' },
				body: JSON.stringify(newAlias)
			});
			if (!res.ok) throw new Error('Feil');
			const row = await res.json();
			aliases = [...aliases, row];
			newAlias = { alias: '', description: '' };
		} catch {
			errorMsg = 'Kunne ikke opprette alias';
		}
	}

	async function updateRouting(route: Route, aliasId: string) {
		saving = route.job_type;
		errorMsg = '';
		try {
			const res = await fetch(`/api/admin/ai/routing/${route.job_type}`, {
				method: 'PATCH',
				headers: { 'Content-Type': 'application/json' },
				body: JSON.stringify({ alias_id: aliasId })
			});
			if (!res.ok) throw new Error('Feil');
			const updated = await res.json();
			route.alias_id = updated.alias_id;
			route.alias = aliases.find((a) => a.id === updated.alias_id)?.alias ?? route.alias;
			markSaved(route.job_type);
		} catch {
			errorMsg = 'Kunne ikke oppdatere ruting';
		} finally {
			saving = null;
		}
	}

	async function addRoute() {
		errorMsg = '';
		if (!newRoute.job_type || !newRoute.alias_id) return;
		try {
			const res = await fetch('/api/admin/ai/routing', {
				method: 'POST',
				headers: { 'Content-Type': 'application/json' },
				body: JSON.stringify(newRoute)
			});
			if (!res.ok) throw new Error('Feil');
			const row = await res.json();
			row.alias = aliases.find((a: Alias) => a.id === row.alias_id)?.alias ?? '';
			routing = [...routing, row];
			newRoute = { job_type: '', alias_id: '', description: '' };
		} catch {
			errorMsg = 'Kunne ikke legge til ruting';
		}
	}

	function startEditPrompt(prompt: Prompt) {
		editingPrompt = prompt.action;
		editPromptText = prompt.system_prompt;
		editPromptLabel = prompt.label ?? '';
		editPromptIcon = prompt.icon ?? '';
	}

	function cancelEditPrompt() {
		editingPrompt = null;
		editPromptText = '';
		editPromptLabel = '';
		editPromptIcon = '';
	}

	async function savePrompt(prompt: Prompt) {
		saving = prompt.action;
		errorMsg = '';
		try {
			const res = await fetch(`/api/admin/ai/prompts/${prompt.action}`, {
				method: 'PATCH',
				headers: { 'Content-Type': 'application/json' },
				body: JSON.stringify({
					system_prompt: editPromptText,
					label: editPromptLabel || null,
					icon: editPromptIcon || null
				})
			});
			if (!res.ok) throw new Error('Feil ved lagring');
			const updated = await res.json();
			prompt.system_prompt = updated.system_prompt;
			prompt.label = updated.label;
			prompt.icon = updated.icon;
			prompt.updated_at = updated.updated_at;
			editingPrompt = null;
			editPromptText = '';
			editPromptLabel = '';
			editPromptIcon = '';
			markSaved(prompt.action);
		} catch {
			errorMsg = 'Kunne ikke lagre prompt';
		} finally {
			saving = null;
		}
	}

	let configLoading = $state(false);

	async function generateConfig(restart = false) {
		configMsg = '';
		errorMsg = '';
		configLoading = true;
		try {
			const url = restart
				? '/api/admin/ai/generate-config?restart=true'
				: '/api/admin/ai/generate-config';
			const res = await fetch(url, { method: 'POST' });
			const data = await res.json();
			if (!res.ok) throw new Error(data.message ?? 'Feil');
			configMsg = `${data.message} (${data.model_count} modeller)`;
		} catch (e: any) {
			errorMsg = e.message || 'Feil ved config-generering';
		} finally {
			configLoading = false;
		}
	}

	let enabledKeys = $derived(new Set(apiKeys.filter(k => k.is_enabled).map(k => k.name)));

	function isKeyEnabled(envName: string): boolean {
		return enabledKeys.has(envName);
	}

	let sortedAliases = $derived([...aliases].sort((a, b) => a.alias.localeCompare(b.alias, 'nb')));
	let sortedUsage = $derived([...usage].sort((a, b) => b.total_tokens - a.total_tokens));
	let totalTokens = $derived(usage.reduce((s, u) => s + u.total_tokens, 0));
</script>

<div class="admin-ai">
	<div class="header">
		<h2>AI-administrasjon</h2>
		<span class="header-stats">{aliases.length} aliaser / {providers.length} leverandører / {totalTokens.toLocaleString('nb-NO')} tokens (30d)</span>
	</div>

	<!-- API-nøkler -->
	{#if keysLoaded}
		<div class="key-pills">
			{#each apiKeys as key}
				<button
					class="key-pill"
					class:key-pill--on={key.is_enabled && key.configured}
					class:key-pill--off={!key.is_enabled && key.configured}
					class:key-pill--missing={!key.configured}
					onclick={() => toggleKey(key)}
					title={key.configured
						? (key.is_enabled ? `${key.label} aktiv — klikk for å deaktivere` : `${key.label} deaktivert — klikk for å aktivere`)
						: `${key.label} — mangler nøkkelverdi`}
				>
					{key.label}
					{#if !key.configured}
						&#x2717;
					{:else if key.is_enabled}
						&#x2713;
					{:else}
						&#x25CB;
					{/if}
				</button>
			{/each}
			<button
				class="key-pill key-pill--add"
				onclick={() => { expandedKey = expandedKey === '__new__' ? null : '__new__'; }}
			>+ Ny nøkkel</button>
		</div>

		<!-- Utvidet nøkkeladministrasjon -->
		{#if expandedKey === '__new__'}
			<div class="key-manage-row">
				<input type="text" placeholder="ENV_NAVN (f.eks. DEEPSEEK_API_KEY)" bind:value={newKey.env_name} class="key-input" />
				<input type="text" placeholder="Visningsnavn" bind:value={newKey.label} class="key-input key-input--short" />
				<input type="password" placeholder="API-nøkkel (valgfritt)" bind:value={newKey.key_value} class="key-input" />
				<button class="add-btn" onclick={addKey}>Legg til</button>
				<button class="toggle-btn" onclick={() => { expandedKey = null; }}>Avbryt</button>
			</div>
		{/if}

		<!-- Nøkkeldetaljer -->
		<div class="key-details">
			{#each apiKeys as key}
				<div class="key-detail-row">
					<button
						class="key-detail-toggle"
						onclick={() => { expandedKey = expandedKey === key.name ? null : key.name; keyValueInput = ''; }}
					>
						<span class="key-detail-label">{key.label}</span>
						<span class="key-detail-env">{key.name}</span>
						<span class="key-detail-source">
							{#if key.has_db_value}
								nøkkel i DB
							{:else if key.configured}
								nøkkel fra env
							{:else}
								ikke konfigurert
							{/if}
						</span>
					</button>
					{#if expandedKey === key.name}
						<div class="key-detail-edit">
							<input
								type="password"
								placeholder="Lim inn ny nøkkelverdi..."
								bind:value={keyValueInput}
								class="key-input"
							/>
							<div class="key-detail-actions">
								<button class="add-btn" onclick={() => saveKeyValue(key)}>Lagre nøkkel</button>
								{#if key.has_db_value}
									<button class="toggle-btn" onclick={() => clearKeyValue(key)}>Fjern DB-verdi</button>
								{/if}
								<button class="delete-btn" onclick={() => deleteKey(key)}>Slett</button>
							</div>
							{#if saved === key.name}
								<span class="status-saved">OK</span>
							{/if}
						</div>
					{/if}
				</div>
			{/each}
		</div>
	{/if}

	{#if errorMsg}
		<div class="error-msg">{errorMsg}</div>
	{/if}

	<!-- Seksjon 1: Modellkatalog -->
	<section>
		<div class="catalog-header">
			<h3>Modellkatalog</h3>
			<div class="catalog-actions">
				{#if catalogLoaded}
					<input
						type="text"
						class="catalog-search"
						placeholder="Søk modeller..."
						bind:value={catalogSearch}
					/>
					<button class="toggle-btn" onclick={() => { catalogLoaded = false; catalogModels = []; }}>Skjul</button>
				{/if}
				<button
					class="toggle-btn"
					onclick={loadCatalog}
					disabled={catalogLoading}
				>
					{catalogLoading ? 'Laster...' : catalogLoaded ? 'Oppdater' : 'Last inn katalog'}
				</button>
			</div>
		</div>

		{#if catalogLoaded}
			{#if groupedByProvider.length === 0}
				<p class="hint">Ingen modeller matcher søket.</p>
			{:else}
				{#each groupedByProvider as [providerName, models] (providerName)}
					<div class="provider-group">
						<button class="provider-header" onclick={() => toggleCatalogProvider(providerName)}>
							<span class="provider-chevron">{expandedProviders.has(providerName) ? '\u25BC' : '\u25B6'}</span>
							<span class="provider-name">{providerName}</span>
							<span class="provider-stats">{models.length} modeller</span>
						</button>

						{#if expandedProviders.has(providerName)}
							<div class="catalog-list">
								<div class="catalog-row catalog-row--header">
									<span class="cat-col-name">Modell</span>
									<span class="cat-col-ctx">Kontekst</span>
									<span class="cat-col-price">Prompt/M</span>
									<span class="cat-col-price">Kompl./M</span>
									<span class="cat-col-add"></span>
								</div>

								{#each models as model (model.id)}
									<div class="catalog-row">
										<span class="cat-col-name" title={model.id}>{model.name}</span>
										<span class="cat-col-ctx">{formatCtx(model.context_length)}</span>
										<span class="cat-col-price">{formatPrice(model.prompt_price_per_m)}</span>
										<span class="cat-col-price">{formatPrice(model.completion_price_per_m)}</span>
										<span class="cat-col-add">
											<button
												class="toggle-btn"
												onclick={() => { addingFromCatalog = addingFromCatalog === model.id ? null : model.id; catalogAddAlias = ''; }}
											>{addingFromCatalog === model.id ? '&#x2717;' : 'Legg til &rarr;'}</button>
										</span>
									</div>
									{#if addingFromCatalog === model.id}
										<div class="catalog-add-row">
											<span class="catalog-add-label">Legg til <strong>{model.name}</strong> via {model.api_key_env}:</span>
											<select bind:value={catalogAddAlias}>
												<option value="">Velg alias...</option>
												{#each aliases as a}
													<option value={a.id}>{a.alias}</option>
												{/each}
											</select>
											<button
												class="add-btn"
												disabled={!catalogAddAlias}
												onclick={() => addFromCatalog(model, catalogAddAlias)}
											>Legg til</button>
										</div>
									{/if}
								{/each}
							</div>
						{/if}
					</div>
				{/each}
			{/if}
		{/if}
	</section>

	<!-- Seksjon 2: Modellaliaser -->
	<section>
		<h3>Modellaliaser</h3>
		<div class="table-list">
			<div class="table-row table-row--header">
				<span class="col-alias">Alias</span>
				<span class="col-desc">Beskrivelse</span>
				<span class="col-providers">Leverandører</span>
				<span class="col-active">Aktiv</span>
				<span class="col-status"></span>
			</div>

			{#each sortedAliases as alias (alias.id)}
				{@const ap = providersForAlias(alias.id)}
				{@const primaryModel = ap.find(p => p.is_active && isKeyEnabled(p.api_key_env))?.litellm_model}
				{#if editingAlias === alias.id}
					<div class="table-row alias-edit-row">
						<input type="text" class="alias-edit-input" bind:value={editAliasName} placeholder="Alias-navn" />
						<input type="text" class="alias-edit-input" bind:value={editAliasDesc} placeholder="Beskrivelse" />
						<span></span>
						<span class="alias-edit-actions">
							<button class="add-btn" onclick={() => saveAlias(alias)}>Lagre</button>
							<button class="toggle-btn" onclick={cancelEditAlias}>Avbryt</button>
						</span>
						<span class="col-status">
							{#if saving === alias.id}
								<span class="status-saving">...</span>
							{/if}
						</span>
					</div>
				{:else}
					<div class="table-row" class:table-row--inactive={!alias.is_active}>
						<span
							class="col-alias clickable"
							onclick={() => (expandedAlias = expandedAlias === alias.id ? null : alias.id)}
						>
							{alias.alias}
							{#if primaryModel}
								<span class="alias-model">{primaryModel.replace('openrouter/', '')}</span>
							{/if}
						</span>
						<span class="col-desc">{alias.description ?? '\u2014'}</span>
						<span class="col-providers">{ap.length}</span>
						<span class="col-active alias-action-group">
							<button class="toggle-btn" onclick={() => startEditAlias(alias)}>Rediger</button>
							<button class="toggle-btn" onclick={() => toggleAlias(alias)}>
								{alias.is_active ? 'På' : 'Av'}
							</button>
						</span>
						<span class="col-status">
							{#if saving === alias.id}
								<span class="status-saving">...</span>
							{:else if saved === alias.id}
								<span class="status-saved">OK</span>
							{/if}
						</span>
					</div>
				{/if}

				{#if expandedAlias === alias.id}
					<div class="provider-list-alias">
						{#each ap as provider, idx (provider.id)}
							{@const keyDisabled = !isKeyEnabled(provider.api_key_env)}
							<div class="provider-row-alias" class:provider-row--inactive={!provider.is_active} class:provider-row--key-off={keyDisabled}>
								<span class="col-pri">
									<span class="pri-arrows">
										<button
											class="pri-btn"
											disabled={idx === 0}
											onclick={() => swapProviders(provider, ap[idx - 1])}
											title="Flytt opp"
										>&#x25B2;</button>
										<button
											class="pri-btn"
											disabled={idx === ap.length - 1}
											onclick={() => swapProviders(provider, ap[idx + 1])}
											title="Flytt ned"
										>&#x25BC;</button>
									</span>
									#{provider.priority}
								</span>
								<span class="col-model">{provider.litellm_model}</span>
								<span class="col-key" class:col-key--disabled={keyDisabled}>{provider.api_key_env}{#if keyDisabled} (av){/if}</span>
								<span class="col-extra-pills">
									<button
										class="extra-pill"
										class:extra-pill--on={hasWebPlugin(provider)}
										onclick={() => toggleWebPlugin(provider)}
										title="Web-søk (OpenRouter plugin)"
									>web {hasWebPlugin(provider) ? '\u2713' : '\u2717'}</button>
									{#if provider.extra_params && Object.keys(provider.extra_params).length > (hasWebPlugin(provider) ? 1 : 0)}
										<span class="extra-pill extra-pill--custom" title={JSON.stringify(provider.extra_params)}>+params</span>
									{/if}
									<button class="extra-edit-btn" onclick={() => startEditExtraParams(provider)} title="Rediger extra_params JSON">&hellip;</button>
								</span>
								<span class="col-active">
									<button class="toggle-btn" onclick={() => toggleProvider(provider)}>
										{provider.is_active ? 'På' : 'Av'}
									</button>
								</span>
								<button class="delete-btn" onclick={() => deleteProvider(provider)}>Slett</button>
								<span class="col-status">
									{#if saving === provider.id}
										<span class="status-saving">...</span>
									{:else if saved === provider.id}
										<span class="status-saved">OK</span>
									{/if}
								</span>
							</div>
							{#if editingExtraParams === provider.id}
								<div class="extra-params-editor">
									<textarea
										bind:value={editExtraParamsText}
										rows="4"
										placeholder={'{"plugins": [{"id": "web"}]}'}
									></textarea>
									<div class="extra-params-actions">
										<button class="add-btn" onclick={() => saveExtraParams(provider)}>Lagre</button>
										<button class="toggle-btn" onclick={() => { editingExtraParams = null; }}>Avbryt</button>
									</div>
								</div>
							{/if}
						{/each}

						<div class="provider-row-alias provider-row--add">
							<span class="col-pri"></span>
							<div class="add-model-input">
								<input
									type="text"
									placeholder="gemini/modell-navn"
									bind:value={newProvider.litellm_model}
								/>
								{#if catalogLoaded}
									<button
										class="toggle-btn catalog-pick-btn"
										onclick={() => { showCatalogPicker = !showCatalogPicker; catalogPickerSearch = ''; }}
									>Katalog</button>
								{/if}
							</div>
							<select bind:value={newProvider.api_key_env}>
								{#each apiKeys as k}
									<option value={k.name}>{k.label} ({k.name})</option>
								{/each}
							</select>
							<button class="add-btn" onclick={() => addProvider(alias.id)}>Legg til</button>
						</div>

						{#if showCatalogPicker && catalogLoaded}
							<div class="catalog-picker">
								<input
									type="text"
									class="catalog-picker-search"
									placeholder="Søk i katalog..."
									bind:value={catalogPickerSearch}
								/>
								<div class="catalog-picker-list">
									{#each catalogPickerFiltered as model (model.id)}
										<button
											class="catalog-picker-item"
											onclick={() => selectFromPicker(model)}
										>
											<span class="picker-name">{model.name}</span>
											<span class="picker-meta">{formatCtx(model.context_length)} / {formatPrice(model.completion_price_per_m)}</span>
										</button>
									{/each}
								</div>
							</div>
						{/if}
					</div>
				{/if}
			{/each}
		</div>

		<div class="add-form">
			<input type="text" placeholder="sidelinja/nytt-alias" bind:value={newAlias.alias} />
			<input type="text" placeholder="Beskrivelse" bind:value={newAlias.description} />
			<button class="add-btn" onclick={addAlias}>Nytt alias</button>
		</div>
	</section>

	<!-- Seksjon 3: Jobbruting -->
	<section>
		<h3>Jobbruting</h3>
		<div class="table-list">
			<div class="table-row table-row--header">
				<span class="col-jobtype">Jobbtype</span>
				<span class="col-alias">Modellalias</span>
				<span class="col-desc">Beskrivelse</span>
				<span class="col-status"></span>
			</div>

			{#each routing as route (route.job_type)}
				<div class="table-row">
					<span class="col-jobtype">{route.job_type}</span>
					<span class="col-alias">
						<select
							value={route.alias_id}
							onchange={(e) =>
								updateRouting(route, (e.target as HTMLSelectElement).value)}
						>
							{#each aliases as a}
								<option value={a.id}>{a.alias}</option>
							{/each}
						</select>
					</span>
					<span class="col-desc">{route.description ?? '\u2014'}</span>
					<span class="col-status">
						{#if saving === route.job_type}
							<span class="status-saving">...</span>
						{:else if saved === route.job_type}
							<span class="status-saved">OK</span>
						{/if}
					</span>
				</div>
			{/each}
		</div>

		<div class="add-form">
			<input type="text" placeholder="jobbtype" bind:value={newRoute.job_type} />
			<select bind:value={newRoute.alias_id}>
				<option value="">Velg alias...</option>
				{#each aliases as a}
					<option value={a.id}>{a.alias}</option>
				{/each}
			</select>
			<input type="text" placeholder="Beskrivelse" bind:value={newRoute.description} />
			<button class="add-btn" onclick={addRoute}>Legg til</button>
		</div>
	</section>

	<!-- Seksjon 4: System-prompts -->
	<section>
		<h3>System-prompts</h3>
		<div class="table-list">
			<div class="table-row table-row--header prompt-row">
				<span class="col-action">Action</span>
				<span class="col-label">Visningsnavn</span>
				<span class="col-desc">Beskrivelse</span>
				<span class="col-chars">Tegn</span>
				<span class="col-updated">Oppdatert</span>
				<span class="col-edit"></span>
			</div>

			{#each prompts as prompt (prompt.action)}
				<div class="table-row prompt-row">
					<span class="col-action">{prompt.action}</span>
					<span class="col-label">{prompt.icon ?? ''} {prompt.label ?? '\u2014'}</span>
					<span class="col-desc">{prompt.description ?? '\u2014'}</span>
					<span class="col-chars">{prompt.system_prompt.length}</span>
					<span class="col-updated">{new Date(prompt.updated_at).toLocaleDateString('nb-NO')}</span>
					<span class="col-edit">
						{#if saving === prompt.action}
							<span class="status-saving">...</span>
						{:else if saved === prompt.action}
							<span class="status-saved">OK</span>
						{:else}
							<button class="toggle-btn" onclick={() => startEditPrompt(prompt)}>Rediger</button>
						{/if}
					</span>
				</div>

				{#if editingPrompt === prompt.action}
					<div class="prompt-editor">
						<div class="prompt-editor-meta">
							<label>
								<span class="prompt-meta-label">Ikon</span>
								<input type="text" bind:value={editPromptIcon} placeholder="🧹" class="prompt-meta-input prompt-meta-input--icon" />
							</label>
							<label>
								<span class="prompt-meta-label">Visningsnavn</span>
								<input type="text" bind:value={editPromptLabel} placeholder="Vask tekst" class="prompt-meta-input" />
							</label>
						</div>
						<textarea
							bind:value={editPromptText}
							rows="12"
						></textarea>
						<div class="prompt-editor-footer">
							<span class="prompt-char-count">{editPromptText.length} tegn</span>
							<div class="prompt-editor-actions">
								<button class="toggle-btn" onclick={cancelEditPrompt}>Avbryt</button>
								<button class="add-btn" onclick={() => savePrompt(prompt)}>Lagre</button>
							</div>
						</div>
					</div>
				{/if}
			{/each}
		</div>
	</section>

	<!-- Seksjon 5: Tokenforbruk -->
	<section>
		<div class="catalog-header">
			<h3>Tokenforbruk (siste 30 dager)</h3>
			{#if totalEstimatedCost !== null}
				<span class="usage-total-cost">Estimert totalkostnad: ${totalEstimatedCost.toFixed(2)}</span>
			{/if}
		</div>
		{#if usage.length === 0}
			<p class="hint">Ingen AI-kall registrert ennå.</p>
		{:else}
			<div class="table-list">
				<div class="table-row table-row--header usage-row">
					<span>Alias</span>
					<span>Modell</span>
					<span>Prompt</span>
					<span class="col-num">Kall</span>
					<span class="col-num">Prompt-tok.</span>
					<span class="col-num">Kompl.</span>
					<span class="col-num">Totalt</span>
					<span class="col-num">Est. $</span>
				</div>

				{#each sortedUsage as row}
					{@const cost = estimateCost(row)}
					<div class="table-row usage-row">
						<span class="col-alias">{row.model_alias}</span>
						<span class="col-model-actual">{row.model_actual ?? '\u2014'}</span>
						<span class="col-action-usage">{row.action ?? '\u2014'}</span>
						<span class="col-num">{row.call_count}</span>
						<span class="col-num">{row.prompt_tokens.toLocaleString('nb-NO')}</span>
						<span class="col-num">{row.completion_tokens.toLocaleString('nb-NO')}</span>
						<span class="col-num">{row.total_tokens.toLocaleString('nb-NO')}</span>
						<span class="col-num">{cost !== null ? `$${cost.toFixed(2)}` : '\u2014'}</span>
					</div>
				{/each}
			</div>
			{#if !catalogLoaded}
				<p class="hint">Last inn modellkatalogen for å se estimerte kostnader.</p>
			{/if}
		{/if}
	</section>

	<!-- Seksjon 6: Konfigurasjon -->
	<section>
		<h3>Konfigurasjon</h3>
		<div class="config-box">
			<button class="generate-btn" onclick={() => generateConfig(false)} disabled={configLoading}>
				Generer config.yaml
			</button>
			<button class="generate-btn generate-btn--restart" onclick={() => generateConfig(true)} disabled={configLoading}>
				{configLoading ? 'Jobber...' : 'Generer + restart gateway'}
			</button>
			{#if configMsg}
				<span class="config-msg">{configMsg}</span>
			{/if}
			<p class="hint">Genererer LiteLLM config.yaml fra databasen. «Generer + restart» aktiverer endringene umiddelbart.</p>
		</div>
	</section>
</div>

<style>
	.admin-ai {
		max-width: 960px;
	}

	.header {
		display: flex;
		align-items: baseline;
		gap: 1rem;
		margin-bottom: 0.75rem;
	}

	h2 {
		font-size: 1.4rem;
	}

	h3 {
		font-size: 1.1rem;
		margin-bottom: 0.75rem;
	}

	.header-stats {
		font-size: 0.8rem;
		color: #8b92a5;
	}

	/* API-nøkkel-pills */
	.key-pills {
		display: flex;
		gap: 0.5rem;
		margin-bottom: 1.5rem;
		flex-wrap: wrap;
	}

	.key-pill {
		font-size: 0.7rem;
		font-weight: 600;
		padding: 0.2rem 0.6rem;
		border-radius: 9999px;
		letter-spacing: 0.03em;
		cursor: pointer;
		transition: opacity 0.15s;
	}

	.key-pill:hover {
		opacity: 0.8;
	}

	.key-pill--on {
		background: #0d3320;
		border: 1px solid #166534;
		color: #4ade80;
	}

	.key-pill--off {
		background: #1e1e2e;
		border: 1px solid #3b3b52;
		color: #8b92a5;
	}

	.key-pill--missing {
		background: #3b1219;
		border: 1px solid #6b2028;
		color: #f87171;
	}

	.key-pill--add {
		background: transparent;
		border: 1px dashed #3b3b52;
		color: #8b92a5;
	}

	.key-pill--add:hover {
		border-color: #8b92a5;
		color: #cdd6f4;
	}

	.key-manage-row {
		display: flex;
		gap: 0.5rem;
		margin-bottom: 1rem;
		align-items: center;
		flex-wrap: wrap;
	}

	.key-input {
		background: #181825;
		border: 1px solid #2d3148;
		color: #cdd6f4;
		padding: 0.3rem 0.5rem;
		border-radius: 4px;
		font-size: 0.8rem;
		flex: 1;
		min-width: 150px;
	}

	.key-input--short {
		flex: 0.5;
		min-width: 100px;
	}

	.key-details {
		display: flex;
		flex-direction: column;
		gap: 1px;
		margin-bottom: 1.5rem;
	}

	.key-detail-row {
		background: #1e1e2e;
		border-radius: 4px;
	}

	.key-detail-toggle {
		display: flex;
		gap: 1rem;
		align-items: center;
		width: 100%;
		padding: 0.4rem 0.6rem;
		background: none;
		border: none;
		color: #cdd6f4;
		font-size: 0.8rem;
		cursor: pointer;
		text-align: left;
	}

	.key-detail-toggle:hover {
		background: #262640;
	}

	.key-detail-label {
		font-weight: 600;
		min-width: 80px;
	}

	.key-detail-env {
		color: #8b92a5;
		font-family: monospace;
		font-size: 0.75rem;
		flex: 1;
	}

	.key-detail-source {
		font-size: 0.7rem;
		color: #6c7086;
	}

	.key-detail-edit {
		padding: 0.5rem 0.6rem;
		border-top: 1px solid #2d3148;
	}

	.key-detail-actions {
		display: flex;
		gap: 0.5rem;
		margin-top: 0.4rem;
		align-items: center;
	}

	section {
		margin-bottom: 2rem;
	}

	.error-msg {
		background: #3b1219;
		border: 1px solid #6b2028;
		color: #f87171;
		padding: 0.5rem 0.75rem;
		border-radius: 6px;
		margin-bottom: 1rem;
		font-size: 0.85rem;
	}

	/* Modellkatalog */
	.catalog-header {
		display: flex;
		align-items: center;
		justify-content: space-between;
		gap: 1rem;
		margin-bottom: 0.75rem;
	}

	.catalog-header h3 {
		margin-bottom: 0;
	}

	.catalog-actions {
		display: flex;
		gap: 0.5rem;
		align-items: center;
	}

	.catalog-search {
		background: #0f1117;
		border: 1px solid #2d3148;
		border-radius: 4px;
		color: #e1e4e8;
		padding: 0.3rem 0.5rem;
		font-size: 0.8rem;
		width: 200px;
	}

	.catalog-search:focus {
		outline: none;
		border-color: #3b82f6;
	}

	.provider-group {
		margin-bottom: 0.5rem;
	}

	.provider-header {
		display: flex;
		align-items: center;
		gap: 0.5rem;
		width: 100%;
		padding: 0.5rem 0.75rem;
		background: #1a1d2e;
		border: 1px solid #2d3148;
		border-radius: 6px;
		color: #e1e4e8;
		cursor: pointer;
		font-size: 0.85rem;
		text-align: left;
	}

	.provider-header:hover {
		border-color: #3b82f6;
	}

	.provider-chevron {
		font-size: 0.6rem;
		color: #8b92a5;
		width: 1em;
	}

	.provider-name {
		font-weight: 600;
		flex: 1;
	}

	.provider-stats {
		font-size: 0.75rem;
		color: #8b92a5;
	}

	.catalog-list {
		display: flex;
		flex-direction: column;
		gap: 1px;
		background: #2d3148;
		border: 1px solid #2d3148;
		border-top: none;
		border-radius: 0 0 6px 6px;
		overflow: hidden;
	}

	.catalog-row {
		display: grid;
		grid-template-columns: 3fr 70px 80px 80px 100px;
		align-items: center;
		gap: 0.5rem;
		padding: 0.4rem 0.75rem;
		background: #161822;
		font-size: 0.8rem;
	}

	.catalog-row--header {
		background: #1a1d2e;
		font-weight: 600;
		color: #8b92a5;
		font-size: 0.7rem;
		text-transform: uppercase;
		letter-spacing: 0.05em;
	}

	.cat-col-name {
		overflow: hidden;
		text-overflow: ellipsis;
		white-space: nowrap;
	}

	.cat-col-ctx {
		text-align: right;
		font-variant-numeric: tabular-nums;
		color: #8b92a5;
		font-size: 0.75rem;
	}

	.cat-col-price {
		text-align: right;
		font-variant-numeric: tabular-nums;
		font-size: 0.75rem;
	}

	.cat-col-add {
		text-align: right;
	}

	.cat-col-add select {
		font-size: 0.7rem;
		padding: 0.15rem 0.25rem;
	}

	.catalog-add-row {
		display: flex;
		gap: 0.5rem;
		align-items: center;
		padding: 0.5rem 0.75rem;
		background: #1a1d2e;
		border-left: 3px solid #4ade80;
		font-size: 0.8rem;
	}

	.catalog-add-row select {
		font-size: 0.75rem;
		padding: 0.2rem 0.3rem;
	}

	.catalog-add-label {
		color: #8b92a5;
		white-space: nowrap;
		font-size: 0.75rem;
	}

	/* Alias table */
	.table-list {
		display: flex;
		flex-direction: column;
		gap: 1px;
		background: #2d3148;
		border: 1px solid #2d3148;
		border-radius: 6px;
		overflow: hidden;
	}

	.table-row {
		display: grid;
		grid-template-columns: 2fr 2fr 1fr 60px 40px;
		align-items: center;
		gap: 0.5rem;
		padding: 0.5rem 0.75rem;
		background: #161822;
		font-size: 0.8rem;
	}

	.table-row--header {
		background: #1a1d2e;
		font-weight: 600;
		color: #8b92a5;
		font-size: 0.7rem;
		text-transform: uppercase;
		letter-spacing: 0.05em;
	}

	.table-row--inactive {
		opacity: 0.5;
	}

	.col-alias {
		overflow: hidden;
		text-overflow: ellipsis;
		white-space: nowrap;
	}

	.alias-model {
		display: block;
		font-size: 0.75em;
		color: #8b92a5;
		font-weight: normal;
		white-space: nowrap;
		overflow: hidden;
		text-overflow: ellipsis;
	}

	.clickable {
		cursor: pointer;
		text-decoration: underline;
		text-decoration-style: dotted;
		text-underline-offset: 3px;
	}

	.col-desc {
		color: #8b92a5;
		overflow: hidden;
		text-overflow: ellipsis;
		white-space: nowrap;
	}

	.col-providers, .col-active, .col-status {
		text-align: center;
	}

	/* Alias edit */
	.alias-edit-row {
		grid-template-columns: 2fr 2fr 1fr auto 40px;
	}

	.alias-edit-input {
		width: 100%;
	}

	.alias-edit-actions {
		display: flex;
		gap: 0.35rem;
		white-space: nowrap;
	}

	.alias-action-group {
		display: flex;
		gap: 0.25rem;
		justify-content: center;
	}

	.col-num {
		text-align: right;
		font-variant-numeric: tabular-nums;
	}

	.col-jobtype {
		font-family: monospace;
	}

	.col-pri {
		color: #8b92a5;
		font-size: 0.75rem;
		width: 60px;
		display: flex;
		align-items: center;
		gap: 0.25rem;
	}

	.pri-arrows {
		display: flex;
		flex-direction: column;
		gap: 0;
	}

	.pri-btn {
		background: none;
		border: none;
		color: #6c7086;
		font-size: 0.55rem;
		cursor: pointer;
		padding: 0;
		line-height: 1;
	}

	.pri-btn:hover:not(:disabled) {
		color: #cdd6f4;
	}

	.pri-btn:disabled {
		opacity: 0.2;
		cursor: default;
	}

	.col-model {
		font-family: monospace;
		font-size: 0.75rem;
	}

	.col-key {
		font-size: 0.75rem;
		color: #8b92a5;
	}

	/* Provider sub-list (alias section) */
	.provider-list-alias {
		background: #0f1117;
		padding: 0.5rem 0.75rem 0.5rem 2rem;
		border-bottom: 1px solid #2d3148;
	}

	.provider-row-alias {
		display: grid;
		grid-template-columns: 30px 2fr 1fr auto 50px 50px 40px;
		align-items: center;
		gap: 0.5rem;
		padding: 0.35rem 0;
		font-size: 0.8rem;
	}

	.provider-row--inactive {
		opacity: 0.5;
	}

	.provider-row--key-off {
		opacity: 0.4;
		border-left: 2px solid #6b2028;
		padding-left: 0.5rem;
	}

	.col-key--disabled {
		color: #f87171;
		font-style: italic;
	}

	.provider-row--add {
		padding-top: 0.5rem;
		border-top: 1px solid #2d3148;
		margin-top: 0.25rem;
	}

	.add-model-input {
		display: flex;
		gap: 0.25rem;
		align-items: center;
	}

	.add-model-input input {
		flex: 1;
		min-width: 0;
	}

	.catalog-pick-btn {
		white-space: nowrap;
		flex-shrink: 0;
	}

	/* Catalog picker dropdown */
	.catalog-picker {
		background: #161822;
		border: 1px solid #3b82f6;
		border-radius: 6px;
		padding: 0.5rem;
		margin-top: 0.5rem;
	}

	.catalog-picker-search {
		width: 100%;
		background: #0f1117;
		border: 1px solid #2d3148;
		border-radius: 4px;
		color: #e1e4e8;
		padding: 0.3rem 0.5rem;
		font-size: 0.8rem;
		margin-bottom: 0.35rem;
	}

	.catalog-picker-search:focus {
		outline: none;
		border-color: #3b82f6;
	}

	.catalog-picker-list {
		max-height: 200px;
		overflow-y: auto;
		display: flex;
		flex-direction: column;
		gap: 1px;
	}

	.catalog-picker-item {
		display: flex;
		justify-content: space-between;
		align-items: center;
		padding: 0.3rem 0.5rem;
		background: #0f1117;
		border: none;
		color: #e1e4e8;
		font-size: 0.75rem;
		cursor: pointer;
		text-align: left;
		border-radius: 3px;
	}

	.catalog-picker-item:hover {
		background: #1a1d2e;
	}

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

	.picker-meta {
		color: #8b92a5;
		font-size: 0.7rem;
		flex-shrink: 0;
		margin-left: 0.5rem;
	}

	/* Extra params */
	.col-extra-pills {
		display: flex;
		gap: 0.25rem;
		align-items: center;
	}

	.extra-pill {
		font-size: 0.6rem;
		padding: 0.1rem 0.4rem;
		border-radius: 9999px;
		border: 1px solid #2d3148;
		background: #1a1d2e;
		color: #8b92a5;
		cursor: pointer;
		white-space: nowrap;
	}

	.extra-pill:hover {
		border-color: #3b82f6;
	}

	.extra-pill--on {
		background: #0d3320;
		border-color: #166534;
		color: #4ade80;
	}

	.extra-pill--custom {
		background: #2d1f4e;
		border-color: #6d4aaa;
		color: #c4b5fd;
		cursor: default;
	}

	.extra-edit-btn {
		background: none;
		border: none;
		color: #8b92a5;
		font-size: 0.75rem;
		cursor: pointer;
		padding: 0 0.2rem;
	}

	.extra-edit-btn:hover {
		color: #e1e4e8;
	}

	.extra-params-editor {
		background: #161822;
		border: 1px solid #3b82f6;
		border-radius: 6px;
		padding: 0.5rem;
		margin: 0.35rem 0;
	}

	.extra-params-editor textarea {
		width: 100%;
		background: #0f1117;
		border: 1px solid #2d3148;
		border-radius: 4px;
		color: #e1e4e8;
		padding: 0.4rem;
		font-size: 0.75rem;
		font-family: monospace;
		resize: vertical;
	}

	.extra-params-editor textarea:focus {
		outline: none;
		border-color: #3b82f6;
	}

	.extra-params-actions {
		display: flex;
		gap: 0.35rem;
		margin-top: 0.35rem;
	}

	/* Buttons */
	.toggle-btn {
		background: #1a1d2e;
		border: 1px solid #2d3148;
		border-radius: 4px;
		color: #e1e4e8;
		padding: 0.15rem 0.5rem;
		font-size: 0.7rem;
		cursor: pointer;
	}

	.toggle-btn:hover {
		border-color: #3b82f6;
	}

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

	.delete-btn {
		background: none;
		border: none;
		color: #6b2028;
		font-size: 0.7rem;
		cursor: pointer;
		padding: 0.15rem 0.35rem;
	}

	.delete-btn:hover {
		color: #f87171;
	}

	.add-btn {
		background: #1a1d2e;
		border: 1px solid #2d3148;
		border-radius: 4px;
		color: #e1e4e8;
		padding: 0.3rem 0.75rem;
		font-size: 0.75rem;
		cursor: pointer;
	}

	.add-btn:hover {
		border-color: #3b82f6;
	}

	.generate-btn {
		background: #1e3a5f;
		border: 1px solid #3b82f6;
		border-radius: 6px;
		color: #e1e4e8;
		padding: 0.5rem 1rem;
		font-size: 0.85rem;
		cursor: pointer;
	}

	.generate-btn:hover:not(:disabled) {
		background: #264b7a;
	}

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

	.generate-btn--restart {
		background: #1e4f3a;
		border-color: #22c55e;
	}

	.generate-btn--restart:hover:not(:disabled) {
		background: #276b4f;
	}

	/* Forms */
	.add-form {
		display: flex;
		gap: 0.5rem;
		margin-top: 0.75rem;
	}

	input[type='text'] {
		background: #0f1117;
		border: 1px solid #2d3148;
		border-radius: 4px;
		color: #e1e4e8;
		padding: 0.3rem 0.5rem;
		font-size: 0.8rem;
		flex: 1;
	}

	select {
		background: #0f1117;
		border: 1px solid #2d3148;
		border-radius: 4px;
		color: #e1e4e8;
		padding: 0.3rem 0.5rem;
		font-size: 0.8rem;
	}

	input:focus,
	select:focus {
		outline: none;
		border-color: #3b82f6;
	}

	.status-saving {
		color: #8b92a5;
	}

	.status-saved {
		color: #4ade80;
	}

	.config-box {
		display: flex;
		align-items: center;
		gap: 1rem;
		flex-wrap: wrap;
	}

	.config-msg {
		color: #4ade80;
		font-size: 0.85rem;
	}

	.hint {
		color: #8b92a5;
		font-size: 0.8rem;
		font-style: italic;
	}

	/* Usage/tokenforbruk */
	.usage-row {
		grid-template-columns: 1fr 2fr 1fr 60px 80px 80px 80px 60px;
	}

	.col-action-usage {
		font-size: 0.75rem;
		color: #8b92a5;
		overflow: hidden;
		text-overflow: ellipsis;
		white-space: nowrap;
	}

	.col-model-actual {
		font-family: monospace;
		font-size: 0.7rem;
		color: #8b92a5;
		overflow: hidden;
		text-overflow: ellipsis;
		white-space: nowrap;
	}

	.usage-total-cost {
		font-size: 0.85rem;
		color: #4ade80;
		font-weight: 600;
	}

	/* Prompt-seksjon */
	.prompt-row {
		grid-template-columns: 1.2fr 1.2fr 2fr 60px 80px 70px;
	}

	.col-label {
		font-size: 0.85rem;
	}

	.col-action {
		font-family: monospace;
	}

	.col-chars {
		text-align: right;
		font-variant-numeric: tabular-nums;
		color: #8b92a5;
		font-size: 0.75rem;
	}

	.col-updated {
		color: #8b92a5;
		font-size: 0.75rem;
	}

	.col-edit {
		text-align: center;
	}

	.prompt-editor {
		background: #0f1117;
		padding: 0.75rem;
		border-bottom: 1px solid #2d3148;
	}

	.prompt-editor-meta {
		display: flex;
		gap: 0.75rem;
		margin-bottom: 0.5rem;
	}

	.prompt-editor-meta label {
		display: flex;
		align-items: center;
		gap: 0.35rem;
	}

	.prompt-meta-label {
		font-size: 0.75rem;
		color: #8b92a5;
	}

	.prompt-meta-input {
		background: #161822;
		border: 1px solid #2d3148;
		border-radius: 4px;
		color: #e1e4e8;
		padding: 0.25rem 0.4rem;
		font-size: 0.8rem;
		width: 160px;
	}

	.prompt-meta-input--icon {
		width: 50px;
		text-align: center;
	}

	.prompt-meta-input:focus {
		outline: none;
		border-color: #3b82f6;
	}

	.prompt-editor textarea {
		width: 100%;
		background: #161822;
		border: 1px solid #2d3148;
		border-radius: 4px;
		color: #e1e4e8;
		padding: 0.5rem;
		font-size: 0.8rem;
		font-family: monospace;
		line-height: 1.5;
		resize: vertical;
	}

	.prompt-editor textarea:focus {
		outline: none;
		border-color: #3b82f6;
	}

	.prompt-editor-footer {
		display: flex;
		justify-content: space-between;
		align-items: center;
		margin-top: 0.5rem;
	}

	.prompt-char-count {
		color: #8b92a5;
		font-size: 0.75rem;
	}

	.prompt-editor-actions {
		display: flex;
		gap: 0.5rem;
	}
</style>
