/* v3 buttons (ADMIN_DESIGN.md core §7, reference §2). Role tokens only.
   At most one primary per screen; destructive only inside a confirm.
   Built in phase 3 for the feedback parts (dialogs, error pages, empty
   states); phase 4 adds the small/toolbar sizes with the grid. */

.lg-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  min-height: var(--control-height);
  padding: 0 var(--space-4);
  border: 1px solid transparent;
  border-radius: var(--radius-control);
  font: inherit;
  font-size: var(--size-body);
  font-weight: 500;
  line-height: 1;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
  touch-action: manipulation;
  transition: background-color var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.lg-btn:active:not(:disabled) { transform: scale(0.98); }
/* A busy button is locked (hx-disabled-elt) but keeps its colour. */
.lg-btn:disabled:not([data-lg-busy]) { background: var(--disabled-bg); border-color: transparent; color: var(--disabled-text); cursor: not-allowed; }

/* Ledger 2 levels (decisions 306, 313): primary (blue, one per header and per
   action bar) · secondary (grey fill, no border, only on --surface) · tertiary
   (ghost: text only) · icon (⋯, row tools). Approve / reject / danger are the
   special cases. Hover only where hover exists, so a tapped button never stays
   dark; press feedback stays instant on :active. */
.lg-btn--primary { background: var(--primary); color: var(--on-primary); }
.lg-btn--secondary { background: var(--secondary-fill); color: var(--text); }
.lg-btn--ghost { background: transparent; color: var(--text); }
.lg-btn--danger { background: var(--danger); color: var(--on-primary); }
.lg-btn--reject { background: var(--surface); border-color: var(--danger-border); color: var(--danger); }
/* Approve: maker/checker only (core §2 "one accent" exception). */
.lg-btn--approve { background: var(--success); color: var(--on-primary); }
@media (hover: hover) and (pointer: fine) {
  .lg-btn--primary:hover:not(:disabled) { background: var(--primary-hover); }
  .lg-btn--secondary:hover:not(:disabled) { background: var(--secondary-fill-hover); }
  .lg-btn--ghost:hover:not(:disabled) { background: var(--neutral-tint); }
  .lg-btn--danger:hover:not(:disabled) { background: color-mix(in srgb, var(--danger) 88%, var(--text)); }
  .lg-btn--reject:hover:not(:disabled) { background: var(--danger-tint); }
  .lg-btn--approve:hover:not(:disabled) { background: color-mix(in srgb, var(--success) 88%, var(--text)); }
  .lg-btn--icon:hover:not(:disabled) { color: var(--text); }
}
@media (prefers-contrast: more) {
  .lg-btn--secondary { border-color: var(--border-control); }
}

/* Small (dense toolbars, bulk bar, row actions) and icon-only. */
.lg-btn--sm { min-height: var(--control-height-sm); padding: 0 var(--space-3); font-size: var(--size-label); }
.lg-btn--icon { min-width: var(--control-height); padding: 0; color: var(--text-muted); }
.lg-btn--icon.lg-btn--sm { min-width: var(--control-height-sm); }
.lg-btn svg { flex: none; }

/* Label and busy verb share one grid cell, so the button keeps the width
   of the longer of the two ("Save" / "Saving…", reference §2). */
.lg-btn__text { display: inline-grid; }
.lg-btn__text > * { grid-area: 1 / 1; }
.lg-btn__busy { visibility: hidden; }

/* Spinner in the pressed button (reference §5): same width, label hidden
   behind it, locked by htmx (hx-disabled-elt) and aria-busy set by
   js/v3/progress.js. Works on v2 buttons too (attribute, not class). */
[data-lg-busy] {
  position: relative;
  color: transparent !important;
  pointer-events: none;
}
[data-lg-busy]::after {
  content: "";
  position: absolute;
  inset: 0;
  width: 1rem;
  height: 1rem;
  margin: auto;
  border: 2px solid var(--text-muted);
  border-right-color: transparent;
  border-radius: 50%;
  animation: lg-spin 700ms linear infinite;
}
.lg-btn--primary[data-lg-busy]::after,
.lg-btn--danger[data-lg-busy]::after,
.lg-btn--approve[data-lg-busy]::after { border-color: var(--on-primary); border-right-color: transparent; }
/* With a busy verb: spinner + verb in view (not a bare spinner). */
/* The busy verb always reserves room for the spinner, so the width never jumps. */
.lg-btn__busy { padding-inline-start: 1.5rem; }
.lg-btn[data-lg-busy]:has(.lg-btn__busy) { color: inherit !important; }
.lg-btn--primary[data-lg-busy]:has(.lg-btn__busy),
.lg-btn--danger[data-lg-busy]:has(.lg-btn__busy),
.lg-btn--approve[data-lg-busy]:has(.lg-btn__busy) { color: var(--on-primary) !important; }
.lg-btn[data-lg-busy]:has(.lg-btn__busy)::after { inset: 0 auto 0 var(--space-4); }
.lg-btn[data-lg-busy] .lg-btn__label { visibility: hidden; }
.lg-btn[data-lg-busy] .lg-btn__busy { visibility: visible; }
@keyframes lg-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  [data-lg-busy]::after { animation-duration: 1600ms; }
}

/* Motion 319 (1): after a save the button itself says "Saved" with a tick for
   1.5 s (js/v3/saved.js), green as in the preview; colour change only, no movement. */
.lg-btn--saved, .lg-btn--saved:hover { background: var(--success) !important; color: var(--on-primary) !important; }
.lg-btn__tick { flex: none; }

/* Phones: buttons are the input height, 2.75rem (Ledger 2, decision 303: "buttons
   match it"; was 2.5rem to the eye, decision 284), body-size text. The invisible
   ::before still keeps any smaller button (sm) at the 44px touch minimum
   (--touch-target; Apple HIG, WCAG 2.5.5). */
@media (max-width: 39.99em) {
  .lg-btn { position: relative; min-height: var(--touch-target); padding-inline: var(--space-3); font-size: var(--size-body); }
  .lg-btn::before {
    content: "";
    position: absolute;
    inset: calc((var(--touch-target) - 100%) / -2) 0;
    min-block-size: var(--touch-target);
  }
}
