@use "sass:map";
@use "../base/color" as cl;
@use "../base/border" as bo;
@use "../base/font" as ft;
@use "../base/space" as sp;
@use "../base/size" as sz;
@use "../base/variants" as vr;

// Buttons
//
// Bootstrap-shaped: one base class plus a variant class, e.g.
//   <button class="qo-btn qo-btn-primary">
//   <button class="qo-btn qo-btn-outline-danger qo-btn-sm">
//
// Every variant carries its own :hover, :active, :focus-visible and :disabled
// states — there are no separate state classes to add.
//
// Four families are generated from `$variants` (base/2.3.0):
//   qo-btn-<v>          solid fill
//   qo-btn-outline-<v>  transparent, coloured border, fills on hover
//   qo-btn-soft-<v>     tint fill, deepens on hover
//   qo-btn-link-<v>     text only, underlines on hover

$btn-padding-x: sp.$space-4 !default;  // 16px
$btn-padding-x-sm: sp.$space-3 !default;
$btn-gap: sp.$space-2 !default;

// Size ramp: (height, horizontal padding, font-size, line-height)
$btn-sizes: (
  xs: (24px, sp.$space-2, ft.$font-size-xs, ft.$line-height-xs),
  sm: (sz.$control-height-sm, $btn-padding-x-sm, ft.$font-size-sm, ft.$line-height-sm),
  md: (sz.$control-height, $btn-padding-x, ft.$font-size-md, ft.$line-height-md),
  lg: (48px, sp.$space-5, ft.$font-size-lg, ft.$line-height-lg),
) !default;

.qo-btn {
  min-height: sz.$control-height;
  padding: 0 $btn-padding-x;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: $btn-gap;
  border: bo.$border-width-sm solid transparent;
  border-radius: bo.$border-radius-md;
  background: transparent;
  color: cl.$text-dark;
  font-family: ft.$font-family-primary;
  font-size: ft.$font-size-md;
  font-weight: ft.$font-weight-medium;
  line-height: 1;
  white-space: nowrap;
  text-decoration: none;
  cursor: pointer;
  transition: background-color 0.2s ease, border-color 0.2s ease,
    color 0.2s ease, box-shadow 0.2s ease;

  // The one focus treatment for every button. `:focus-visible` so a mouse
  // click does not leave a ring behind, which is why the old hand-rolled
  // `:focus` rings were being removed screen by screen.
  &:focus-visible {
    outline: 0;
    box-shadow: cl.$focus-ring;
  }

  &:disabled,
  &.qo-disabled {
    opacity: 0.48;
    cursor: not-allowed;
    box-shadow: none;
  }

  // ---- sizes ----
  @each $name, $spec in $btn-sizes {
    &.qo-btn-#{$name} {
      min-height: nth($spec, 1);
      padding: 0 nth($spec, 2);
      font-size: nth($spec, 3);
    }
  }

  // Square icon-only button — one per size, so an icon button always lines up
  // with the text button beside it.
  &.qo-btn-icon {
    width: sz.$control-height;
    padding: 0;
    @each $name, $spec in $btn-sizes {
      &.qo-btn-#{$name} { width: nth($spec, 1); }
    }
  }

  &.qo-btn-full {
    display: flex;
    width: 100%;
  }

  &.qo-btn-pill { border-radius: bo.$border-radius-pill; }
  &.qo-btn-square { border-radius: bo.$border-radius-0; }

  // ---- solid ----
  @each $name, $spec in vr.$variants {
    &.qo-btn-#{$name} {
      background-color: map.get($spec, base);
      border-color: if($name == default, cl.$border-default, map.get($spec, base));
      color: map.get($spec, on);

      &:hover:not(:disabled):not(.qo-disabled) {
        background-color: map.get($spec, hover);
        border-color: if($name == default, cl.$border-secondary, map.get($spec, hover));
      }
      &:active:not(:disabled):not(.qo-disabled) {
        background-color: map.get($spec, active);
        border-color: if($name == default, cl.$border-secondary, map.get($spec, active));
      }
    }
  }

  // ---- outline ----
  @each $name, $spec in vr.$variants {
    &.qo-btn-outline-#{$name} {
      background-color: transparent;
      border-color: if($name == default, cl.$border-default, map.get($spec, base));
      // `ink` rather than `base`: a pale variant's own fill is unreadable as
      // text on a white page. This is what made `qo-btn-outline-default`
      // invisible before 2.3.0 — it used $text-light on a transparent ground.
      color: map.get($spec, ink);

      &:hover:not(:disabled):not(.qo-disabled) {
        background-color: map.get($spec, base);
        border-color: map.get($spec, base);
        color: map.get($spec, on);
      }
      &:active:not(:disabled):not(.qo-disabled) {
        background-color: map.get($spec, active);
        border-color: map.get($spec, active);
        color: map.get($spec, on);
      }
    }
  }

  // ---- soft / tint ----
  @each $name, $spec in vr.$variants {
    &.qo-btn-soft-#{$name} {
      background-color: map.get($spec, soft);
      border-color: transparent;
      color: map.get($spec, ink);

      &:hover:not(:disabled):not(.qo-disabled) {
        background-color: map.get($spec, base);
        color: map.get($spec, on);
      }
      &:active:not(:disabled):not(.qo-disabled) {
        background-color: map.get($spec, active);
        color: map.get($spec, on);
      }
    }
  }

  // ---- link ----
  @each $name, $spec in vr.$variants {
    &.qo-btn-link-#{$name} {
      min-height: auto;
      padding: 0;
      background: transparent;
      border-color: transparent;
      color: map.get($spec, ink);

      &:hover:not(:disabled):not(.qo-disabled) {
        color: map.get($spec, hover);
        text-decoration: underline;
      }
      &:active:not(:disabled):not(.qo-disabled) { color: map.get($spec, active); }
    }
  }
}

// A button group — adjacent buttons sharing one outline.
.qo-btn-group {
  display: inline-flex;
  align-items: center;

  > .qo-btn {
    border-radius: 0;
    &:first-child { border-radius: bo.$border-radius-md 0 0 bo.$border-radius-md; }
    &:last-child { border-radius: 0 bo.$border-radius-md bo.$border-radius-md 0; }
    &:only-child { border-radius: bo.$border-radius-md; }
    &:not(:first-child) { margin-left: -#{bo.$border-width-sm}; }
    &:hover, &:focus-visible { z-index: 1; }
  }
}
