/* =====================================================================
   Vatar · components/button.css · v1.1.0 (19 Oct 2026; comments v1.3.0) · v1.5.0 (5 Nov 2026: quiet, text,
   round, split bar; see CHANGELOG.md)
   Direction B · Angular / chamfered (user pick). Spec: design-system.md §8.1.
   Load after tokens.css. Every value is a token from tokens.css; the only
   other custom properties are this file's private --_* knobs, set from tokens.

   Markup (links use the same classes on <a>):
   <button class="btn btn--primary btn--md" type="button">
     <span class="btn__face">
       <span class="btn__label">Play now</span>
       <svg class="arrow" …aria-hidden="true">…</svg>
       <span class="btn__spin" aria-hidden="true"></span>
     </span>
   </button>

   Variants: btn--primary · btn--secondary · btn--ghost · btn--icon (add to a
   variant; needs aria-label) · btn--hero (primary only, one per page).
   v1.5.0:   btn--quiet (plate, no stroke, no slab) · btn--text (lilac text action,
             no plate) · btn--round (44px icon-only circle) · .btn-split (split bar).
             Button rules: one loud (primary) button per screen; every secondary is
             btn--quiet or btn--text; small row actions are icon-only
             (btn--text btn--icon or btn--round); two quiet actions side by side
             are one .btn-split. Never a boxed secondary with a slab next to a primary.
   Sizes:    btn--sm 44 · btn--md 52 (default) · btn--lg 60 · btn--hero 64px face.
   States:   :hover :active :focus-visible :disabled, plus .is-loading
             (with aria-busy="true") and .is-disabled (for <a>, with
             aria-disabled="true" and no href). .is-hover / .is-active /
             .is-focus force a state for static specimens only.

   The outer element never moves: it is the hit area, the focus-ring box and
   the slab (::before). Only .btn__face moves, so the target never slides
   away from the pointer and the ring never jumps.
   ===================================================================== */

.btn {
  /* size knobs (md default) */
  --_h: var(--button-height-md);
  --_px: var(--button-padding-x-md);
  --_ch: var(--button-chamfer-md);
  --_off: var(--button-offset-md);
  --_ico: var(--button-icon-size-md);
  --_fs: var(--type-button-font-size);
  --_fw: var(--type-button-font-weight);
  --_ls: var(--type-button-letter-spacing);
  /* press travel = the slab offset; loading holds the plate half-way */
  --_travel: var(--_off);
  --_hold: calc(var(--_off) / 2);
  /* two clipped corners: top-left and bottom-right */
  --_clip: polygon(var(--_ch) 0, 100% 0, 100% calc(100% - var(--_ch)), calc(100% - var(--_ch)) 100%, 0 100%, 0 var(--_ch));

  position: relative;
  display: inline-flex;
  flex: none;
  vertical-align: top;
  isolation: isolate;
  margin: 0;
  padding: 0 var(--_off) var(--_off) 0; /* room for the slab, right and down */
  border: 0;
  border-radius: var(--button-radius);
  background: none;
  color: var(--_label);
  font-family: var(--type-button-font-family);
  font-size: var(--_fs);
  font-weight: var(--_fw);
  line-height: var(--type-button-line-height);
  letter-spacing: var(--_ls);
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
  user-select: none;
  -webkit-user-select: none;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}
.btn--sm {
  --_h: var(--button-height-sm); --_px: var(--button-padding-x-sm);
  --_ch: var(--button-chamfer-sm); --_off: var(--button-offset-sm); --_ico: var(--button-icon-size-sm);
  --_fs: var(--type-button-sm-font-size); --_ls: var(--type-button-sm-letter-spacing);
}
.btn--lg {
  --_h: var(--button-height-lg); --_px: var(--button-padding-x-lg);
  --_ch: var(--button-chamfer-lg); --_off: var(--button-offset-lg); --_ico: var(--button-icon-size-lg);
}
.btn--hero {
  --_h: var(--button-height-hero); --_px: var(--button-padding-x-hero);
  --_ch: var(--button-chamfer-hero); --_off: var(--button-offset-hero); --_ico: var(--button-icon-size-hero);
  --_fs: var(--button-hero-font-size); --_fw: var(--button-hero-font-weight);
}

