/* ============================================================================
 * Button — .ui-btn  (variants: primary / secondary / ghost / danger / link)
 *                   (sizes: xs / sm / md / lg, [icon], [disabled], [aria-busy])
 * ========================================================================== */

.ui-btn {
  --btn-pad-y: 9px;
  --btn-pad-x: 17px;
  --btn-font: var(--text-sm);

  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  font-family: var(--font-sans);
  font-size: var(--btn-font);
  font-weight: var(--weight-medium);
  line-height: var(--leading-tight);
  border-radius: var(--radius-sm);
  padding: var(--btn-pad-y) var(--btn-pad-x);
  cursor: pointer;
  /* Light needs a stronger line here: --border on this fill measures 1.047:1.
     why: docs/foundations.md#elevation */
  border: 1px solid var(--control-edge);
  background: var(--surface); /* code-bg: inherit — control paint; the containing surface is the ground, for a chip and for a band alike. */
  color: var(--text);
  white-space: nowrap;
  transition: background var(--dur-fast) var(--ease),
    border-color var(--dur-fast) var(--ease),
    color var(--dur-fast) var(--ease),
    transform var(--dur-fast) var(--ease),
    filter var(--dur-fast) var(--ease);
}

.ui-btn:hover {
  background: color-mix(in srgb, var(--accent) 14%, var(--surface)); /* code-bg: inherit — control paint; the containing surface is the ground, for a chip and for a band alike. */
  color: var(--strong);
}
/* The hover edge steps aside under the band: an accent edge one pixel inside an
   accent band is the second band #578 round r34 took off the focus rules, and a
   pointer resting on a focused button would put it back. The fill above is not an
   edge and stays. why: docs/foundations.md#the-focus-ring */
.ui-btn:hover:not(:focus-visible) { border-color: var(--accent); }
.ui-btn:active { transform: translateY(1px); }

.ui-btn svg { width: 16px; height: 16px; flex: none; stroke-width: 2.4; }

/* -- Variants ----------------------------------------------------------- */
.ui-btn--primary {
  background: var(--accent-strong);
  color: var(--accent-contrast);
  border-color: var(--accent-strong);
  font-weight: var(--weight-semibold);
}
.ui-btn--primary:hover {
  filter: brightness(1.1);
  color: var(--accent-contrast);
  background: var(--accent-strong);
  border-color: var(--accent-strong);
}

.ui-btn--ghost {
  background: transparent;
  border-color: transparent;
  color: var(--text);
}
.ui-btn--ghost:hover {
  background: var(--surface); /* code-bg: inherit — control paint; the containing surface is the ground, for a chip and for a band alike. */
  border-color: transparent;
  color: var(--strong);
}

.ui-btn--link {
  background: transparent;
  border-color: transparent;
  color: var(--accent);
  padding-inline: 0;
}
.ui-btn--link .ui-btn__label-slot { overflow: visible; }
.ui-btn--link[aria-busy="true"] .ui-btn__label-slot { overflow: hidden; }
.ui-btn--link .ui-btn__label { text-decoration: underline; text-underline-offset: 0.2em; }
.ui-btn.ui-btn--link:hover {
  background: transparent;
  border-color: transparent;
  color: var(--strong);
  text-decoration: underline;
}

.ui-btn--danger { color: var(--text); }
.ui-btn--danger:hover, .ui-btn--danger:focus-visible {
  color: var(--pink);
  border-color: var(--pink);
  background: color-mix(in srgb, var(--pink) 10%, transparent); /* code-bg: inherit — control paint; the containing surface is the ground, for a chip and for a band alike. */
}

/* -- Sizes -------------------------------------------------------------- */
/* why: docs/components.md#extra-small-buttons */
.ui-btn--xs { --btn-pad-y: 4.5px; --btn-pad-x: 8px; --btn-font: var(--text-xs); min-width: 24px; min-height: 24px; }
.ui-btn--xs svg { width: 13px; height: 13px; stroke-width: 2.8; }
.ui-btn--sm { --btn-pad-y: 6px; --btn-pad-x: 12px; --btn-font: calc(var(--text-sm) - 0.5px); }
.ui-btn--lg { --btn-pad-y: 13px; --btn-pad-x: 24px; --btn-font: var(--text-md); border-radius: var(--radius-md); }

