/* ==========================================================================
   .tp-button — P1.F2.T3
   ©2026 Vexstorm Studios – All Rights Reserved

   Variants   --primary  --secondary  --ghost  --danger  --icon  --small  --block
   Elements   __icon  __label  __spinner
   States     :hover  :active  :focus-visible  :disabled  [aria-disabled]  .tp-is-loading

   Every variant is at least 24x24 CSS px (ACC-006) and in practice 40px tall,
   which is the comfortable target for a tool used for hours. The focus ring
   comes from utilities.css; only the offset is adjusted here, and only where
   the ring would otherwise be clipped.

   A destructive action is --danger *and* says what it destroys in its label.
   Colour is never the only signal that an action is irreversible (ACC-004).
   ========================================================================== */

.tp-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--tp-space-2);
  min-height: var(--tp-space-8);
  min-width: var(--tp-space-target-min);
  padding: var(--tp-space-2) var(--tp-space-5);
  border: var(--tp-border-width-hairline) solid transparent;
  border-radius: var(--tp-radius-md);
  background-color: var(--tp-color-surface-raised);
  color: var(--tp-color-text-primary);
  font-family: var(--tp-font-sans);
  font-size: var(--tp-text-sm);
  font-weight: var(--tp-weight-medium);
  line-height: var(--tp-leading-tight);
  text-align: center;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
  transition:
    background-color var(--tp-motion-duration-fast) var(--tp-motion-ease-standard),
    border-color var(--tp-motion-duration-fast) var(--tp-motion-ease-standard),
    color var(--tp-motion-duration-fast) var(--tp-motion-ease-standard);
}

.tp-button:hover {
  background-color: var(--tp-color-surface-sunken);
}

.tp-button:active {
  background-color: var(--tp-color-accent-subtle);
}

.tp-button:disabled,
.tp-button[aria-disabled="true"] {
  opacity: var(--tp-opacity-disabled);
  cursor: not-allowed;
  /* A disabled control must not appear to respond. */
  background-color: var(--tp-color-surface-sunken);
  color: var(--tp-color-text-muted);
  pointer-events: none;
}

/* --------------------------------------------------------------------------
   Variants
   -------------------------------------------------------------------------- */

/* The single most important action on a page. At most one per view. */
.tp-button--primary {
  background-color: var(--tp-color-accent-default);
  border-color: var(--tp-color-accent-default);
  color: var(--tp-color-text-on-accent);
}

.tp-button--primary:hover {
  background-color: var(--tp-color-accent-hover);
  border-color: var(--tp-color-accent-hover);
}

.tp-button--primary:active {
  background-color: var(--tp-color-accent-active);
  border-color: var(--tp-color-accent-active);
}

/* The default action shape: a visible boundary, no fill. border-default rather
   than border-subtle, because this boundary IS the control (WCAG 1.4.11). */
.tp-button--secondary {
  background-color: var(--tp-color-surface-raised);
  border-color: var(--tp-color-border-default);
  color: var(--tp-color-text-primary);
}

.tp-button--secondary:hover {
  background-color: var(--tp-color-surface-sunken);
  border-color: var(--tp-color-border-strong);
}

.tp-button--secondary:active {
  background-color: var(--tp-color-accent-subtle);
}

/* Tertiary: toolbar and table-row actions, where a row of bordered buttons
   would out-shout the data. */
.tp-button--ghost {
  background-color: transparent;
  border-color: transparent;
  color: var(--tp-color-text-secondary);
}

.tp-button--ghost:hover {
  background-color: var(--tp-color-surface-sunken);
  color: var(--tp-color-text-primary);
}

.tp-button--ghost:active {
  background-color: var(--tp-color-accent-subtle);
}

/* Destructive. Outlined rather than filled, so a delete control never becomes
   the visual default action on a page by being the loudest thing on it. */
.tp-button--danger {
  background-color: var(--tp-color-state-danger-subtle);
  border-color: var(--tp-color-state-danger);
  color: var(--tp-color-state-danger-text);
}

.tp-button--danger:hover {
  background-color: var(--tp-color-state-danger);
  border-color: var(--tp-color-state-danger);
  color: var(--tp-color-text-on-accent);
}

.tp-button--danger:active {
  border-color: var(--tp-color-state-danger);
  background-color: var(--tp-color-state-danger);
  color: var(--tp-color-text-on-accent);
}

/* Icon-only. The accessible name lives in a .tp-u-visually-hidden span or an
   aria-label; an icon-only control with neither is a defect (ACC-003). */
.tp-button--icon {
  padding: var(--tp-space-2);
  width: var(--tp-space-8);
  min-width: var(--tp-space-8);
}

.tp-button--small {
  min-height: var(--tp-space-7);
  padding: var(--tp-space-1) var(--tp-space-3);
  font-size: var(--tp-text-xs);
}

.tp-button--block {
  display: flex;
  width: 100%;
}

/* --------------------------------------------------------------------------
   Elements
   -------------------------------------------------------------------------- */

.tp-button__icon {
  width: var(--tp-space-icon);
  height: var(--tp-space-icon);
  flex: none;
}

.tp-button__label {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
}

.tp-button__spinner {
  width: var(--tp-space-icon);
  height: var(--tp-space-icon);
  flex: none;
  border: var(--tp-border-width-thick) solid currentColor;
  border-top-color: transparent;
  border-radius: var(--tp-radius-pill);
  animation: tp-button-spin var(--tp-motion-duration-slow) linear infinite;
  /* Hidden until the loading state is set, so the markup can always carry it
     and JavaScript never builds an element. */
  display: none;
}

/* --------------------------------------------------------------------------
   Runtime state — set by JavaScript, never authored into a template
   -------------------------------------------------------------------------- */

.tp-button.tp-is-loading {
  cursor: progress;
  pointer-events: none;
}

.tp-button.tp-is-loading .tp-button__spinner {
  display: block;
}

.tp-button.tp-is-loading .tp-button__icon {
  display: none;
}

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

/* --------------------------------------------------------------------------
   Focus
   -------------------------------------------------------------------------- */

.tp-button:focus-visible {
  /* Lift above adjacent buttons in a cluster so the offset ring is not painted
     underneath the next control's background. */
  position: relative;
  z-index: var(--tp-z-dropdown);
}