/* ---------- the plate (face) ---------- */
.btn__face {
  position: relative;
  z-index: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--button-gap);
  height: var(--_h);
  padding-inline: var(--_px);
  border-radius: var(--button-radius);
  clip-path: var(--_clip);
  background-color: var(--_face);
  color: var(--_label);
  transform: translate(0, 0);
  transition:
    transform var(--button-duration-hover) var(--motion-easing-standard),
    background-color var(--button-duration-hover) var(--motion-easing-standard),
    box-shadow var(--button-duration-hover) var(--motion-easing-standard),
    color var(--button-duration-hover) var(--motion-easing-standard);
}
.btn__label, .btn svg { position: relative; z-index: 2; }
.btn svg { width: var(--_ico); height: var(--_ico); flex: none; }
.btn .arrow { transition: transform var(--button-duration-hover) var(--motion-easing-standard); }
.btn--icon .btn__face { width: var(--_h); padding-inline: 0; }

/* ---------- the slab: same chamfered plate, offset down-right (a painted sign's drop shadow) ---------- */
.btn::before {
  content: "";
  position: absolute;
  z-index: 0;
  inset: var(--_off) 0 0 var(--_off);
  clip-path: var(--_clip);
  background: var(--_slab);
}

/* secondary stroke: the face is the stroke colour, face::before is the fill inset by the stroke.
   Inner chamfer = chamfer − stroke × (2 − √2) so the stroke is even along the cut. */
.btn__face::before {
  content: "";
  position: absolute;
  z-index: 0;
  inset: var(--_stroke, 0px);
  --_chi: calc(var(--_ch) - var(--_stroke, 0px) * 0.586);
  clip-path: polygon(var(--_chi) 0, 100% 0, 100% calc(100% - var(--_chi)), calc(100% - var(--_chi)) 100%, 0 100%, 0 var(--_chi));
  background: var(--_fill, transparent);
  transition: background-color var(--button-duration-hover) var(--motion-easing-standard);
}

/* ---------- variants ---------- */
.btn--primary {
  --_face: var(--button-primary-bg);
  --_face-hover: var(--button-primary-bg-hover);
  --_face-pressed: var(--button-primary-bg-pressed);
  --_label: var(--button-primary-text);
  --_slab: repeating-linear-gradient(var(--button-stripe-angle), var(--button-primary-slab) 0 var(--space-0-5), var(--button-primary-hatch) var(--space-0-5) var(--space-1));
}
.btn--secondary {
  --_stroke: var(--button-border-width);
  --_face: var(--button-secondary-border);
  --_face-hover: var(--button-secondary-border);
  --_face-pressed: var(--button-secondary-border);
  --_fill: var(--button-secondary-bg);
  --_label: var(--button-secondary-text);
  --_slab: var(--button-secondary-slab);
}
.btn--ghost {
  --_off: 0px;
  --_face: transparent;
  --_face-hover: var(--button-ghost-bg-hover);
  --_face-pressed: var(--button-ghost-bg-pressed);
  --_label: var(--button-ghost-text);
  padding: 0;
}
.btn--ghost::before { display: none; }
.btn--ghost .btn__face { clip-path: none; }

