@layer components {
/* =============================================================================
   @elements/style — buttons

   Bare <button> defaults + the .button coercion class for anchors and
   other elements. Wrapped in :where() so any single class wins.

   Intent variants:   is-primary / is-ghost / is-danger

   Size variants:     is-sm / is-lg / is-hero
   Width variant:     is-block
   Chrome variant:    is-bare (strip all chrome) / is-icon (icon-only label)
   States:            is-loading / is-disabled (in addition to :disabled)

   Each variant owns ONE axis. Order doesn't matter, no hidden requirements:
     <button class="is-primary is-lg is-block">Sign up</button>
============================================================================= */

/* BASE SHAPE ---------------------------------------------------------- */

:where(button, .button) {
  display:         inline-flex;
  align-items:     center;
  justify-content: center;
  gap:             var(--space-2);
  height:          var(--button-height);
  padding:         0 var(--button-padding-x);
  font-family:     var(--font-sans);
  font-size:       var(--button-font-size);
  font-weight:     var(--button-font-weight);
  line-height:     1;
  letter-spacing:  var(--tracking-normal);
  white-space:     nowrap;
  text-decoration: none;
  background:      transparent;
  color:           var(--ink);
  border:          1px solid var(--rule);
  border-radius:   var(--button-radius);
  cursor:          pointer;
  user-select:     none;
  transition:
    var(--transition-colors),
    transform var(--duration-instant) var(--ease-out),
    box-shadow var(--duration-fast) var(--ease-out);
}

:where(button:hover, .button:hover) {
  background:   var(--bg-muted);
}

:where(button:active, .button:active) {
  background: var(--bg-panel);
  transform:  translateY(1px);
}

:where(button:focus-visible, .button:focus-visible) {
  outline:    none;
  box-shadow: var(--focus-ring);
}

:where(button:disabled, button[aria-disabled="true"],
       .button:disabled, .button.is-disabled, .button[aria-disabled="true"]) {
  cursor:  not-allowed;
  opacity: var(--opacity-disabled);
}

/* INTENT — PRIMARY (accent-filled) ----------------------------------- */
/* Consumes --accent. Default theme: monochrome (neutral-900). Branded   */
/* theme (e.g. themes/elements.css): brand color via --accent override.  */

button.is-primary, .button.is-primary {
  background:   var(--accent);
  color:        var(--accent-ink);
  border-color: var(--accent);
}

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

button.is-primary:active, .button.is-primary:active {
  background:   color-mix(in srgb, var(--accent) 92%, black);
  border-color: color-mix(in srgb, var(--accent) 92%, black);
}

/* INTENT — GHOST (no border, no fill) -------------------------------- */

button.is-ghost, .button.is-ghost {
  background:   transparent;
  color:        var(--ink-soft);
  border-color: transparent;
}

button.is-ghost:hover, .button.is-ghost:hover {
  background:   var(--bg-panel);
  color:        var(--ink);
  border-color: transparent;
}

button.is-ghost:active, .button.is-ghost:active {
  background: var(--bg-canvas);
}

/* INTENT — DANGER (red-filled) -------------------------------------- */
/* Hover derives from --danger with color-mix rather than --danger-ink:  */
/* in dark mode --danger-ink is a light text tint, not a fill color.     */

button.is-danger, .button.is-danger {
  background:   var(--danger);
  color:        var(--white);
  border-color: var(--danger);
}

button.is-danger:hover, .button.is-danger:hover {
  background:   color-mix(in srgb, var(--danger) 88%, black);
  border-color: color-mix(in srgb, var(--danger) 88%, black);
}

button.is-danger:focus-visible, .button.is-danger:focus-visible {
  box-shadow: var(--focus-ring-danger);
}

/* SIZE — SM ---------------------------------------------------------- */

button.is-sm, .button.is-sm {
  height:    var(--button-height-sm);
  padding:   0 var(--button-padding-x-sm);
  font-size: var(--text-xs);
}

/* SIZE — LG ---------------------------------------------------------- */

button.is-lg, .button.is-lg {
  height:    var(--button-height-lg);
  padding:   0 var(--button-padding-x-lg);
  font-size: var(--button-font-size-lg);
}

/* SIZE — HERO -------------------------------------------------------- */

button.is-hero, .button.is-hero {
  height:      var(--button-height-hero);
  padding:     0 var(--space-6);
  font-size:   var(--text-md);
  font-weight: var(--weight-semibold);
}

/* WIDTH — BLOCK ------------------------------------------------------ */

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

/* CHROME — BARE (strip chrome entirely) ----------------------------- */

button.is-bare, .button.is-bare {
  height:        auto;
  padding:       0;
  background:    none;
  color:         inherit;
  border:        none;
  border-radius: 0;
}

button.is-bare:hover, .button.is-bare:hover,
button.is-bare:active, .button.is-bare:active {
  background: none;
  border:     none;
  transform:  none;
}

/* STATE — LOADING ---------------------------------------------------- */

button.is-loading, .button.is-loading {
  cursor:         progress;
  pointer-events: none;
  opacity:        var(--opacity-muted);
}

/*
   The spinner is drawn, not marked up. The base is already inline-flex with
   `gap: var(--space-2)`, so ::before slots in ahead of the label with no
   markup change — `class="is-loading"` is the whole API. Every app was
   hand-rolling the same rotating svg and keyframes.

   currentColor means it inherits the intent: white on is-primary, ink on a
   ghost. The ring is a transparent-topped border, which is why it reads as a
   spinner rather than a solid disc.
*/
button.is-loading::before, .button.is-loading::before {
  content:       "";
  width:         1em;
  height:        1em;
  flex:          none;
  border:        2px solid currentColor;
  border-top-color: transparent;
  border-radius: var(--radius-full);
  /* Literal, not --duration-slow: that token is 280ms, tuned for transitions.
     A full revolution at that speed reads as a blur. */
  animation:     elements-button-spin 700ms linear infinite;
}

/* Respect a reduced-motion preference: keep the ring, drop the rotation. */
@media (prefers-reduced-motion: reduce) {
  button.is-loading::before, .button.is-loading::before {
    animation: none;
  }
}

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

/* ICON — a button whose whole label is an icon ----------------------- */
/*
   Opt in with `is-icon`. This used to auto-detect via
   `:has(> svg:only-child)`, which is wrong: `:only-child` counts ELEMENTS, so
   a button with a text label beside an icon — <button>Saving <svg/></button> —
   matched too, lost its height and padding, and silently shrank next to its
   siblings. CSS cannot tell "no other elements" from "no text either", so
   there is no guard to add and the detection had to go.

   Wrapping the label in a <span> was the workaround. It is no longer needed:
   a button styles as an icon button only when you say so.
*/

button.is-icon, .button.is-icon {
  height:        auto;
  padding:       var(--space-1-5);
  background:    none;
  color:         inherit;
  border:        none;
  border-radius: var(--radius-sm);
}

button.is-icon:hover, .button.is-icon:hover {
  background: var(--bg-panel);
  border:     none;
  transform:  none;
}

button.is-icon:active, .button.is-icon:active {
  background: var(--bg-canvas);
  border:     none;
  transform:  none;
}

/* BUTTON GROUP — adjacent buttons share borders ---------------------- */

.button-group {
  display: inline-flex;
}

.button-group > button,
.button-group > .button {
  border-radius: 0;
}

.button-group > button:first-child,
.button-group > .button:first-child {
  border-top-left-radius:    var(--button-radius);
  border-bottom-left-radius: var(--button-radius);
}

.button-group > button:last-child,
.button-group > .button:last-child {
  border-top-right-radius:    var(--button-radius);
  border-bottom-right-radius: var(--button-radius);
}

.button-group > button + button,
.button-group > .button + .button {
  margin-left: -1px;
}

.button-group > button:hover,
.button-group > .button:hover {
  z-index: var(--z-raised);
}

}
