/**
 * ucb-button — the plugin's ONE button.
 *
 * Handle: `ucb-button`. Extracted out of shows-dashboard.css (2.55.8) for the
 * same reason ucb-dialog, ucb-explain and ucb-inline-login were: surfaces
 * OUTSIDE the dashboard need it. The report shortcodes render standalone as
 * well as embedded, and because `.btn` was locked inside the dashboard
 * stylesheet each of them grew its own button instead — `.ucb-sales-button`,
 * `.ucb-ur-btn`, plus a normalisation block in shows-dashboard.css that
 * repainted WP-admin's `.button` to look like this one. Three spellings of the
 * same control; all three are gone.
 * (Sales Pulse's `.ucb-sp-custom-apply` / `.ucb-sp-retry` are a fourth, and are
 * deliberately still bespoke — they sit in a row of Period chips and wear the
 * pill, which may be the point. Open item in TODO-shared-ui-kit.md.)
 *
 * ⚠ Reach for `.btn` before writing a new button class. A bespoke button in a
 * feature stylesheet lands at the same (0,2,0) specificity as `.btn-*:hover`,
 * so which one wins is decided by stylesheet load order — that is how a
 * refund button shipped white-on-white for an afternoon (see .btn-danger).
 *
 * Variants: .btn-primary (brand fill) · .btn-secondary (outline) ·
 * .btn-danger (destructive, fills on hover) · .btn-sm · .btn-inline ·
 * .is-busy (in-flight spinner) · .is-clean / [disabled] (muted).
 *
 * It depends on the --ucb-* custom properties. Those live on :root in
 * shows-dashboard.css today; a page that enqueues this without that file gets
 * the fallbacks declared in :root below.
 */

/* Fallback tokens ONLY, so a page that loads this file WITHOUT
 * shows-dashboard.css still renders a real button instead of an unstyled one.
 *
 * ⚠ `:where(:root)` — zero specificity, deliberately. A plain `:root` here
 * would be (0,1,0) and could overwrite another stylesheet's tokens purely on
 * load order; ucb-brevo-signup.css, for one, sets --ucb-brand to a different
 * red. At zero specificity ANY real declaration wins, whichever loads first.
 * Same trick ucb-explain.css uses for the same reason. */
:where(:root) {
  --ucb-brand: #8B2025;
  --ucb-brand-dark: #6B181C;
  --ucb-gray-50: #fafafa;
  --ucb-gray-100: #f4f4f5;
  --ucb-gray-200: #e4e4e7;
  --ucb-gray-300: #d4d4d8;
  --ucb-gray-600: #52525b;
  --ucb-red-dark: #b91c1c;
  --ucb-border-strong: #767676;
  --ucb-transition: 0.15s ease;
}

/* ── 9. Buttons ────────────────────────────────────────────── */
.btn {
  width: 100%;
  text-align: center;
  color: #fff;
  text-transform: uppercase;
  padding: 15px;
  display: block;
  font-weight: 600;
  font-size: 14px;
  border-radius: 5px;
  font-family: 'Knockout 31 Junior Middlewt', 'DM Sans', sans-serif;
  letter-spacing: 0.4px;
  margin-bottom: 0;
  border: 1px solid transparent;
  /* `.btn` is worn by <a> as well as <button> (the reports' "Clear" is a link
     that resets the query string). Without this the anchor keeps the theme's
     underline and stops matching the button beside it. */
  text-decoration: none;
  cursor: pointer;
  transition: background var(--ucb-transition), color var(--ucb-transition), border-color var(--ucb-transition);
  line-height: 1.2;
}
/* ⚠ An `<a class="btn">` is not a `<button>`. A <button> vertically centres its
   own content; an anchor does not — so the moment something gives .btn a
   min-height taller than its text (shows-dashboard.css §25c does exactly that,
   44px for touch targets on a phone) the label sits at the TOP of the box on
   every anchor button and centred on every real one. Reported on the meal
   waiver cards' "Print / PDF" beside "Sign off" and "Revoke".

   ⚠ `inline-flex`, NOT `flex`. `a.btn` is (0,1,1) and outranks `.btn-sm`,
   `.btn-inline` and `.btn-secondary` (0,1,0), which set `display: inline-block;
   width: auto` — `flex` would blockify every inline anchor button in the plugin
   and stack rows that are meant to sit side by side. `inline-flex` lays out
   identically to `inline-block` while gaining the centring. (It still loses to
   `.btn[hidden]` at (0,2,0), so `hidden` keeps working; and a flex box ignores
   `text-align`, which is why `justify-content` is set too.)
   All four anchor .btns in the plugin are `btn btn-secondary btn-sm` today —
   verified before widening this. */
a.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

/* Inline variant for buttons that shouldn't be full-width */
/* An author `display` defeats the [hidden] attribute (convention 33), and
   .btn sets one above — so every JS `btn.hidden = true` in the dashboard is
   a silent no-op without this. */
.btn[hidden] { display: none; }

