@use './button-base';
@use '../core/style/private' as style-private;
@use '../core/style/vendor-prefixes';
@use '../core/tokens/token-utils';
@use '../core/focus-indicators/private' as focus-indicators-private;
@use './m3-button';

$fallbacks: m3-button.get-tokens();

.mat-mdc-button-base {
  text-decoration: none;
  // Makes button icon not cut off/shrink making the icon visible to fix b/411228600
  & .mat-icon {
    // stylelint-disable material/no-prefixes
    min-height: fit-content;
    flex-shrink: 0;
  }

  // Hide the hover ripple on devices that don't support hover. Note that we have the `span`
  // in the selector in order to increase the specificity over the actual hover styles.
  @media (hover: none) {
    &:hover > span.mat-mdc-button-persistent-ripple::before {
      opacity: 0;
    }
  }
}

.mdc-button {
  @include vendor-prefixes.user-select(none);
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  box-sizing: border-box;
  min-width: 64px;
  border: none;
  outline: none;
  line-height: inherit;
  -webkit-appearance: none;
  overflow: visible;
  vertical-align: middle;
  background: transparent;
  padding: 0 8px;

  &::-moz-focus-inner {
    padding: 0;
    border: 0;
  }

  &:active {
    outline: none;
  }

  &:hover {
    cursor: pointer;
  }

  &:disabled {
    cursor: default;
    pointer-events: none;
  }

  &[hidden] {
    display: none;
  }

  .mdc-button__label {
    position: relative;
  }
}

.mat-mdc-button {
  padding: 0 #{token-utils.slot(button-text-horizontal-padding, $fallbacks, true)};
  height: token-utils.slot(button-text-container-height, $fallbacks);
  font-family: token-utils.slot(button-text-label-text-font, $fallbacks);
  font-size: token-utils.slot(button-text-label-text-size, $fallbacks);
  letter-spacing: token-utils.slot(button-text-label-text-tracking, $fallbacks);
  text-transform: token-utils.slot(button-text-label-text-transform, $fallbacks);
  font-weight: token-utils.slot(button-text-label-text-weight, $fallbacks);

  &, .mdc-button__ripple {
    border-radius: token-utils.slot(button-text-container-shape, $fallbacks);
  }

  &:not(:disabled) {
    color: token-utils.slot(button-text-label-text-color, $fallbacks);
  }

  // We need to re-apply the disabled tokens since MDC uses
  // `:disabled` which doesn't apply to anchors.
  @include button-base.mat-private-button-disabled {
    color: token-utils.slot(button-text-disabled-label-text-color, $fallbacks);
  }

  @include button-base.mat-private-button-horizontal-layout(
      button-text-icon-spacing, button-text-icon-offset,
      button-text-with-icon-horizontal-padding, $fallbacks);
  @include button-base.mat-private-button-ripple(
      button-text-ripple-color, button-text-state-layer-color,
      button-text-disabled-state-layer-color,
      button-text-hover-state-layer-opacity, button-text-focus-state-layer-opacity,
      button-text-pressed-state-layer-opacity, $fallbacks);
  @include button-base.mat-private-button-touch-target(false,
    button-text-touch-target-size, button-text-touch-target-display, $fallbacks);
}

.mat-mdc-unelevated-button {
  transition: box-shadow 280ms cubic-bezier(0.4, 0, 0.2, 1);
  height: token-utils.slot(button-filled-container-height, $fallbacks);
  font-family: token-utils.slot(button-filled-label-text-font, $fallbacks);
  font-size: token-utils.slot(button-filled-label-text-size, $fallbacks);
  letter-spacing: token-utils.slot(button-filled-label-text-tracking, $fallbacks);
  text-transform: token-utils.slot(button-filled-label-text-transform, $fallbacks);
  font-weight: token-utils.slot(button-filled-label-text-weight, $fallbacks);
  padding: 0 #{token-utils.slot(button-filled-horizontal-padding, $fallbacks, true)};

  @include button-base.mat-private-button-horizontal-layout(
      button-filled-icon-spacing, button-filled-icon-offset, null, $fallbacks);
  @include button-base.mat-private-button-ripple(
      button-filled-ripple-color, button-filled-state-layer-color,
      button-filled-disabled-state-layer-color,
      button-filled-hover-state-layer-opacity, button-filled-focus-state-layer-opacity,
      button-filled-pressed-state-layer-opacity, $fallbacks);
  @include button-base.mat-private-button-touch-target(false,
    button-filled-touch-target-size, button-filled-touch-target-display, $fallbacks);

  &:not(:disabled) {
    color: token-utils.slot(button-filled-label-text-color, $fallbacks);
    background-color: token-utils.slot(button-filled-container-color, $fallbacks);
  }

  &, .mdc-button__ripple {
    border-radius: token-utils.slot(button-filled-container-shape, $fallbacks);
  }

  // We need to re-apply the disabled tokens since MDC uses
  // `:disabled` which doesn't apply to anchors.
  @include button-base.mat-private-button-disabled {
    color: token-utils.slot(button-filled-disabled-label-text-color, $fallbacks);
    background-color: token-utils.slot(button-filled-disabled-container-color, $fallbacks);
  }
}

