/* Button. One box for both the <button> and the <a> form, so a control that leaves the app
   looks like the ones that do not. The label and the spinner share a single grid cell: the cell
   is sized by the label, so entering the loading state cannot change the button's width.

   Round, because a button rests on the shell (the corners rule, tokens.css). Three weights, as the
   snapshot drew them and with no accent colour: the primary is filled with
   ink and lettered in the background colour, the secondary is an ink hairline on nothing, and the
   quiet one is underlined text. Danger is the primary's shape in the one colour the palette keeps.
   Each has a fixed height from the tokens rather than a height made of padding, so a row of them
   lines up whatever the label. */
.button {
  display: inline-grid;
  grid-template-areas: "control";
  place-items: center;
  box-sizing: border-box;
  height: var(--control-height);
  font: inherit;
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  line-height: 1;
  text-align: center;
  text-decoration: none;
  white-space: nowrap;
  border: var(--hairline) solid transparent;
  border-radius: var(--radius-button);
  padding: 0 var(--space-4);
  cursor: pointer;
}

.button-label,
.button-spinner {
  grid-area: control;
}

.button:focus-visible {
  outline: var(--focus-width) solid var(--color-accent);
  outline-offset: var(--focus-offset);
}

.button-small {
  height: var(--control-height-small);
  font-size: var(--text-quiet);
  padding: 0 var(--space-3);
}

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

.button-primary:hover:not([disabled], [aria-disabled="true"]) {
  background: var(--color-accent-hover);
  border-color: var(--color-accent-hover);
}

.button-secondary {
  background: transparent;
  border-color: var(--color-ink);
  color: var(--color-ink);
}

.button-secondary:hover:not([disabled], [aria-disabled="true"]) {
  background: color-mix(in oklab, var(--color-ink) 6%, transparent);
}

/* Quiet: a way back or out. It reads as text, not as a second button: no height of its own, no
   padding, the muted colour, underlined. */
.button-quiet {
  height: auto;
  background: none;
  border-color: transparent;
  color: var(--color-muted);
  font-size: var(--text-quiet);
  font-weight: var(--weight-regular);
  text-decoration: underline;
  text-underline-offset: 0.15em;
  padding: 0;
}

.button-quiet:hover:not([disabled], [aria-disabled="true"]) {
  color: var(--color-ink);
}

.button-quiet.button-small {
  font-size: var(--text-label);
}

.button-danger {
  background: var(--color-danger);
  border-color: var(--color-danger);
  color: var(--color-danger-ink);
}

.button-danger:hover:not([disabled], [aria-disabled="true"]) {
  background: var(--color-danger-hover);
  border-color: var(--color-danger-hover);
}

/* Pressed: what this control stages is in the tray (the toggle rule). Neither filled nor plain but
   pending, as a staged thing is everywhere: a dashed rim on the panel, in ink. A second press takes
   it back out. */
.button[aria-pressed="true"]:not([disabled]) {
  background: var(--color-line-panel);
  border-color: var(--color-ink);
  border-style: dashed;
  color: var(--color-ink);
}

.button[aria-pressed="true"]:hover:not([disabled]) {
  background: var(--color-line-later);
}

/* Disabled as the snapshot draws "Release to production" before it can be pressed: the fill and
   the ink go, a hairline and the muted colour stay, so it is plainly a control and plainly not one
   to press now. */
.button[disabled],
.button[aria-disabled="true"] {
  cursor: default;
  background: transparent;
  border-color: var(--color-line);
  color: var(--color-muted);
}

.button-quiet[disabled],
.button-quiet[aria-disabled="true"] {
  border-color: transparent;
  text-decoration: none;
}

/* Loading: the label stays in the DOM, so the control keeps its accessible name and its width,
   and the spinner takes its place on screen. aria-busy is what says so out loud. A loading button
   is disabled as well, but it keeps its own face: it is the one being answered, not one that is
   not available. */
.button-loading[disabled].button-primary,
.button-loading[aria-disabled="true"].button-primary {
  background: var(--color-accent);
  border-color: var(--color-accent);
  color: var(--color-accent-ink);
}

.button-loading[disabled].button-secondary,
.button-loading[aria-disabled="true"].button-secondary {
  border-color: var(--color-ink);
  color: var(--color-ink);
}

.button-loading[disabled].button-danger,
.button-loading[aria-disabled="true"].button-danger {
  background: var(--color-danger);
  border-color: var(--color-danger);
  color: var(--color-danger-ink);
}

.button-loading .button-label {
  opacity: 0;
}

.button-spinner {
  width: 1em;
  height: 1em;
  border: var(--focus-width) solid currentColor;
  border-right-color: transparent;
  border-radius: 50%;
  animation: button-spin 0.7s linear infinite;
}

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

@media (prefers-reduced-motion: reduce) {
  .button-spinner {
    animation-duration: 2s;
  }
}