/* Icon-only */
.ui-btn--icon { --btn-pad-y: 9px; padding: 9px; border-radius: var(--radius-sm); }
.ui-btn--icon.ui-btn--xs { --btn-pad-y: 4.5px; padding: 4.5px; }
.ui-btn--icon.ui-btn--sm { --btn-pad-y: 6px; padding: 6px; }

.ui-btn--block { width: 100%; }

/* -- States ------------------------------------------------------------- */
/* Off, in every variant. A disabled button has no variant identity — primary,
   secondary and danger all take the same flat pair, because the accent IS the
   "press me" and keeping a faded version of it was what put a disabled primary
   at 1.48:1 (white on a washed-out purple). Dropping the accent is most of what
   makes this read as inert; the quiet ink is the rest. #220 */
.ui-btn:disabled,
.ui-btn[aria-disabled="true"] {
  background: var(--disabled-surface); /* code-bg: inherit — control paint; the containing surface is the ground, for a chip and for a band alike. */
  border-color: var(--disabled-border);
  /* muted-ink: state — unavailable control */ color: var(--disabled-ink);
  cursor: not-allowed;
  pointer-events: none;
}
/* A ghost button draws no box when it is on, so it draws none when it is off. */
.ui-btn--ghost:disabled,
.ui-btn--ghost[aria-disabled="true"] {
  background: transparent;
  border-color: transparent;
  /* muted-ink: state — unavailable control */ color: var(--disabled-ink-bare);
}
.ui-btn--link:disabled,
.ui-btn--link[aria-disabled="true"] {
  background: transparent;
  border-color: transparent;
  /* muted-ink: state — unavailable link action */ color: var(--disabled-ink-bare);
}
/* With no box, the ink is read on whatever is behind it, so the ghost takes an ink
   set for the dullest ground: in dark 7.49 / 6.31 / 7.00 / 5.44 on --bg / --surface /
   --surface-2 / --surface-3, in light 5.85 / 6.50 / 5.49 / 5.70. The enabled ghost now uses body
   ink, keeping its words readable without changing the disabled pair. #273 cut this ink to rescue two
   dark pairs from under #220's floor; #295 re-picked --muted against the elevation
   ladder and lifted both clear, so it is the margin now rather than the rescue.

   #273 got here the long way. It first gave the ghost the flat disabled box
   instead, on the claim that nothing would get less readable. That was false:
   --bg and --surface lost up to 0.46. Then the box was rendered in a pager at
   page 1, and the boxed First and Prev read heavier than the boxless Next and
   Last beside them: the controls that were off looked like the live ones. No
   contrast table shows that. The box was reverted and this ink shipped.
   Held by src/styles/button-disabled.test.js. */

/* why: docs/components.md#busy-button-labels */
.ui-btn { position: relative; }
.ui-btn[aria-busy="true"] { pointer-events: none; }
.ui-btn[aria-busy="true"][data-btn-wired] {
  pointer-events: auto;
  filter: none;
  transform: none;
}
/* Busy keeps the resting variant paint. The disabled selector above owns the
   ordinary unavailable state; a wired busy control remains focused and must
   not flatten its action identity while work is in flight. */
.ui-btn[aria-busy="true"],
.ui-btn[aria-busy="true"]:hover,
.ui-btn[aria-busy="true"]:active {
  background: var(--surface); /* code-bg: inherit — busy paint retains the button's containing gap. */
  border-color: var(--border);
  color: var(--text);
  filter: none;
  transform: none;
}
.ui-btn[aria-busy="true"].ui-btn--primary,
.ui-btn[aria-busy="true"].ui-btn--primary:hover,
.ui-btn[aria-busy="true"].ui-btn--primary:active {
  background: var(--accent-strong); /* code-bg: inherit — busy paint retains the button's containing gap. */
  border-color: var(--accent-strong);
  color: var(--accent-contrast);
}
.ui-btn[aria-busy="true"].ui-btn--ghost,
.ui-btn[aria-busy="true"].ui-btn--ghost:hover,
.ui-btn[aria-busy="true"].ui-btn--ghost:active {
  background: transparent; /* code-bg: inherit — busy paint retains the button's containing gap. */
  border-color: transparent;
  color: var(--text);
}
.ui-btn[aria-busy="true"].ui-btn--link,
.ui-btn[aria-busy="true"].ui-btn--link:hover,
.ui-btn[aria-busy="true"].ui-btn--link:active {
  background: transparent; /* code-bg: inherit — busy paint retains the button's containing gap. */
  border-color: transparent;
  color: var(--accent);
}
.ui-btn[aria-busy="true"].ui-btn--danger,
.ui-btn[aria-busy="true"].ui-btn--danger:hover,
.ui-btn[aria-busy="true"].ui-btn--danger:active {
  background: var(--surface); /* code-bg: inherit — busy paint retains the button's containing gap. */
  border-color: var(--border);
  color: var(--text);
}
/* A caller can mark a control both busy and unavailable. The explicit marker
   keeps that ordinary disabled state from inheriting the busy variant paint. */
