/* ═══════════════════════════════════════════════════════════════════════════
   @devopsnext/starterkit-button-component — the entire visual definition of <Button>.
   Import once, anywhere:  import "@devopsnext/starterkit-button-component/styles.css";

   TOKEN SOURCING — remote sheet primary, this file backup:

     https://cdn.thinktalentws48.click/starterkit/colors_and_type.css

   That sheet is NOT imported here. A CSS `@import` is all-or-nothing, and it
   also ships `* { box-sizing }`, `body { background/color/font }`, a Google
   Fonts request and a pile of component classes — none of which a button
   library may impose on a host, and all of which would need a CSP allowance
   from every consumer. Hosts already on the design system load it themselves;
   standalone consumers need nothing.

   So the tokens are vendored instead, as inline fallbacks on `.ib-btn`:

       --ib-t-fg2: var(--fg2, #8b93b5);

   A CSS fallback applies only to an absent custom property, so the host's --fg2
   wins wherever it is defined and the vendored copy renders the button where it
   is not. Priority falls out of the mechanism — no load-order rule to get
   wrong, and no `@layer`.

   Two consequences worth stating, because both were live alternatives:

   1. This file declares NOTHING on :root. A layered `:root` block would also
      lose to the host correctly, but layered or not it still hands --border,
      --fg1 and --font-body to every other component on the page. Aliasing on
      .ib-btn keeps the blast radius at this component.

   2. Component rules are deliberately UNLAYERED. They must beat unlayered
      global resets (Bootstrap's `button {}`, Tailwind preflight) — and an
      unlayered class selector does, on specificity.

   The alias block below is generated: `pnpm sync:tokens` refetches the sheet,
   `pnpm sync:tokens:check` fails CI when the vendored copy drifts.
   ═══════════════════════════════════════════════════════════════════════════ */

/* @tokens:start — generated by scripts/sync-tokens.mjs, do not edit */
/* Source: @devopsnext/starterkit-theme/presets/think.css — regenerate with `pnpm sync:tokens`.
   Each alias is `var(<host token>, <vendored default>)`: the host's sheet wins
   whenever it defines the token, these values render the button when it does
   not. Scoped to .ib-btn — this file declares nothing on :root. */