/* ghost: four HUD corner brackets that lock on when hovered */
.btn--ghost::after {
  content: "";
  position: absolute;
  z-index: 2;
  pointer-events: none;
  inset: calc(var(--button-ghost-bracket-inset) * -1);
  background:
    linear-gradient(var(--button-ghost-bracket), var(--button-ghost-bracket)) top left / var(--button-ghost-bracket-size) var(--button-ghost-bracket-width) no-repeat,
    linear-gradient(var(--button-ghost-bracket), var(--button-ghost-bracket)) top left / var(--button-ghost-bracket-width) var(--button-ghost-bracket-size) no-repeat,
    linear-gradient(var(--button-ghost-bracket), var(--button-ghost-bracket)) top right / var(--button-ghost-bracket-size) var(--button-ghost-bracket-width) no-repeat,
    linear-gradient(var(--button-ghost-bracket), var(--button-ghost-bracket)) top right / var(--button-ghost-bracket-width) var(--button-ghost-bracket-size) no-repeat,
    linear-gradient(var(--button-ghost-bracket), var(--button-ghost-bracket)) bottom left / var(--button-ghost-bracket-size) var(--button-ghost-bracket-width) no-repeat,
    linear-gradient(var(--button-ghost-bracket), var(--button-ghost-bracket)) bottom left / var(--button-ghost-bracket-width) var(--button-ghost-bracket-size) no-repeat,
    linear-gradient(var(--button-ghost-bracket), var(--button-ghost-bracket)) bottom right / var(--button-ghost-bracket-size) var(--button-ghost-bracket-width) no-repeat,
    linear-gradient(var(--button-ghost-bracket), var(--button-ghost-bracket)) bottom right / var(--button-ghost-bracket-width) var(--button-ghost-bracket-size) no-repeat;
  opacity: 0;
  transform: scale(var(--button-ghost-bracket-scale-from));
  transition:
    opacity var(--button-duration-hover) var(--motion-easing-standard),
    transform var(--button-duration-release) var(--button-easing-release);
}

/* hero: the Vatar signal stripe before the arrow (monochrome, label colour; never amber) */
.btn--hero .btn__face { padding-right: calc(var(--button-padding-x-hero) + var(--space-12)); }
.btn--hero .btn__face::after {
  content: "";
  position: absolute;
  z-index: 1;
  top: 0;
  bottom: 0;
  right: calc(var(--space-12) + var(--space-1));
  width: var(--space-4);
  background: linear-gradient(90deg,
    var(--button-hero-stripe) 0 var(--space-1),
    transparent var(--space-1) calc(var(--space-1) * 2),
    var(--button-hero-stripe) calc(var(--space-1) * 2) calc(var(--space-1) * 3),
    transparent 0);
  transform: skewX(var(--button-hero-stripe-skew));
}
.btn--hero .arrow { position: absolute; right: var(--space-5); }

/* ---------- hover: the plate rises up-left (spring), the offset grows ---------- */
.btn.is-hover .btn__face {
  transform: translate(calc(var(--button-lift) * -1), calc(var(--button-lift) * -1));
  background-color: var(--_face-hover);
  transition-duration: var(--button-duration-release);
  transition-timing-function: var(--button-easing-release);
}
@media (hover: hover) {
  .btn:not(:disabled):not(.is-disabled):not(.is-loading):hover .btn__face {
    transform: translate(calc(var(--button-lift) * -1), calc(var(--button-lift) * -1));
    background-color: var(--_face-hover);
    transition-duration: var(--button-duration-release);
    transition-timing-function: var(--button-easing-release);
  }
}
.btn--secondary.is-hover .btn__face::before { background-color: var(--button-secondary-bg-hover); }
@media (hover: hover) {
  .btn--secondary:not(:disabled):not(.is-disabled):not(.is-loading):hover .btn__face::before { background-color: var(--button-secondary-bg-hover); }
}
.btn--ghost.is-hover .btn__face { transform: none; }
@media (hover: hover) {
  .btn--ghost:not(:disabled):not(.is-disabled):not(.is-loading):hover .btn__face { transform: none; }
}
.btn--ghost.is-hover::after { opacity: 1; transform: scale(1); }
@media (hover: hover) {
  .btn--ghost:not(:disabled):not(.is-disabled):not(.is-loading):hover::after { opacity: 1; transform: scale(1); }
}
.btn.is-hover .arrow { transform: translateX(var(--motion-distance-nudge)); }
@media (hover: hover) {
  .btn:not(:disabled):not(.is-disabled):not(.is-loading):hover .arrow { transform: translateX(var(--motion-distance-nudge)); }
}