.mat-mdc-raised-button {
  transition: box-shadow 280ms cubic-bezier(0.4, 0, 0.2, 1);
  box-shadow: token-utils.slot(button-protected-container-elevation-shadow, $fallbacks);
  height: token-utils.slot(button-protected-container-height, $fallbacks);
  font-family: token-utils.slot(button-protected-label-text-font, $fallbacks);
  font-size: token-utils.slot(button-protected-label-text-size, $fallbacks);
  letter-spacing: token-utils.slot(button-protected-label-text-tracking, $fallbacks);
  text-transform: token-utils.slot(button-protected-label-text-transform, $fallbacks);
  font-weight: token-utils.slot(button-protected-label-text-weight, $fallbacks);
  padding: 0 #{token-utils.slot(button-protected-horizontal-padding, $fallbacks, true)};

  @include button-base.mat-private-button-horizontal-layout(
      button-protected-icon-spacing, button-protected-icon-offset, null, $fallbacks);
  @include button-base.mat-private-button-ripple(
      button-protected-ripple-color, button-protected-state-layer-color,
      button-protected-disabled-state-layer-color,
      button-protected-hover-state-layer-opacity, button-protected-focus-state-layer-opacity,
      button-protected-pressed-state-layer-opacity, $fallbacks);
  @include button-base.mat-private-button-touch-target(false,
      button-protected-touch-target-size, button-protected-touch-target-display, $fallbacks);

  &:not(:disabled) {
    color: token-utils.slot(button-protected-label-text-color, $fallbacks);
    background-color: token-utils.slot(button-protected-container-color, $fallbacks);
  }

  &, .mdc-button__ripple {
    border-radius: token-utils.slot(button-protected-container-shape, $fallbacks);
  }

  @media (hover: hover) {
    &:hover {
      box-shadow: token-utils.slot(button-protected-hover-container-elevation-shadow, $fallbacks);
    }
  }

  &:focus {
    box-shadow: token-utils.slot(button-protected-focus-container-elevation-shadow, $fallbacks);
  }

  &:active, &:focus:active {
    box-shadow: token-utils.slot(button-protected-pressed-container-elevation-shadow, $fallbacks);
  }

  // We need to re-apply the disabled tokens since MDC uses
  // `:disabled` which doesn't apply to anchors.
  @include button-base.mat-private-button-disabled {
    color: token-utils.slot(button-protected-disabled-label-text-color, $fallbacks);
    background-color: token-utils.slot(button-protected-disabled-container-color, $fallbacks);

    &.mat-mdc-button-disabled {
      box-shadow: token-utils.slot(
          button-protected-disabled-container-elevation-shadow, $fallbacks);
    }
  }
}

.mat-mdc-outlined-button {
  border-style: solid;
  transition: border 280ms cubic-bezier(0.4, 0, 0.2, 1);
  height: token-utils.slot(button-outlined-container-height, $fallbacks);
  font-family: token-utils.slot(button-outlined-label-text-font, $fallbacks);
  font-size: token-utils.slot(button-outlined-label-text-size, $fallbacks);
  letter-spacing: token-utils.slot(button-outlined-label-text-tracking, $fallbacks);
  text-transform: token-utils.slot(button-outlined-label-text-transform, $fallbacks);
  font-weight: token-utils.slot(button-outlined-label-text-weight, $fallbacks);
  border-radius: token-utils.slot(button-outlined-container-shape, $fallbacks);
  border-width: token-utils.slot(button-outlined-outline-width, $fallbacks);
  padding: 0 #{token-utils.slot(button-outlined-horizontal-padding, $fallbacks, true)};

  @include button-base.mat-private-button-horizontal-layout(
      button-outlined-icon-spacing, button-outlined-icon-offset, null, $fallbacks);
  @include button-base.mat-private-button-ripple(
      button-outlined-ripple-color, button-outlined-state-layer-color,
      button-outlined-disabled-state-layer-color,
      button-outlined-hover-state-layer-opacity, button-outlined-focus-state-layer-opacity,
      button-outlined-pressed-state-layer-opacity, $fallbacks);
  @include button-base.mat-private-button-touch-target(false,
      button-outlined-touch-target-size, button-outlined-touch-target-display, $fallbacks);

  &:not(:disabled) {
    color: token-utils.slot(button-outlined-label-text-color, $fallbacks);
    border-color: token-utils.slot(button-outlined-outline-color, $fallbacks);
  }

  // We need to re-apply the disabled tokens since MDC uses
  // `:disabled` which doesn't apply to anchors.
  @include button-base.mat-private-button-disabled {
    color: token-utils.slot(button-outlined-disabled-label-text-color, $fallbacks);
    border-color: token-utils.slot(button-outlined-disabled-outline-color, $fallbacks);
  }
}

