@scope (alert-ui) {
  :where(:scope) {
    /* ── Colors ── */
    --alert-bg:       var(--a-bg-muted);
    --alert-fg:       var(--a-fg);
    --alert-border:   var(--a-border-subtle);
    --alert-icon-fg:  var(--a-fg-muted);

    /* ── Layout ── */
    --alert-radius:   var(--a-radius-md);
    --alert-px:       var(--a-space-3);
    --alert-py:       var(--a-space-2);
    --alert-gap:      var(--a-space-2);

    /* ── Typography ── */
    --alert-font:        var(--a-ui-size);
    --alert-line-height: var(--a-ui-line-height, 1.5);

    /* ── SPEC-006 dunning pattern tokens ── */
    --alert-amount-font: var(--a-font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
    --alert-meta-fg:     var(--a-fg-muted);
    --alert-actions-gap: var(--a-space-2);
    --alert-actions-mt:  var(--a-space-2);
  }

  :scope {
    /* ── Base ── */
    box-sizing: border-box;
    display: flex;
    /* `align-items: start` so the leading icon and close button anchor
       to the top — keeps the icon visually paired with the first line of
       text on multi-line alerts. The leading slot's own height = body
       line-height (below) means the icon optically centers on line 1. */
    align-items: start;
    gap: var(--alert-gap);
    padding: var(--alert-py) var(--alert-px);
    border: 1px solid var(--alert-border);
    border-radius: var(--alert-radius);
    font-size: var(--alert-font);
    line-height: var(--alert-line-height);
    color: var(--alert-fg);
    background: var(--alert-bg);
  }

  /* ── Variants ── */
  :scope[variant="info"] {
    --alert-bg:      var(--a-info-muted);
    --alert-fg:      var(--a-info-text);
    --alert-border:  var(--a-info-border-subtle);
    --alert-icon-fg: var(--a-info-strong);
  }

  :scope[variant="success"] {
    --alert-bg:      var(--a-success-muted);
    --alert-fg:      var(--a-success-text);
    --alert-border:  var(--a-success-border-subtle);
    --alert-icon-fg: var(--a-success-strong);
  }

  :scope[variant="warning"] {
    --alert-bg:      var(--a-warning-muted);
    --alert-fg:      var(--a-warning-text);
    --alert-border:  var(--a-warning-border-subtle);
    --alert-icon-fg: var(--a-warning-strong);
  }

  :scope[variant="danger"] {
    --alert-bg:      var(--a-danger-muted);
    --alert-fg:      var(--a-danger-text);
    --alert-border:  var(--a-danger-border-subtle);
    --alert-icon-fg: var(--a-danger-strong);
  }

  /* `muted` and `neutral` are semantic aliases of the base — same tokens
     as the default variant, declared explicitly so the yaml enum and the
     CSS contract agree. Use cases: passive callouts (beta banners,
     tertiary notes) where the alert should read as quiet chrome rather
     than carrying tonal weight. */
  :scope[variant="muted"],
  :scope[variant="neutral"] {
    --alert-bg:      var(--a-bg-muted);
    --alert-fg:      var(--a-fg);
    --alert-border:  var(--a-border-subtle);
    --alert-icon-fg: var(--a-fg-muted);
  }

  /* ── Slots ── */
  :scope [slot="leading"] {
    flex-shrink: 0;
    color: var(--alert-icon-fg);
    /* Box height = one line of body so the icon optical-centers on the
       first line under `align-items: start`. */
    display: inline-flex;
    align-items: center;
    min-height: calc(var(--alert-font) * var(--alert-line-height));
    /* `ensure()` appends the leading-slot icon to the host, which
       puts it after any consumer-provided content in DOM order.
       Force it to the visual lead via flex `order` so the icon
       always reads first. */
    order: -1;
  }

  :scope [slot="content"] {
    flex: 1;
    min-width: 0;
  }

  /* Trailing action area — optional single button or small button group.
     flex-shrink:0 keeps it from collapsing; align-self:start anchors it
     to the first text line under the `align-items:start` root.
     `order: 1` sorts it AFTER the content slot regardless of DOM order:
     alert.js appends the auto-stamped [slot="content"] / [slot="leading"]
     *after* any author-provided [slot="action"], so without an explicit
     order the action button renders wedged between the icon and the
     message instead of trailing. content's `flex: 1` then pushes the
     action (+ close) to the right edge. Mirrors the dunning path, which
     already assigns explicit per-slot order integers. */
  :scope [slot="action"] {
    flex-shrink: 0;
    align-self: start;
    order: 1;
  }

  /* Close button is a `<button-ui icon="x" variant="ghost" size="sm">`
     stamped by alert.js — it brings its own focus ring, hover state,
     and transitions. Box height matches the leading slot so X and icon
     sit on the same first-line baseline.
     The X color tracks the alert's variant text color (e.g. success-text
     on success, danger-text on danger) instead of the default ghost
     subtle/muted — so the dismiss icon reads as part of the alert chrome
     rather than disconnected grey. */
  :scope [slot="close"] {
    flex-shrink: 0;
    /* Sort last (after content order:0 and action order:1) so the dismiss
       button is the right-most affordance. content's flex:1 pushes both
       action + close to the trailing edge. */
    order: 2;
    min-height: calc(var(--alert-font) * var(--alert-line-height));
    --button-fg-ghost: var(--alert-fg);
    --button-fg-ghost-hover: var(--alert-icon-fg);
  }

  /* ──────────────────────────────────────────────────────────────
     SPEC-006 — Dunning / Payment-Failed pattern
     ──────────────────────────────────────────────────────────────
     `pattern="dunning"` switches the alert into a billing notice
     layout. The default alert is a single-row flex container; the
     dunning mode keeps the leading icon and close button in a
     "header" row but stacks the content + actions vertically below.

     We achieve this by switching the host to `flex-wrap: wrap` and
     assigning `order` per slot. The standard alert children authored
     in arbitrary DOM order (buttons before content is the common
     consumer mistake) are visually re-ordered by these rules so the
     final layout always reads icon → content → actions → close. */

  :scope[pattern="dunning"] {
    flex-wrap: wrap;
    row-gap: var(--alert-actions-mt);
    /* Use align-items: flex-start so the leading icon hugs the top
       of the message regardless of how tall the content + actions
       column grows. */
    align-items: flex-start;
  }

  /* Visual order — icon first, then content, then actions, then
     close. Source DOM order is irrelevant under these rules. The
     `order` integers leave room (10/20/30/40) for future expansion
     without renumbering. */
  :scope[pattern="dunning"] [slot="leading"]   { order: 10; }
  :scope[pattern="dunning"] [slot="content"]   { order: 20; }
  :scope[pattern="dunning"] [slot="actions"]   { order: 30; }
  :scope[pattern="dunning"] [slot="close"]     { order: 40; }

  :scope[pattern="dunning"] [data-dunning-amount] {
    font-family: var(--alert-amount-font);
    font-variant-numeric: tabular-nums;
    font-weight: 600;
    /* Inherit color from the variant; tabular-nums + monospace make
       the amount the scannable focal datum. */
  }

  :scope[pattern="dunning"] [data-dunning-meta] {
    color: var(--alert-meta-fg);
    font-size: calc(var(--alert-font) * 0.9375);
  }

  :scope[pattern="dunning"] [data-dunning-title] {
    display: inline-block;
    margin-inline-end: var(--a-space-1, 0.25rem);
  }

  /* Actions slot — sits below the content as a row of buttons.
     `flex-basis: 100%` combined with the `order: 30` rule pushes
     the actions onto their own row after the content row. The
     padding-inline-start indents the buttons under the message
     column (so they left-align with the body text, not the leading
     icon). */
  :scope[pattern="dunning"] [slot="actions"] {
    flex-basis: 100%;
    display: flex;
    flex-wrap: wrap;
    gap: var(--alert-actions-gap);
    padding-inline-start: calc(var(--alert-font) + var(--alert-gap));
  }

  /* Lenient — when a bare button-ui carries data-dunning-action but
     no explicit slot=actions, give it the same visual order as the
     actions group so authoring oversights don't break layout. */
  :scope[pattern="dunning"] > [data-dunning-action]:not([slot]) {
    order: 30;
    flex-basis: 100%;
  }
}