.ui-btn[aria-busy="true"][data-btn-disabled] {
  background: var(--disabled-surface); /* code-bg: inherit — busy+disabled keeps its containing gap. */
  border-color: var(--disabled-border);
  /* muted-ink: state — busy+disabled control */ color: var(--disabled-ink);
  cursor: not-allowed;
  pointer-events: none;
}
.ui-btn--ghost[aria-busy="true"][data-btn-disabled] {
  background: transparent; /* code-bg: inherit — busy+disabled keeps its containing gap. */
  border-color: transparent;
  /* muted-ink: state — busy+disabled ghost */ color: var(--disabled-ink-bare);
}
.ui-btn__label-slot { display: inline-grid; overflow: hidden; }
.ui-btn__label {
  grid-area: 1 / 1;
  transform: translateY(0);
}
.ui-btn[data-btn-ready] .ui-btn__label { animation: ui-btn-label-in var(--dur-med) var(--ease-out) both; }
.ui-btn[aria-busy="true"] .ui-btn__label {
  transform: translateY(100%);
  animation: ui-btn-label-out var(--dur-med) var(--ease-in) both;
}
.ui-btn[aria-busy="true"] > svg,
.ui-btn[aria-busy="true"] > span[aria-hidden="true"]:not(.ui-btn__dots) { visibility: hidden; }
.ui-btn__dots {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 4px;
  overflow: hidden;
  pointer-events: none;
}
.ui-btn__dots i {
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: currentColor;
  animation: ui-btn-dot-in var(--dur-med) var(--ease-out) both, ui-btn-dot-pulse 1.4s ease-in-out infinite; /* motion: ambient — dots pulse until the request completes */
}
.ui-btn--xs .ui-btn__dots { gap: 2px; }
.ui-btn--xs .ui-btn__dots i { width: 3px; height: 3px; }
.ui-btn--sm .ui-btn__dots { gap: 3px; }
.ui-btn--sm .ui-btn__dots i { width: 4px; height: 4px; }
.ui-btn--lg .ui-btn__dots { gap: 5px; }
.ui-btn--lg .ui-btn__dots i { width: 6px; height: 6px; }
.ui-btn__dots i:nth-child(2) { animation-delay: 0s, 0.2s; } /* motion: ambient — stagger the second pulse */
.ui-btn__dots i:nth-child(3) { animation-delay: 0s, 0.4s; } /* motion: ambient — stagger the third pulse */
@keyframes ui-btn-label-in { from { transform: translateY(100%); } to { transform: translateY(0); } }
@keyframes ui-btn-label-out { from { transform: translateY(0); } 45%, to { transform: translateY(100%); } }
@keyframes ui-btn-dot-in { from, 45% { translate: 0 24px; } to { translate: 0 0; } }
@keyframes ui-btn-dot-pulse { 0%, 100% { opacity: 1; scale: 1; } 50% { opacity: 0.3; scale: 0.8; } }
@media (prefers-reduced-motion: reduce) {
  .ui-btn, .ui-btn__label { transition: none; }
  .ui-btn[data-btn-ready] .ui-btn__label,
  .ui-btn[aria-busy="true"] .ui-btn__label { animation: none; }
  .ui-btn__dots i { animation: none; }
}

@keyframes ui-spin { to { transform: rotate(360deg); } }