/* ---------- pressed: the plate slides flush onto its slab (60ms, exit easing) ---------- */
.btn:not(:disabled):not(.is-disabled):not(.is-loading):active .btn__face,
.btn.is-active .btn__face {
  transform: translate(var(--_travel), var(--_travel));
  background-color: var(--_face-pressed);
  transition-duration: var(--button-duration-press);
  transition-timing-function: var(--button-easing-press);
}
.btn--secondary:not(:disabled):not(.is-disabled):not(.is-loading):active .btn__face::before,
.btn--secondary.is-active .btn__face::before { background-color: var(--button-secondary-bg-pressed); }
.btn--ghost:not(:disabled):not(.is-disabled):not(.is-loading):active .btn__face,
.btn--ghost.is-active .btn__face { transform: none; }
.btn--ghost:not(:disabled):not(.is-disabled):not(.is-loading):active::after,
.btn--ghost.is-active::after { opacity: 1; transform: scale(var(--button-ghost-bracket-scale-press)); transition-duration: var(--button-duration-press); }

/* ---------- focus-visible: a 2px lilac rectangle around plate + slab (HUD selection box) ---------- */
.btn:focus-visible, .btn.is-focus { outline: var(--focus-ring-width) solid var(--focus-ring-color); outline-offset: var(--focus-ring-offset); }
.btn:focus:not(:focus-visible) { outline: none; }

/* ---------- loading: plate held half-down, hazard stripes scroll across the face ---------- */
.btn.is-loading { cursor: progress; }
.btn.is-loading .btn__label, .btn.is-loading .arrow, .btn.is-loading .btn__face > svg { visibility: hidden; }
.btn__spin {
  display: none;
  position: absolute;
  z-index: 3;
  left: 50%;
  top: 50%;
  width: var(--space-5);
  height: var(--space-5);
  margin: calc(var(--space-5) / -2) 0 0 calc(var(--space-5) / -2);
  border-radius: var(--radius-pill); /* the spinner is a ring, not a button shape */
  border: var(--border-width-thick) solid currentColor;
  border-right-color: transparent;
  animation: btn-spin var(--motion-duration-entrance) var(--motion-easing-linear) infinite;
}
.btn.is-loading .btn__spin { display: block; }
.btn.is-loading .btn__face { transform: translate(var(--_hold), var(--_hold)); }
.btn.is-loading .btn__face::before {
  background-image: repeating-linear-gradient(var(--button-stripe-angle), var(--button-loading-stripe) 0 var(--space-2), transparent var(--space-2) var(--space-4));
  background-size: calc(var(--space-4) * 1.4142) 100%;
  animation: btn-stripe var(--motion-duration-entrance) var(--motion-easing-linear) infinite;
}
.btn--primary.is-loading .btn__face::before { inset: 0; clip-path: none; }
.btn--hero.is-loading .btn__face::after { visibility: hidden; }
.btn--ghost.is-loading .btn__face { transform: none; }
.btn--ghost.is-loading::after { opacity: 1; transform: scale(1); }
@keyframes btn-spin { to { transform: rotate(360deg); } }
@keyframes btn-stripe { to { background-position: calc(var(--space-4) * 1.4142) 0; } }

/* ---------- disabled: plate pushed flush onto its slab, flat colours ---------- */
.btn:disabled, .btn.is-disabled {
  cursor: not-allowed;
  --_face: var(--button-primary-bg-disabled);
  --_label: var(--button-primary-text-disabled);
  --_slab: var(--button-primary-bg-disabled);
  --_fill: var(--button-primary-bg-disabled);
}
.btn--secondary:disabled, .btn--secondary.is-disabled {
  --_face: var(--button-secondary-border-disabled);
  --_fill: var(--button-secondary-bg);
  --_label: var(--button-secondary-text-disabled);
}
.btn--ghost:disabled, .btn--ghost.is-disabled { --_face: transparent; --_fill: transparent; --_label: var(--button-ghost-text-disabled); }
.btn:disabled .btn__face, .btn.is-disabled .btn__face { transform: translate(var(--_off), var(--_off)); }
.btn:disabled::after, .btn.is-disabled::after { visibility: hidden; }
.btn--hero:disabled .btn__face::after, .btn--hero.is-disabled .btn__face::after { opacity: var(--opacity-disabled); }

/* =====================================================================
   v1.5.0 · 5 Nov 2026 · quiet, text, round and the split bar (app kit hand-back, owner picks 3–5 Nov)
   Placed after the disabled block on purpose: these variants keep their own plate colours when disabled.
   Shared rules for the three: no slab, no hover lift, tap highlight off, and hover only on a real
   mouse/trackpad (@media (hover: hover) and (pointer: fine)), never sticky on touch.
   ===================================================================== */
