<!--
Shared loading / empty / error placeholder for a view or panel. Gives
every surface one consistent treatment and a11y semantics:

- `loading` and `empty` announce politely (`role="status"`);
- `error` announces assertively (`role="alert"`) and may carry a retry /
  recovery action.

Callers pass an already-translated `message` (and `actionLabel`); the
component owns layout, the spinner, and the live-region role only.
-->
<script lang="ts">
	type Props = {
		kind: "loading" | "empty" | "error";
		message: string;
		actionLabel?: string;
		onAction?: () => void;
		testid?: string;
	};
	let { kind, message, actionLabel, onAction, testid }: Props = $props();
</script>

<div
	class="view-state {kind}"
	data-testid={testid}
	data-kind={kind}
	role={kind === "error" ? "alert" : "status"}
>
	{#if kind === "loading"}
		<span class="spinner" aria-hidden="true"></span>
	{/if}
	<p class="message">{message}</p>
	{#if actionLabel !== undefined && onAction !== undefined}
		<button type="button" class="action" onclick={onAction}>
			{actionLabel}
		</button>
	{/if}
</div>

<style>
	.view-state {
		display: flex;
		flex-direction: column;
		align-items: center;
		justify-content: center;
		gap: var(--space-3);
		padding: var(--space-6) var(--space-4);
		text-align: center;
		color: var(--color-text-muted);
		font-family: var(--font-sans);
	}
	.message {
		margin: 0;
		max-width: 32rem;
		line-height: var(--leading-normal);
	}
	.view-state.error .message {
		color: var(--color-danger);
	}
	.action {
		font: inherit;
		padding: var(--space-2) var(--space-4);
		background: var(--color-surface-raised);
		color: var(--color-text);
		border: 1px solid var(--color-border);
		border-radius: var(--radius-sm);
		cursor: pointer;
	}
	.action:hover {
		background: var(--color-surface-hover);
		border-color: var(--color-border-strong);
	}
	.spinner {
		width: 1.5rem;
		height: 1.5rem;
		border: 2px solid var(--color-border);
		border-top-color: var(--color-accent);
		border-radius: var(--radius-pill);
		animation: view-state-spin 0.8s linear infinite;
	}
	@media (prefers-reduced-motion: reduce) {
		.spinner {
			animation-duration: 2s;
		}
	}
	@keyframes view-state-spin {
		to {
			transform: rotate(360deg);
		}
	}
</style>