.ib-btn {
  --ib-t-fg1: var(--fg1, #f0f2ff);
  --ib-t-fg2: var(--fg2, #8b93b5);
  --ib-t-primary-text: var(--primary-text, #59b3ff);
  --ib-t-primary-on-solid: var(--primary-on-solid, #ffffff);
  --ib-t-primary-channel: var(--primary-channel, 55 163 254);
  --ib-t-secondary-text: var(--secondary-text, #738296);
  --ib-t-secondary-on-solid: var(--secondary-on-solid, #ffffff);
  --ib-t-secondary-channel: var(--secondary-channel, 100 116 139);
  --ib-t-accent-text: var(--accent-text, #c8e063);
  --ib-t-accent-on-solid: var(--accent-on-solid, #0b0f19);
  --ib-t-accent-channel: var(--accent-channel, 179 211 53);
  --ib-t-success-text: var(--success-text, #6eba67);
  --ib-t-success-on-solid: var(--success-on-solid, #0b0f19);
  --ib-t-success-channel: var(--success-channel, 76 175 80);
  --ib-t-warning-text: var(--warning-text, #feb054);
  --ib-t-warning-on-solid: var(--warning-on-solid, #0b0f19);
  --ib-t-warning-channel: var(--warning-channel, 245 158 11);
  --ib-t-danger-text: var(--danger-text, #f86278);
  --ib-t-danger-on-solid: var(--danger-on-solid, #0b0f19);
  --ib-t-danger-channel: var(--danger-channel, 244 63 94);
  --ib-t-info-text: var(--info-text, #4f81cd);
  --ib-t-info-on-solid: var(--info-on-solid, #ffffff);
  --ib-t-info-channel: var(--info-channel, 35 108 211);
  --ib-t-accent-green-text: var(--accent-green-text, #c8e063);
  --ib-t-accent-green-on-solid: var(--accent-green-on-solid, #0b0f19);
  --ib-t-accent-green-channel: var(--accent-green-channel, 179 211 53);
  --ib-t-accent-pink-text: var(--accent-pink-text, #f26594);
  --ib-t-accent-pink-on-solid: var(--accent-pink-on-solid, #0b0f19);
  --ib-t-accent-pink-channel: var(--accent-pink-channel, 238 68 128);
  --ib-t-fg-muted: var(--fg-muted, rgba(255, 255, 255, 0.45));
  --ib-t-border: var(--border, rgba(255, 255, 255, 0.08));
  --ib-t-btn-outline-border: var(--btn-outline-border, rgba(255, 255, 255, 0.34));
  --ib-t-btn-outline-border-hover: var(--btn-outline-border-hover, rgba(255, 255, 255, 0.55));
  --ib-t-btn-ghost-bg: var(--btn-ghost-bg, rgba(255, 255, 255, 0.05));
  --ib-t-btn-ghost-bg-hover: var(--btn-ghost-bg-hover, rgba(255, 255, 255, 0.10));
  --ib-t-radius-chip: var(--radius-chip, 16px);
  --ib-t-radius-pill: var(--radius-pill, 9999px);
  --ib-t-gradient-primary: var(--gradient-primary, linear-gradient(135deg, var(--primary-solid, #007acd), var(--primary-solid-hover, #0171bf)));
  --ib-t-gradient-secondary: var(--gradient-secondary, linear-gradient(135deg, var(--secondary-solid, #64748b), var(--secondary-solid-hover, #5d6c82)));
  --ib-t-gradient-accent: var(--gradient-accent, linear-gradient(135deg, var(--accent-solid, #b3d335), var(--accent-solid-hover, #a6c333)));
  --ib-t-gradient-success: var(--gradient-success, linear-gradient(135deg, var(--success-solid, #4caf50), var(--success-solid-hover, #47a24c)));
  --ib-t-gradient-warning: var(--gradient-warning, linear-gradient(135deg, var(--warning-solid, #f59e0b), var(--warning-solid-hover, #e2930c)));
  --ib-t-gradient-danger: var(--gradient-danger, linear-gradient(135deg, var(--danger-solid, #f43f5e), var(--danger-solid-hover, #e13b58)));
  --ib-t-gradient-info: var(--gradient-info, linear-gradient(135deg, var(--info-solid, #0058d4), var(--info-solid-hover, #0152c5)));
  --ib-t-gradient-accent-green: var(--gradient-accent-green, linear-gradient(135deg, var(--accent-green-solid, #b3d335), var(--accent-green-solid-hover, #a6c333)));
  --ib-t-gradient-accent-pink: var(--gradient-accent-pink, linear-gradient(135deg, var(--accent-pink-solid, #ee4480), var(--accent-pink-solid-hover, #dc4078)));
  --ib-t-fg1-channel: var(--fg1-channel, 240 242 255);
  --ib-t-font-body: var(--font-body, 'Plus Jakarta Sans', system-ui, sans-serif);
  --ib-t-white-channel: var(--white-channel, 255 255 255);
}

/* Light scheme. Every family redefines its own channel and text token against
   its own scheme's --surface, so this block is a second, independent set of
   values rather than a computed flip of the dark one. */
[data-mui-color-scheme="light"] .ib-btn,
[data-theme="light"] .ib-btn {
  --ib-t-fg1: var(--fg1, #1a1d2e);
  --ib-t-fg2: var(--fg2, #5a6080);
  --ib-t-primary-text: var(--primary-text, #1b5686);
  --ib-t-primary-channel: var(--primary-channel, 39 117 180);
  --ib-t-secondary-text: var(--secondary-text, #252d39);
  --ib-t-secondary-channel: var(--secondary-channel, 62 73 89);
  --ib-t-accent-text: var(--accent-text, #576328);
  --ib-t-accent-channel: var(--accent-channel, 108 125 44);
  --ib-t-success-text: var(--success-text, #255925);
  --ib-t-success-channel: var(--success-channel, 57 122 54);
  --ib-t-warning-text: var(--warning-text, #8a5a19);
  --ib-t-warning-channel: var(--warning-channel, 181 118 32);
  --ib-t-danger-text: var(--danger-text, #7a1a2c);
  --ib-t-danger-channel: var(--danger-channel, 169 43 67);
  --ib-t-info-text: var(--info-text, #001c4b);
  --ib-t-info-channel: var(--info-channel, 0 53 125);
  --ib-t-accent-green-text: var(--accent-green-text, #576328);
  --ib-t-accent-green-channel: var(--accent-green-channel, 108 125 44);
  --ib-t-accent-pink-text: var(--accent-pink-text, #771d3e);
  --ib-t-accent-pink-channel: var(--accent-pink-channel, 165 47 90);
  --ib-t-fg-muted: var(--fg-muted, rgba(0, 0, 0, 0.45));
  --ib-t-border: var(--border, rgba(0, 0, 0, 0.14));
  --ib-t-btn-outline-border: var(--btn-outline-border, rgba(0, 0, 0, 0.24));
  --ib-t-btn-outline-border-hover: var(--btn-outline-border-hover, rgba(0, 0, 0, 0.42));
  --ib-t-btn-ghost-bg: var(--btn-ghost-bg, rgba(0, 0, 0, 0.03));
  --ib-t-btn-ghost-bg-hover: var(--btn-ghost-bg-hover, rgba(0, 0, 0, 0.06));
  --ib-t-fg1-channel: var(--fg1-channel, 26 29 46);
}

/* Same defaults for a host that ships no scheme attribute at all. Scoped to a
   root carrying neither: without that guard, a host running dark mode on a
   light-preference machine would pick these up. */
@media (prefers-color-scheme: light) {
  :root:not([data-mui-color-scheme]):not([data-theme]) .ib-btn {
    --ib-t-fg1: var(--fg1, #1a1d2e);
    --ib-t-fg2: var(--fg2, #5a6080);
    --ib-t-primary-text: var(--primary-text, #1b5686);
    --ib-t-primary-channel: var(--primary-channel, 39 117 180);
    --ib-t-secondary-text: var(--secondary-text, #252d39);
    --ib-t-secondary-channel: var(--secondary-channel, 62 73 89);
    --ib-t-accent-text: var(--accent-text, #576328);
    --ib-t-accent-channel: var(--accent-channel, 108 125 44);
    --ib-t-success-text: var(--success-text, #255925);
    --ib-t-success-channel: var(--success-channel, 57 122 54);
    --ib-t-warning-text: var(--warning-text, #8a5a19);
    --ib-t-warning-channel: var(--warning-channel, 181 118 32);
    --ib-t-danger-text: var(--danger-text, #7a1a2c);
    --ib-t-danger-channel: var(--danger-channel, 169 43 67);
    --ib-t-info-text: var(--info-text, #001c4b);
    --ib-t-info-channel: var(--info-channel, 0 53 125);
    --ib-t-accent-green-text: var(--accent-green-text, #576328);
    --ib-t-accent-green-channel: var(--accent-green-channel, 108 125 44);
    --ib-t-accent-pink-text: var(--accent-pink-text, #771d3e);
    --ib-t-accent-pink-channel: var(--accent-pink-channel, 165 47 90);
    --ib-t-fg-muted: var(--fg-muted, rgba(0, 0, 0, 0.45));
    --ib-t-border: var(--border, rgba(0, 0, 0, 0.14));
    --ib-t-btn-outline-border: var(--btn-outline-border, rgba(0, 0, 0, 0.24));
    --ib-t-btn-outline-border-hover: var(--btn-outline-border-hover, rgba(0, 0, 0, 0.42));
    --ib-t-btn-ghost-bg: var(--btn-ghost-bg, rgba(0, 0, 0, 0.03));
    --ib-t-btn-ghost-bg-hover: var(--btn-ghost-bg-hover, rgba(0, 0, 0, 0.06));
    --ib-t-fg1-channel: var(--fg1-channel, 26 29 46);
  }
}
/* @tokens:end */

/* Label colour for the transparent fills (outline, bare) — SIMPLIFIED under the
   semantic-role ABI, and this section used to be much bigger.

   Through 1.x, a design system's `*-text` tokens were tuned as accents on a
   DARK surface only: two of the old hue-named accents landed as low as
   ~1.7:1 and ~2.2:1 measured on white. Nothing guaranteed a `*-text` token
   read on its own scheme's `--surface`, so this file carried a second,
   hand-measured `--ib-light-*` layer — five literals mapped to the `-deep`
   ramp — sitting BETWEEN the public `--ib-accent-*` override and the host
   token, active in light mode only.

   The 2.0 ABI closes that gap at the source: `--<family>-text` is now defined
   as "the family AS text, >=4.5:1 on --surface" — a per-scheme guarantee the
   preset itself owes, not something this package re-derives. Dark and light
   each redefine `--<family>-text` against their own `--surface`, so a single
   fallback level is correct in both schemes and the `--ib-light-*` layer has
   nothing left to compensate for. Removing it also removes the exact class of
   bug it used to guard against — two hand-written blocks disagreeing with each
   other — because there is only one block left to disagree with itself. */

/* ── Base ─────────────────────────────────────────────────────────────────── */

.ib-btn {
  /* Overridden per tone. Neutral values so a missing data-tone still renders. */
  --ib-ch: var(--ib-t-fg1-channel);
  --ib-grad: none;
  --ib-accent: var(--ib-t-fg2);

  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  box-sizing: border-box;
  margin: 0;
  font-family: var(--ib-t-font-body);
  font-weight: 600;
  line-height: 1.2;
  text-align: center;
  text-decoration: none;
  background: none;
  border: 1px solid transparent;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition:
    filter 0.2s,
    box-shadow 0.2s,
    border-color 0.2s,
    color 0.2s,
    background-color 0.2s,
    opacity 0.2s,
    transform 0.12s;
}

.ib-btn > svg {
  flex-shrink: 0;
}

.ib-btn[data-full-width] {
  width: 100%;
}

/* ── Axis: tone ───────────────────────────────────────────────────────────── */
/* A tone publishes four custom properties and styles nothing itself. Adding a
   tone is one rule here and it composes with every fill for free.

   --ib-ch       "R G B" of the family's non-text mark — outline borders,
                 shadows, hover washes, the focus ring, the disabled treatment.
   --ib-grad     the family's ready-made solid-fill gradient (from the
                 family's own --solid / --solid-hover, so re-keying those two
                 tokens upstream re-keys this for free).
   --ib-on-solid the MEASURED ink for the solid fill and its spinner — never a
                 blind #fff guess, and correct against both the resting fill
                 and its hover state.
   --ib-accent   the label colour for the transparent fills (outline, bare).
                 Prefers the per-tone --ib-accent-* escape hatch, then the
                 family's own text token — see the note above this block. */
.ib-btn[data-tone="primary"] {
  --ib-ch: var(--ib-t-primary-channel);
  --ib-grad: var(--ib-t-gradient-primary);
  --ib-on-solid: var(--ib-t-primary-on-solid);
  --ib-accent: var(--ib-accent-primary, var(--ib-t-primary-text));
}
.ib-btn[data-tone="secondary"] {
  --ib-ch: var(--ib-t-secondary-channel);
  --ib-grad: var(--ib-t-gradient-secondary);
  --ib-on-solid: var(--ib-t-secondary-on-solid);
  --ib-accent: var(--ib-accent-secondary, var(--ib-t-secondary-text));
}
.ib-btn[data-tone="accent"] {
  --ib-ch: var(--ib-t-accent-channel);
  --ib-grad: var(--ib-t-gradient-accent);
  --ib-on-solid: var(--ib-t-accent-on-solid);
  --ib-accent: var(--ib-accent-accent, var(--ib-t-accent-text));
}
.ib-btn[data-tone="success"] {
  --ib-ch: var(--ib-t-success-channel);
  --ib-grad: var(--ib-t-gradient-success);
  --ib-on-solid: var(--ib-t-success-on-solid);
  --ib-accent: var(--ib-accent-success, var(--ib-t-success-text));
}
.ib-btn[data-tone="warning"] {
  --ib-ch: var(--ib-t-warning-channel);
  --ib-grad: var(--ib-t-gradient-warning);
  --ib-on-solid: var(--ib-t-warning-on-solid);
  --ib-accent: var(--ib-accent-warning, var(--ib-t-warning-text));
}
.ib-btn[data-tone="danger"] {
  --ib-ch: var(--ib-t-danger-channel);
  --ib-grad: var(--ib-t-gradient-danger);
  --ib-on-solid: var(--ib-t-danger-on-solid);
  --ib-accent: var(--ib-accent-danger, var(--ib-t-danger-text));
}
.ib-btn[data-tone="info"] {
  --ib-ch: var(--ib-t-info-channel);
  --ib-grad: var(--ib-t-gradient-info);
  --ib-on-solid: var(--ib-t-info-on-solid);
  --ib-accent: var(--ib-accent-info, var(--ib-t-info-text));
}
.ib-btn[data-tone="accent-green"] {
  --ib-ch: var(--ib-t-accent-green-channel);
  --ib-grad: var(--ib-t-gradient-accent-green);
  --ib-on-solid: var(--ib-t-accent-green-on-solid);
  --ib-accent: var(--ib-accent-accent-green, var(--ib-t-accent-green-text));
}
.ib-btn[data-tone="accent-pink"] {
  --ib-ch: var(--ib-t-accent-pink-channel);
  --ib-grad: var(--ib-t-gradient-accent-pink);
  --ib-on-solid: var(--ib-t-accent-pink-on-solid);
  --ib-accent: var(--ib-accent-accent-pink, var(--ib-t-accent-pink-text));
}
.ib-btn[data-tone="neutral"] {
  --ib-ch: var(--ib-t-fg1-channel);
  --ib-grad: none;
  --ib-accent: var(--ib-t-fg2);
}

/* ── Axis: size ───────────────────────────────────────────────────────────── */
/* min-height keeps every size at or above the 24px WCAG 2.5.8 target minimum
   even when a caller drops the label to a single glyph. */

.ib-btn[data-size="sm"] {
  padding: 6px 14px;
  font-size: 12px;
  min-height: 28px;
}
.ib-btn[data-size="md"] {
  padding: 10px 20px;
  font-size: 14px;
  min-height: 40px;
}
.ib-btn[data-size="lg"] {
  padding: 13px 28px;
  font-size: 15px;
  min-height: 46px;
}

/* ── Axis: shape ──────────────────────────────────────────────────────────── */

.ib-btn[data-shape="chip"] {
  border-radius: var(--ib-t-radius-chip);
}
.ib-btn[data-shape="pill"] {
  border-radius: var(--ib-t-radius-pill);
}

/* ── Axis: fill ───────────────────────────────────────────────────────────── */
/* Each fill consumes --ib-ch / --ib-grad / --ib-on-solid / --ib-accent and
   knows nothing about which tone supplied them. Hover rules are gated on
   [data-interactive], which the component renders only while the button can
   actually be pressed. */

.ib-btn[data-fill="solid"] {
  background-image: var(--ib-grad);
  /* `--ib-on-grad` is the escape hatch, not a token alias — a caller can still
     force a different ink for one button. Its own default is no longer a
     blind #fff guess: it falls to `--ib-on-solid`, the family's MEASURED ink
     for this exact fill (legible on both the resting and hovered solid), so
     the button is correct out of the box against a light-first preset instead
     of needing the override just to be readable. */
  color: var(--ib-on-grad, var(--ib-on-solid, #fff));
  border-color: transparent;
  box-shadow: 0 4px 20px rgb(var(--ib-ch) / 0.4);
}
.ib-btn[data-fill="solid"][data-interactive]:hover {
  filter: brightness(1.1);
  box-shadow: 0 6px 28px rgb(var(--ib-ch) / 0.5);
}

.ib-btn[data-fill="ghost"] {
  background-color: var(--ib-t-btn-ghost-bg);
  border-color: var(--ib-t-btn-outline-border);
  color: var(--ib-t-fg2);
}
.ib-btn[data-fill="ghost"][data-interactive]:hover {
  background-color: var(--ib-t-btn-ghost-bg-hover);
  border-color: var(--ib-t-btn-outline-border-hover);
  color: var(--ib-t-fg1);
}

.ib-btn[data-fill="outline"] {
  background-color: transparent;
  border: 2px solid rgb(var(--ib-ch));
  color: var(--ib-accent);
}
/* The hover wash is derived from the tone's own channel. The pre-library button
   drew this border from one family's mark and washed it with a different
   family's colour on hover — an outline that flashed a mismatched hue on
   press. Deriving both from --ib-ch makes that class of mismatch
   unrepresentable. */
.ib-btn[data-fill="outline"][data-interactive]:hover {
  background-color: rgb(var(--ib-ch) / 0.1);
  box-shadow: 0 0 14px rgb(var(--ib-ch) / 0.3);
}

.ib-btn[data-fill="bare"] {
  background: none;
  border-color: transparent;
  color: var(--ib-accent);
}
.ib-btn[data-fill="bare"][data-interactive]:hover {
  background-color: rgb(var(--ib-ch) / 0.08);
  color: var(--ib-t-fg1);
}

/* Sits on top of a coloured surface (gradient hero, featured card), so it is
   deliberately tone-independent: always white-on-whatever.

   KNOWN LIMIT, not fixed here: the wash below reads --ib-t-white-channel,
   which does not flip with scheme, so a light-first brand whose hero surface
   is also light gets a white wash on white. The correct fix is a
   scheme-flipping --overlay-channel emitted by @devopsnext/starterkit-theme
   (white-on-dark / near-black-on-light) with --ib-t-white-channel kept as the
   vendored fallback — but that token does not exist in the theme package or
   the published CDN sheet yet. Wiring `var(--overlay-channel, var(--ib-t-white-channel))`
   here today would make `sync:tokens:check` fail in CI, since the sync script
   throws on any --ib-t-* alias whose raw host name is absent from the live
   sheet. Sequence: add --overlay-channel to starterkit-theme's resolver →
   publish it → then wire it in here. */
.ib-btn[data-fill="translucent"] {
  background-color: rgb(var(--ib-t-white-channel) / 0.15);
  border: 2px solid rgb(var(--ib-t-white-channel) / 0.22);
  /* Escape hatch, not a token alias — see --ib-on-grad above. Translucent sits
     on an arbitrary caller-provided surface (gradient hero, featured card), so
     there is no host token this can derive from automatically; a light-first
     brand whose hero happens to be light overrides `--ib-on-translucent`
     directly. #fff stays correct by default because that surface is
     conventionally dark or saturated. */
  color: var(--ib-on-translucent, #fff);
}
.ib-btn[data-fill="translucent"][data-interactive]:hover {
  background-color: rgb(var(--ib-t-white-channel) / 0.22);
}

/* ── Press ────────────────────────────────────────────────────────────────── */
/* Not expressible at all with JS hover handlers. */

.ib-btn[data-interactive]:active {
  transform: translateY(1px);
}

/* ── Focus ────────────────────────────────────────────────────────────────── */
/* :focus-visible, not :focus — a mouse click must not leave a ring, and a
   keyboard user must always get one. Solid fills ring in --fg1 because a
   same-hue ring on a same-hue gradient is invisible; the 2px offset puts it
   on the page background either way. */

.ib-btn:focus-visible {
  outline: 2px solid var(--ib-btn-focus-ring, rgb(var(--ib-ch) / 0.95));
  outline-offset: 2px;
}
.ib-btn[data-fill="solid"]:focus-visible {
  outline-color: var(--ib-btn-focus-ring, var(--ib-t-fg1));
}

/* ── Disabled ─────────────────────────────────────────────────────────────── */
/* Both selectors every time: a <button> uses :disabled, a disabled <a> can only
   carry aria-disabled. :not([data-loading]) keeps a loading button off the dead
   treatment even though it also renders the disabled attribute. */

.ib-btn:disabled,
.ib-btn[aria-disabled="true"] {
  cursor: not-allowed;
  box-shadow: none;
  filter: none;
  transform: none;
}

.ib-btn[aria-disabled="true"] {
  pointer-events: none;
}

/* Solid keeps a wash of its own hue so identity survives — a disabled danger
   button still reads danger-red instead of collapsing into the same grey as
   every other disabled solid. The low alpha plus the muted label carries
   "inert", which is why these stay at 0.9 opacity and remain legible. */
.ib-btn[data-fill="solid"]:disabled:not([data-loading]),
.ib-btn[data-fill="solid"][aria-disabled="true"]:not([data-loading]) {
  background-image: none;
  background-color: rgb(var(--ib-ch) / 0.12);
  color: rgb(var(--ib-ch) / 0.72);
  border-color: rgb(var(--ib-ch) / 0.26);
  opacity: 0.9;
}

.ib-btn:not([data-fill="solid"]):disabled:not([data-loading]),
.ib-btn:not([data-fill="solid"])[aria-disabled="true"]:not([data-loading]) {
  color: var(--ib-t-fg-muted);
  opacity: 0.5;
}

/* ── Loading ──────────────────────────────────────────────────────────────── */

.ib-btn[data-loading] {
  cursor: progress;
  opacity: 0.92;
}

.ib-btn__spinner {
  width: 14px;
  height: 14px;
  flex-shrink: 0;
  /* Same --overlay-channel limitation as the translucent wash above — the ring
     is --ib-t-white-channel and does not flip with scheme yet. */
  border: 2px solid rgb(var(--ib-t-white-channel) / 0.4);
  /* Base rule's highlighted edge defaults to the solid-fill ink; overridden
     per fill below so translucent gets its own escape hatch instead of
     silently reusing solid's. */
  border-top-color: var(--ib-on-grad, var(--ib-on-solid, #fff));
  border-radius: 50%;
  animation: ib-btn-spin 0.7s linear infinite;
}

.ib-btn[data-fill="translucent"] .ib-btn__spinner {
  border-top-color: var(--ib-on-translucent, #fff);
}

/* Transparent fills need a currentColor spinner or it vanishes on the page bg. */
.ib-btn:not([data-fill="solid"]):not([data-fill="translucent"]) .ib-btn__spinner {
  border-color: var(--ib-t-border);
  border-top-color: currentColor;
}

@keyframes ib-btn-spin {
  to {
    transform: rotate(360deg);
  }
}

/* ── Reduced motion ───────────────────────────────────────────────────────── */
/* The spinner is slowed rather than stopped: it communicates pending state, so
   removing it entirely would remove information, not just decoration. */

@media (prefers-reduced-motion: reduce) {
  .ib-btn {
    transition: none;
  }
  .ib-btn[data-interactive]:active {
    transform: none;
  }
  .ib-btn__spinner {
    animation-duration: 1.6s;
  }
}

/* ── Forced colors (Windows high contrast) ────────────────────────────────── */
/* Gradients and alpha washes are dropped by the OS, which would leave a
   borderless block of ButtonFace. A system border restores the affordance.
   No forced-color-adjust override — the user's palette must win. */

@media (forced-colors: active) {
  .ib-btn {
    border: 1px solid ButtonText;
  }
  .ib-btn:focus-visible {
    outline: 2px solid Highlight;
  }
  .ib-btn:disabled,
  .ib-btn[aria-disabled="true"] {
    color: GrayText;
    border-color: GrayText;
    opacity: 1;
  }
}