.btn--quiet, .btn--text, .btn--round {
  --button-lift: 0px;
  -webkit-tap-highlight-color: transparent;
}
.btn.btn--quiet::before, .btn.btn--text::before, .btn.btn--round::before { display: none; }

/* ---------- quiet: the chamfered plate on a soft fill, lilac label. No stroke, no slab.
   Same sizes (btn--sm / md / lg) and the same plate press as every .btn. Markup: class="btn btn--quiet btn--md". ---------- */
.btn.btn--quiet {
  --_stroke: 0px;
  --_face: var(--button-quiet-bg);
  --_face-hover: var(--button-quiet-bg);
  --_face-pressed: var(--button-quiet-bg-pressed);
  --_fill: transparent;
  --_label: var(--button-quiet-text);
}
.btn.btn--quiet:disabled, .btn.btn--quiet.is-disabled { --_label: var(--button-quiet-text-disabled); }

/* ---------- text: a lilac text action with an optional leading icon. No plate, 44px tall target.
   Markup: <a class="btn btn--text" href="…"><span class="btn__face"><svg …/><span class="btn__label">Join</span></span></a>
   Icon-only row action: add btn--icon (44 × 44, the name goes in aria-label). ---------- */
.btn.btn--text {
  --_h: var(--button-height-sm);
  --_px: var(--button-text-padding-x);
  --_off: 0px;
  --_ico: var(--button-text-icon-size);
  --_fs: var(--button-text-font-size);
  --_fw: var(--font-weight-semibold);
  --_ls: var(--font-tracking-body-sm);
  --_stroke: 0px;
  --_face: transparent;
  --_face-hover: transparent;
  --_face-pressed: transparent;
  --_fill: transparent;
  --_label: var(--button-text-text);
  padding: 0;
  border-radius: var(--radius-sm);   /* focus-ring corners only */
  font-family: var(--font-family-body);
}
.btn.btn--text .btn__face { clip-path: none; gap: calc(var(--space-1) + var(--space-0-5)); }
.btn.btn--text.btn--icon { --_ico: var(--button-round-icon-size); }
.btn.btn--text:disabled, .btn.btn--text.is-disabled { --_label: var(--button-ghost-text-disabled); }

/* ---------- round: icon-only 44px circle on the quiet fill (the one exception to button.radius 0).
   Markup: <button class="btn btn--round" type="button" aria-label="Join"><span class="btn__face"><svg …/></span></button> ---------- */
.btn.btn--round {
  --_h: var(--button-round-size);
  --_off: 0px;
  --_ico: var(--button-round-icon-size);
  --_stroke: 0px;
  --_face: var(--button-quiet-bg);
  --_face-hover: var(--button-quiet-bg);
  --_face-pressed: var(--button-quiet-bg-pressed);
  --_fill: transparent;
  --_label: var(--button-quiet-text);
  padding: 0;
  border-radius: var(--radius-pill);
}
.btn.btn--round .btn__face { width: var(--_h); padding-inline: 0; clip-path: none; border-radius: var(--radius-pill); }
.btn.btn--round:disabled, .btn.btn--round.is-disabled { --_face: var(--button-primary-bg-disabled); --_label: var(--button-quiet-text-disabled); }

/* hover: mouse and trackpad only (the plate colour; text gets a lighter label) */
@media (hover: hover) and (pointer: fine) {
  .btn.btn--quiet, .btn.btn--round { --_face-hover: var(--button-quiet-bg-hover); }
  .btn.btn--text:not(:disabled):not(.is-disabled):not(.is-loading):hover { --_label: var(--button-text-text-hover); }
}
.btn.btn--quiet.is-hover, .btn.btn--round.is-hover { --_face-hover: var(--button-quiet-bg-hover); }
.btn.btn--text.is-hover { --_label: var(--button-text-text-hover); }