.mat-tonal-button {
  transition: box-shadow 280ms cubic-bezier(0.4, 0, 0.2, 1);
  height: token-utils.slot(button-tonal-container-height, $fallbacks);
  font-family: token-utils.slot(button-tonal-label-text-font, $fallbacks);
  font-size: token-utils.slot(button-tonal-label-text-size, $fallbacks);
  letter-spacing: token-utils.slot(button-tonal-label-text-tracking, $fallbacks);
  text-transform: token-utils.slot(button-tonal-label-text-transform, $fallbacks);
  font-weight: token-utils.slot(button-tonal-label-text-weight, $fallbacks);
  padding: 0 #{token-utils.slot(button-tonal-horizontal-padding, $fallbacks, true)};

  &:not(:disabled) {
    color: token-utils.slot(button-tonal-label-text-color, $fallbacks);
    background-color: token-utils.slot(button-tonal-container-color, $fallbacks);
  }

  &, .mdc-button__ripple {
    border-radius: token-utils.slot(button-tonal-container-shape, $fallbacks);
  }

  // We need to re-apply the disabled tokens since MDC uses
  // `:disabled` which doesn't apply to anchors.
  @include button-base.mat-private-button-disabled {
    color: token-utils.slot(button-tonal-disabled-label-text-color, $fallbacks);
    background-color: token-utils.slot(button-tonal-disabled-container-color, $fallbacks);
  }

  @include button-base.mat-private-button-horizontal-layout(
      button-tonal-icon-spacing, button-tonal-icon-offset, null, $fallbacks);
  @include button-base.mat-private-button-ripple(
      button-tonal-ripple-color, button-tonal-state-layer-color,
      button-tonal-disabled-state-layer-color,
      button-tonal-hover-state-layer-opacity, button-tonal-focus-state-layer-opacity,
      button-tonal-pressed-state-layer-opacity, $fallbacks);
  @include button-base.mat-private-button-touch-target(false,
      button-tonal-touch-target-size, button-tonal-touch-target-display, $fallbacks);
}

.mat-mdc-button,
.mat-mdc-unelevated-button,
.mat-mdc-raised-button,
.mat-mdc-outlined-button,
.mat-tonal-button {
  @include button-base.mat-private-button-interactive();
  @include style-private.private-animation-noop();

  // Similar to MDC's `_icon-structure`, apart from the margin which we
  // handle via custom tokens in `mat-private-button-horizontal-layout`.
  & > .mat-icon {
    $icon-size: 1.125rem;
    display: inline-block;
    position: relative;
    vertical-align: top;
    font-size: $icon-size;
    height: $icon-size;
    width: $icon-size;
  }
}

// Since the stroked button has has an actual border that reduces the available space for
// child elements such as the ripple container or focus overlay, an inherited border radius
// for the absolute-positioned child elements does not work properly. This is because the
// child element cannot expand to the same boundaries as the parent element with a border.
// In order to work around this issue by *not* hiding overflow, we adjust the child elements
// to fully cover the actual button element. This means that the border-radius would be correct
// then. See: https://github.com/angular/components/issues/13738
.mat-mdc-outlined-button .mat-mdc-button-ripple,
.mat-mdc-outlined-button .mdc-button__ripple {
  $offset: -1px;
  top: $offset;
  left: $offset;
  bottom: $offset;
  right: $offset;
}

// For the button element, default inset/offset values are necessary to ensure that
// the focus indicator is sufficiently contrastive and renders appropriately.
.mat-mdc-unelevated-button,
.mat-tonal-button,
.mat-mdc-raised-button {
  .mat-focus-indicator::before {
    $default-border-width: focus-indicators-private.$default-border-width;
    $border-width: var(--mat-focus-indicator-border-width, #{$default-border-width});
    $offset: calc(#{$border-width} + 2px);
    margin: calc(#{$offset} * -1);
  }
}

.mat-mdc-outlined-button .mat-focus-indicator::before {
  $default-border-width: focus-indicators-private.$default-border-width;
  $border-width: var(--mat-focus-indicator-border-width, #{$default-border-width});
  $offset: calc(#{$border-width} + 3px);
  margin: calc(#{$offset} * -1);
}
