<script lang="ts">
  // v0.2 Phase 5 primitive — inline notice block. Replaces the ~10
  // ad-hoc <div class="bg-{danger,warning,success}/10 …"> patterns
  // scattered across pages. Four tones map to the semantic tokens.
  //
  // v0.3 Phase 3 update — left-bar accent pattern. The visible status
  // signal lives on a 4-px solid left border in the tone colour, full
  // opacity. The surround uses a soft tone-tinted background + outer
  // border in the tone colour. Title and body text use --color-text;
  // icon uses the tone colour. Same accessibility role semantics
  // retained.
  //
  // v0.3 Phase 4d opacity rebalance (2026-05-15 round 4 feedback):
  //   Background    role colour at 8%  (was 10%, less heavy)
  //   Outer border  role colour at 40% (was neutral subtle)
  //   Left bar      role colour at 100% (unchanged)
  //   Icon          role colour (reverted from --color-text once the
  //                 muted-Material palette landed; previous fill-only-
  //                 on-cream concern dissolved with the new ochre
  //                 #7A5D00 light-mode caution).
  //   Title + body  --color-text (unchanged)
  //
  // Pattern matches Material Design "banner with leading accent" and
  // IBM Carbon "inline notification" guidance.
  import { Info, AlertTriangle, AlertOctagon, CheckCircle, X } from "lucide-svelte";
  import type { Snippet } from "svelte";

  type Tone = "info" | "caution" | "danger" | "success";

  interface Props {
    tone?: Tone;
    title?: string;
    dismissible?: boolean;
    onDismiss?: () => void;
    /** Slim variant collapses to a single line with no title block.
        For ambient page-level notices (eg. "You're in browser preview"). */
    slim?: boolean;
    /** v0.3 Phase 4i opt-in: render the tactile counterline as an
        inset shadow. Off by default — notices already carry enough
        semantic language without the extra decoration. Reserve for
        cases where the notice deliberately mimics control identity. */
    counterline?: boolean;
    children?: Snippet;
    classes?: string;
  }

  let {
    tone = "info" as Tone,
    title,
    dismissible = false,
    onDismiss,
    slim = false,
    counterline = false,
    children,
    classes = "",
  }: Props = $props();

  // v0.3 Phase 4g — notice usage tokens. Each tone reads four CSS
  // variables published by v0.3-quietware-tokens.css:
  //   --notice-{tone}-bar     left bar (signal-tier)
  //   --notice-{tone}-icon    icon colour (signal in dark, ink in light)
  //   --notice-{tone}-border  outer border colour
  //   --notice-{tone}-bg      hand-tuned pale tint surface
  //
  // v0.3 Phase 4h — counterlines. A subtle 1-px inset shadow in a
  // softened complementary hue. Tactile-only detail; not a second
  // semantic signal. HC contract zeroes --counterline-width.
  //
  //   --notice-{tone}-counterline   softened-complement tint
  //   --counterline-width           1px in quietware, 0 in HC
  //
  // v0.2 fallback values are defined at :root in the same tokens file
  // via color-mix from the v0.2 --color-{role} tokens, so the Notice
  // renders sensibly with or without quietware active.
  const palette: Record<Tone, { bar: string; bg: string; border: string; iconColor: string; shadow: string; icon: typeof Info }> = {
    info: {
      bar: "border-l-[var(--notice-info-bar)]",
      bg: "bg-[var(--notice-info-bg)]",
      border: "border-[var(--notice-info-border)]",
      iconColor: "text-[var(--notice-info-icon)]",
      shadow: "shadow-[inset_0_0_0_var(--counterline-width,0)_var(--notice-info-counterline,transparent)]",
      icon: Info,
    },
    caution: {
      bar: "border-l-[var(--notice-caution-bar)]",
      bg: "bg-[var(--notice-caution-bg)]",
      border: "border-[var(--notice-caution-border)]",
      iconColor: "text-[var(--notice-caution-icon)]",
      shadow: "shadow-[inset_0_0_0_var(--counterline-width,0)_var(--notice-caution-counterline,transparent)]",
      icon: AlertTriangle,
    },
    danger: {
      bar: "border-l-[var(--notice-danger-bar)]",
      bg: "bg-[var(--notice-danger-bg)]",
      border: "border-[var(--notice-danger-border)]",
      iconColor: "text-[var(--notice-danger-icon)]",
      shadow: "shadow-[inset_0_0_0_var(--counterline-width,0)_var(--notice-danger-counterline,transparent)]",
      icon: AlertOctagon,
    },
    success: {
      bar: "border-l-[var(--notice-success-bar)]",
      bg: "bg-[var(--notice-success-bg)]",
      border: "border-[var(--notice-success-border)]",
      iconColor: "text-[var(--notice-success-icon)]",
      shadow: "shadow-[inset_0_0_0_var(--counterline-width,0)_var(--notice-success-counterline,transparent)]",
      icon: CheckCircle,
    },
  };

  // Danger gets role="alert" so screen readers announce immediately;
  // the others use the less-interrupting role="status".
  const ariaRole = $derived(tone === "danger" ? "alert" : "status");
  const tonePal = $derived(palette[tone]);
  const ToneIcon = $derived(tonePal.icon);
</script>

<div
  role={ariaRole}
  class="rounded-r-lg rounded-l-sm border border-l-4 text-[13px] flex gap-2.5
    {slim ? 'px-3 py-2 items-center' : 'px-4 py-3 items-start'}
    {tonePal.bar}
    {slim ? 'border-border-subtle' : tonePal.border}
    {tonePal.bg} {counterline ? tonePal.shadow : ''} {classes}"
>
  <ToneIcon size={slim ? 14 : 16} class="shrink-0 {slim ? '' : 'mt-0.5'} {tonePal.iconColor}" aria-hidden="true" />
  <div class="flex-1 min-w-0 leading-relaxed text-text">
    {#if title && !slim}
      <p class="font-semibold text-text mb-1">{title}</p>
    {/if}
    {#if children}{@render children()}{/if}
  </div>
  {#if dismissible}
    <button
      type="button"
      class="shrink-0 text-text-tertiary hover:text-text size-5 flex items-center justify-center rounded"
      aria-label="Dismiss notice"
      onclick={onDismiss}
    >
      <X size={14} />
    </button>
  {/if}
</div>
