/* ===========================================================================
 * F02 — Button. D28 (the interactive gold ramp), D30 (two focus rings).
 *
 * All five variants share one geometry: 40px tall, pill, 14/600 label, 24px of
 * horizontal padding, 8px icon gap. What varies is the fill.
 *
 * The state rules, in order of how easily they get broken:
 *
 *   - Hover and active change the FILL, never the opacity. Opacity is reserved
 *     for `disabled` so that a hovered button and a dead one can never look
 *     alike (D28).
 *   - Loading is not disabled styling. A loading button keeps its own fill and
 *     swaps its leading icon for a spinner — it is working, not unavailable.
 *   - The label stays in the DOM while loading, hidden with `visibility` and
 *     not `display`, so the button does not resize mid-flight.
 *   - The focus ring is the component's OWN colour question: gold on a neutral
 *     button, white on a gold-filled one where gold would vanish, brick on a
 *     destructive one (D30).
 * ======================================================================== */

.ui-button {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  height: var(--button-height);
  padding: 0 var(--space-6);
  border: var(--border-width) solid transparent;
  border-radius: var(--radius-pill);
  font-family: var(--font-sans);
  font-size: var(--type-body-size);
  line-height: var(--type-body-leading);
  font-weight: var(--font-weight-semibold);
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
  background: none;
  transition: background var(--duration-fast) var(--easing-standard),
              border-color var(--duration-fast) var(--easing-standard),
              color var(--duration-fast) var(--easing-standard);
}

.ui-button:hover { text-decoration: none; }

.ui-button--full-width { width: 100%; }

/* The player shell's controls grow to the 44px touch floor. */
.shell--player .ui-button { height: var(--control-height-mobile); }

/* --- primary — the gold gradient fill ----------------------------------- */
.ui-button--primary {
  background: var(--gradient-gold);
  color: var(--text-on-gold);
}
.ui-button--primary:hover,
.ui-button--primary.is-hover { background: var(--gradient-gold-hover); }
.ui-button--primary:active,
.ui-button--primary.is-active { background: var(--gradient-gold-active); }

/* --- outline — 1px gold at rest, 100% gold plus a wash on hover ---------- */
.ui-button--outline {
  background: var(--surface-input);
  border-color: var(--gold-rest);
  color: var(--text-gold);
}
.ui-button--outline:hover,
.ui-button--outline.is-hover {
  border-color: var(--gold-100);
  background: var(--gold-wash-hover);
  color: var(--gold-100);
}
.ui-button--outline:active,
.ui-button--outline.is-active {
  border-color: var(--gold-100);
  background: var(--gold-wash-active);
  color: var(--gold-100);
}

/* --- text — the wizard's "Back". Narrower padding; the wash is the only
       thing that appears on hover, as a pill around the label. ------------ */
.ui-button--text {
  padding: 0 var(--space-3);
  color: var(--text-gold);
}
.ui-button--text:hover,
.ui-button--text.is-hover { background: var(--gold-wash-hover); color: var(--gold-100); }
.ui-button--text:active,
.ui-button--text.is-active { background: var(--gold-wash-active); color: var(--gold-100); }

/* --- destructive — the outline pattern in brick.
       There is deliberately no FILLED destructive button. A brick-filled pill
       would read as a second primary action and would be the loudest thing on
       a screen whose loudest thing should be the trophy (D27). ------------ */
.ui-button--destructive {
  background: var(--surface-input);
  border-color: var(--danger-rest);
  color: var(--danger);
}
.ui-button--destructive:hover,
.ui-button--destructive.is-hover {
  border-color: var(--danger);
  background: var(--danger-wash-hover);
  color: var(--danger-text);
}
.ui-button--destructive:active,
.ui-button--destructive.is-active {
  border-color: var(--danger);
  background: var(--danger-wash-active);
  color: var(--danger-text);
}

/* --- icon-only — a 40px circle carrying the outline pattern -------------- */
.ui-button--icon {
  width: var(--button-height);
  padding: 0;
}
.shell--player .ui-button--icon { width: var(--control-height-mobile); }

/* --- focus (D30) — a 2px ring, 2px clear of the button, whose COLOUR depends
       on the button: gold on the neutral variants, white on the gold-filled
       one where gold would vanish, brick on the destructive one so the warning
       colour carries through to the keyboard path.

       The ring is spelled out here rather than left to base.css's global
       :focus-visible. Two reasons: a component should own its own focus
       treatment rather than inherit half of it, and the catalogue's forced
       `.is-focus` class is not :focus-visible, so a colour-only rule drew
       nothing at all. ------------------------------------------------- */
.ui-button:focus-visible,
.ui-button.is-focus {
  outline: var(--focus-ring-outline);
  outline-offset: var(--focus-ring-offset);
  outline-color: var(--focus-colour-neutral);
}
.ui-button--primary:focus-visible,
.ui-button--primary.is-focus { outline-color: var(--focus-colour-on-gold); }
.ui-button--destructive:focus-visible,
.ui-button--destructive.is-focus { outline-color: var(--focus-colour-danger); }

/* --- disabled — opacity, and only here ---------------------------------- */
.ui-button:disabled,
.ui-button.is-disabled {
  cursor: not-allowed;
}
.ui-button:disabled:not(.is-loading),
.ui-button.is-disabled:not(.is-loading) {
  opacity: var(--opacity-disabled);
}

/* --- loading ------------------------------------------------------------ */
.ui-button.is-loading { cursor: progress; }

.ui-button__spinner {
  width: var(--spinner-size);
  height: var(--spinner-size);
  border: var(--spinner-stroke) solid currentcolor;
  border-top-color: transparent;
  border-radius: var(--radius-pill);
  opacity: 0.85;
  flex: none;
}

@media (prefers-reduced-motion: no-preference) {
  .ui-button__spinner { animation: ui-spin var(--duration-spin) linear infinite; }
}

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

/* A `method:` button is Rails' one-button form (D170). The form is invisible
   to layout, so the button sits in a row exactly as a link button would. */
.ui-button-form { display: contents; }

/* --- F09 Actions (D170) ----------------------------------------------------
 * A row of buttons at their natural width. Never a column: a column stretches
 * every button to its container, which is the sign-in screen's look and a
 * 920px gold bar on an admin page. */
.ui-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
}

.ui-actions--end { justify-content: flex-end; }
.ui-actions--start { justify-content: flex-start; }
.ui-actions--between { justify-content: space-between; }
