<script lang="ts">
  // v0.2 Phase 5 primitive — native <button> + token-driven styling.
  // Replaces the ~60 ad-hoc button blocks scattered across pages with
  // one grammar (primary | secondary | tertiary | destructive × sm | md | lg).
  // Bypasses Bits UI deliberately: <button> is already accessible and
  // the headless library would only add weight here.
  import type { Snippet } from "svelte";

  type Variant = "primary" | "secondary" | "tertiary" | "destructive" | "record";
  type Size = "sm" | "md" | "lg";

  interface Props {
    variant?: Variant;
    size?: Size;
    type?: "button" | "submit" | "reset";
    disabled?: boolean;
    loading?: boolean;
    fullWidth?: boolean;
    title?: string;
    ariaLabel?: string;
    onclick?: (e: MouseEvent) => void;
    children?: Snippet;
    classes?: string;
  }

  let {
    variant = "secondary" as Variant,
    size = "md" as Size,
    type = "button",
    disabled = false,
    loading = false,
    fullWidth = false,
    title,
    ariaLabel,
    onclick,
    children,
    classes = "",
  }: Props = $props();

  const sizeClass: Record<Size, string> = {
    sm: "btn-sm",
    md: "btn-md",
    lg: "btn-lg",
  };

  // Variant palette uses semantic tokens; primary fills with --color-accent
  // (amber/copper) and pairs with .btn-filled-text for AA. Destructive
  // mirrors primary on --color-danger.
  //
  // v0.3 Phase 4j — colour-grammar correction.
  //
  //   primary       blue          (was amber, now correct primary action)
  //   record        red           (globally recognised recording colour)
  //   destructive   red           (same fill as record, distinct semantic)
  //   secondary     neutral
  //   tertiary      transparent
  //
  // Brand orange (#F0620A) is reserved for the Lumotia logo / brand
  // mark only and does NOT appear here. The legacy v0.2 path (bg-accent
  // amber) still works for callers that have not migrated; --color-accent
  // points at primary blue under quietware via the tokens CSS.
  //
  // Each filled variant gains a Level-1 wireline (complement of its bg).
  // HC contract zeroes --wire-width so the effect vanishes in HC.
  //
  // Focus state uses Level-2 width via Tailwind's ring utility. Separate
  // box-shadow slot, composes cleanly with the inset wireline.
  const variantClass: Record<Variant, string> = {
    primary:
      "bg-[var(--button-primary-bg)] text-[var(--button-primary-fg)] font-medium " +
      "hover:bg-[var(--button-primary-border)] " +
      "shadow-[inset_0_0_0_var(--wire-width,0)_color-mix(in_srgb,var(--button-primary-wire)_calc(var(--wire-opacity,0)*100%),transparent)]",
    record:
      "bg-[var(--button-record-bg)] text-[var(--button-record-fg)] font-medium " +
      "hover:bg-[var(--button-record-border)] " +
      "shadow-[inset_0_0_0_var(--wire-width,0)_color-mix(in_srgb,var(--button-record-wire)_calc(var(--wire-opacity,0)*100%),transparent)]",
    secondary:
      "bg-bg-elevated text-text border border-border-subtle hover:bg-hover",
    tertiary:
      "bg-transparent text-text-secondary hover:bg-hover hover:text-text",
    destructive:
      "bg-[var(--button-danger-bg)] text-[var(--button-danger-fg)] font-medium " +
      "hover:bg-[var(--button-danger-border)] " +
      "shadow-[inset_0_0_0_var(--wire-width,0)_color-mix(in_srgb,var(--button-danger-wire)_calc(var(--wire-opacity,0)*100%),transparent)]",
  };

  const busy = $derived(loading || disabled);
</script>

<button
  {type}
  class="rounded-lg font-medium select-none disabled:opacity-50 disabled:cursor-not-allowed
    focus-visible:outline-none
    focus-visible:ring-[var(--wire-width-focus,2px)]
    focus-visible:ring-[color-mix(in_srgb,var(--focus-ring-color,var(--color-accent))_calc(var(--wire-opacity-focus,1)*100%),transparent)]
    focus-visible:ring-offset-2 focus-visible:ring-offset-bg
    {sizeClass[size]}
    {variantClass[variant]}
    {fullWidth ? 'w-full' : ''}
    {classes}"
  style="transition-duration: var(--duration-ui)"
  disabled={busy}
  aria-busy={loading ? "true" : undefined}
  aria-label={ariaLabel}
  {title}
  {onclick}
>
  {#if loading}
    <span class="inline-block animate-spin" aria-hidden="true">⟳</span>
  {/if}
  {#if children}{@render children()}{/if}
</button>