/* press: text and round actions have no slab to land on, so they squeeze: scale .97 in 140ms, ease-out */
.btn.btn--text .btn__face, .btn.btn--round .btn__face {
  transition:
    transform var(--button-tap-duration) var(--button-tap-easing),
    background-color var(--button-duration-hover) var(--motion-easing-standard),
    color var(--button-duration-hover) var(--motion-easing-standard);
}
.btn.btn--text:not(:disabled):not(.is-disabled):not(.is-loading):active .btn__face, .btn.btn--text.is-active .btn__face,
.btn.btn--round:not(:disabled):not(.is-disabled):not(.is-loading):active .btn__face, .btn.btn--round.is-active .btn__face {
  transform: scale(var(--button-tap-scale));
  transition-duration: var(--button-tap-duration);
  transition-timing-function: var(--button-tap-easing);
}

/* ---------- split bar: two (or three) quiet actions sharing one rounded surface, a hairline between.
   For a pair of equal secondaries (e.g. Profile · Join). Items tint on press at once, like list rows.
   Markup: <div class="btn-split"><button class="btn-split__item" type="button"><svg …/><span>Profile</span></button>…</div> ---------- */
.btn-split {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: minmax(0, 1fr);
  border-radius: var(--button-split-radius);
  background: var(--button-split-bg);
  overflow: hidden;
}
.btn-split__item {
  appearance: none;
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  min-width: 0;
  height: var(--button-split-height);
  margin: 0;
  padding: 0 var(--space-3);
  border: 0;
  background: none;
  color: var(--button-split-text);
  font: var(--font-weight-semibold) var(--font-size-mobile-body)/1 var(--font-family-body);
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
  user-select: none;
  -webkit-user-select: none;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
  transition: background-color var(--motion-duration-fast) var(--motion-easing-standard);
}
.btn-split__item svg { width: var(--button-split-icon-size); height: var(--button-split-icon-size); flex: none; }
.btn-split__item > span { overflow: hidden; text-overflow: ellipsis; }
.btn-split__item + .btn-split__item::before {
  content: "";
  position: absolute;
  left: 0;
  top: var(--button-split-divider-inset);
  bottom: var(--button-split-divider-inset);
  width: var(--border-width-hairline);
  background: var(--button-split-divider);
}
.btn-split__item:active, .btn-split__item.is-active { background-color: var(--button-split-bg-pressed); transition-duration: 0ms; }
@media (hover: hover) and (pointer: fine) { .btn-split__item:hover { background-color: var(--button-split-bg-pressed); } }
.btn-split__item:focus-visible, .btn-split__item.is-focus { outline: var(--focus-ring-width) solid var(--focus-ring-color); outline-offset: calc(var(--focus-ring-width) * -1); }
.btn-split__item:focus:not(:focus-visible) { outline: none; }
.btn-split__item:disabled { cursor: not-allowed; color: var(--button-quiet-text-disabled); }

/* ---------- reduced motion: no lift, spring, bracket zoom or animated stripes.
   The press still shows as an instant (unanimated) shift plus the pressed colour (WCAG 2.3.3).
   button.lift, the bracket scales and motion.easing.spring are already neutralised in tokens.css. ---------- */
@media (prefers-reduced-motion: reduce) {
  .btn__face, .btn::before, .btn::after, .btn__face::before, .btn .arrow {
    transition-property: background-color, color, box-shadow, opacity !important;
    transition-duration: var(--motion-duration-fast) !important;
    transition-timing-function: var(--motion-easing-standard) !important;
  }
  .btn--ghost::after { transform: none !important; }
  .btn__spin { animation: none; border-right-color: currentColor; border-top-color: transparent; opacity: var(--opacity-muted); }
  .btn.is-loading .btn__face::before { animation: none; }
  /* v1.5.0: text and round actions don't squeeze (button.tap.scale is already 1 via motion.scale.press) */
  .btn.btn--text .btn__face, .btn.btn--round .btn__face { transform: none !important; }
}

/* ---------- forced colours (Windows High Contrast): real border, decorative layers drop out ---------- */
@media (forced-colors: active) {
  .btn__face { border: var(--border-width-thick) solid ButtonText; }
  .btn::before, .btn::after, .btn__face::before, .btn__face::after { forced-color-adjust: auto; background: none !important; }
  .btn-split { border: var(--border-width-thick) solid ButtonText; }
}