.btn-inline {
  display: inline-block;
  width: auto;
}
.btn:focus-visible {
  outline: 2px solid var(--ucb-brand);
  outline-offset: 2px;
}
.btn-primary {
  background: var(--ucb-brand);
  color: white;
  border-color: var(--ucb-brand);
}
/* Muted "nothing to save yet" state. Scoped to `.btn`, NOT `.btn-primary`:
   the Talent tab's per-row Save is a `.btn-secondary`, so while this rule was
   primary-only every one of those rows rendered a fully-highlighted Save
   button that was already `disabled` — it looked like the one thing on the
   card you were meant to press, and did nothing. */
.btn.is-clean,
.btn:disabled,
.btn[disabled] {
  background: var(--ucb-gray-100);
  color: var(--ucb-gray-600);
  border-color: var(--ucb-gray-200);
  cursor: not-allowed;
}
.btn-primary:hover {
  background: var(--ucb-brand-dark);
  border-color: var(--ucb-brand-dark);
}
/* ⚠ Must come AFTER every .btn-*:hover rule and out-specify it (0,3,0 beats
   their 0,2,0 — they were previously winning on source order alone). A muted
   "nothing to save" button still repainted on hover, so a disabled Save looked
   clickable the moment the pointer touched it: brand-dark for .btn-primary,
   white for the Talent tab's .btn-secondary rows. */
.btn.is-clean:hover,
.btn.is-clean:focus,
.btn:disabled:hover,
.btn:disabled:focus,
.btn[disabled]:hover,
.btn[disabled]:focus {
  background: var(--ucb-gray-100);
  color: var(--ucb-gray-600);
  border-color: var(--ucb-gray-200);
}
.btn-secondary {
  display: inline-block;
  width: auto;
  background: white;
  color: var(--ucb-gray-600);
  border-color: var(--ucb-border-strong);
}
.btn-secondary:hover {
  background: var(--ucb-gray-50);
  border-color: var(--ucb-border-strong);
}
/* Destructive action (refund, delete, revoke) — outlined so it never competes
   with .btn-primary for the eye, filling red only on hover/focus.

   ⚠ Use this rather than hand-rolling a red button in a feature's own stylesheet.
   A bespoke `.thing-danger:hover` is (0,2,0), exactly the same as
   `.btn-secondary:hover`, so the winner is decided by SOURCE ORDER — and a
   feature stylesheet or an inline <style> printed before this file loses its
   background while a literal `color:#fff` in the same rule still applies. That
   is white-on-white: the Order Diagnostics refund button shipped that way for
   an afternoon. Colours come from the -dark token tier (convention 46);
   --ucb-red is a fill/border colour and fails contrast as text.

   (`.staff-signin .is-danger` predates this and is the same wheel, reinvented
   and scoped; fold it in next time that panel is touched.) */
.btn-danger {
  display: inline-block;
  width: auto;
  background: white;
  color: var(--ucb-red-dark);
  border-color: var(--ucb-red-dark);
}
.btn-danger:hover,
.btn-danger:focus-visible {
  background: var(--ucb-red-dark);
  color: white;
  border-color: var(--ucb-red-dark);
}
/* In-flight state for any .btn that fires a request: label hidden, spinner in
   its place, clicks refused. Pair it with `disabled` and `aria-busy="true"`.

   ⚠ Doubled class (0,3,0) on purpose. `.btn:disabled:hover` is (0,3,0) and a
   busy button is normally also disabled — at (0,2,0) this rule loses on hover
   and the label flashes back mid-request.

   ⚠ The spinner colour comes from a custom property, never `currentColor`:
   The7 forces currentColor white inside its button styles (convention 33), so
   a currentColor spinner is invisible on UCB and fine on ColdTowne.

   (`.checkin-btn.is-loading` and `.qr-scan-spinner` predate this and each ship
   their own copy plus their own keyframes. Fold them in when those panels are
   next touched — the check-in button is load-bearing mid-show, so not today.) */
.btn.is-busy.is-busy {
  position: relative;
  color: transparent;
  cursor: progress;
  pointer-events: none;
}
.btn.is-busy.is-busy::after {
  content: "";
  position: absolute;
  /* inset:0 + margin:auto centres regardless of box-sizing. */
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  margin: auto;
  width: 14px;
  height: 14px;
  border: 2px solid var(--ucb-gray-300);
  border-top-color: var(--ucb-btn-spinner, var(--ucb-brand));
  border-radius: 50%;
  animation: ucb-btn-spin 0.6s linear infinite;
}
/* On a filled button the default brand spinner is brand-on-brand, i.e. invisible. */
.btn-primary.is-busy.is-busy { --ucb-btn-spinner: #fff; }
@keyframes ucb-btn-spin {
  to { transform: rotate(360deg); }
}
@media (prefers-reduced-motion: reduce) {
  /* 2.3.3 — no spin; the greyed label plus the status line still say "working". */
  .btn.is-busy.is-busy::after { animation: none; }
}
.btn-sm {
  display: inline-block;
  width: auto;
  padding: 8px 14px;
  font-size: 11px;
}
