<script lang="ts">
    /**
     * Decorative loading placeholder. Renders a muted block with a subtle
     * shimmer that sweeps across it. Purely visual — `aria-hidden` keeps it
     * out of the accessibility tree; the loading state should be announced by
     * the container (e.g. `role="status"`).
     *
     * Under prefers-reduced-motion the shimmer gradient/animation is dropped
     * entirely, leaving a flat `--surface-elevated` block.
     */
    let {
        width = '100%',
        height,
        aspectRatio,
        radius = 'md',
        variant = 'block',
        testid
    }: {
        width?: string;
        height?: string;
        /**
         * `aspect-ratio` for the box (e.g. `'2 / 3'`). Lets a fluid-width
         * placeholder reserve its shape without a hard-coded height — the
         * height stays `auto` so the ratio actually applies.
         */
        aspectRatio?: string;
        /** Corner radius, mapped to the design-token scale. */
        radius?: 'sm' | 'md' | 'lg' | 'pill';
        /** `circle` forces a pill radius (for avatars / dots). */
        variant?: 'block' | 'text' | 'circle';
        testid?: string;
    } = $props();

    const radiusClass = $derived(variant === 'circle' ? 'radius-pill' : `radius-${radius}`);

    // A text line gets a sensible default height so callers don't have to; an
    // explicit `height` still wins. Resolving it here (rather than in CSS)
    // keeps a single source of truth for the box height and avoids an inline
    // style silently shadowing a stylesheet rule.
    const resolvedHeight = $derived(height ?? (variant === 'text' ? '0.9em' : undefined));

    const style = $derived(
        `width: ${width};` +
            (resolvedHeight ? ` height: ${resolvedHeight};` : '') +
            (aspectRatio ? ` aspect-ratio: ${aspectRatio};` : '')
    );
</script>

<span class="skeleton {radiusClass}" data-testid={testid} aria-hidden="true" {style}></span>

<style>
    .skeleton {
        display: block;
        /* Flat base — this is the whole appearance under reduced motion. */
        background-color: var(--surface-elevated);
    }

    @media (prefers-reduced-motion: no-preference) {
        .skeleton {
            background-image: linear-gradient(
                90deg,
                var(--surface) 0%,
                var(--surface-elevated) 50%,
                var(--surface) 100%
            );
            background-size: 200% 100%;
            background-repeat: no-repeat;
            animation: skeleton-shimmer 1.2s ease-in-out infinite;
        }
    }

    .radius-sm {
        border-radius: var(--radius-sm);
    }
    .radius-md {
        border-radius: var(--radius-md);
    }
    .radius-lg {
        border-radius: var(--radius-lg);
    }
    .radius-pill {
        border-radius: var(--radius-pill);
    }

    @keyframes skeleton-shimmer {
        from {
            background-position: 200% 0;
        }
        to {
            background-position: -200% 0;
        }
    }
</style>
