@use '../compiled/tokens/scss/color';
@use '../compiled/tokens/scss/ease';
@use '../compiled/tokens/scss/size';
@use '../compiled/tokens/scss/transition';
@use './focus';
@use './theme';

@include theme.props {
  --theme-color-text-toggle-checked-hover: var(--theme-color-text-toggle-hover);
  --theme-color-text-toggle-disabled: #{color.$base-gray-dark};
  --theme-color-text-toggle-hover: #{color.$brand-primary};
}

@include theme.props(dark) {
  --theme-color-text-toggle-checked-hover: #{color.$brand-primary-darker};
  --theme-color-text-toggle-disabled: #{color.$text-light};
  --theme-color-text-toggle-hover: #{color.$text-dark};
}

/// Styles that apply to both checkbox and radio inputs.
///
/// 1. Modern browsers let us apply wholly custom styles to certain elements,
///    but only when `appearance` is set to `none`. Somewhat recent versions of
///    Safari still requires a vendor prefix.
/// 2. Some browsers will squish the input in flex containers, which we
///    never, ever want.
/// 3. Without this, inputs appear too small unless hard-pixel sizes are
///    used (ew).
@mixin base {
  // stylelint-disable-next-line property-no-vendor-prefix
  -webkit-appearance: none; // 1
  appearance: none; // 1
  background-color: color.$text-light;
  block-size: size.$square-toggle-medium;
  border: size.$edge-control solid currentColor;
  color: color.$text-dark;
  cursor: pointer;
  flex: none; // 2
  font: inherit; // 3
  inline-size: size.$square-toggle-medium;
  padding: 0;
  position: relative;
  transition-duration: transition.$quick;
  transition-property: background-color, border-color, color;
  transition-timing-function: ease.$out;
  vertical-align: middle;
}

/// State: Focus
@mixin base-focus {
  box-shadow: 0 0 0 size.$edge-large color.$brand-primary-lighter;
}

/// State: Hover
@mixin base-hover {
  background-color: color.$text-light-emphasis;
  color: var(--theme-color-text-toggle-hover);
}

/// State: Disabled
///
/// 1. We want the input to appear "read-only." A transparent background
///    and dashed line help symbolize a lack of interactivity.
/// 2. Same color used for disabled `c-input` borders.
@mixin base-disabled {
  background-color: transparent; // 1
  border-style: dashed; // 1
  color: var(--theme-color-text-toggle-disabled); // 2
  cursor: not-allowed;
}

/// Shared styles for the inner toggle's "fill" that represents its `checked`
/// state.
@mixin base-inner-pseudo-default {
  content: '';
  opacity: 0;
  position: absolute;
  scale: 0;
  transition-duration: transition.$quick;
  transition-property: opacity, scale;
  transition-timing-function: ease.$out;
}

@mixin base-inner-pseudo-checked {
  opacity: 1;
  scale: 1;
}

/// Checkbox styles
@mixin checkbox {
  @include base;
  border-radius: size.$border-radius-medium;

  @include focus.focus-visible {
    @include base-focus;
  }

  &:hover {
    @include base-hover;
  }

  /// We add the check mark via a pseudo element so we can easily apply
  /// transitions to it without requiring separate elements.
  &::after {
    @include base-inner-pseudo-default;
    background-image: svg-load(
      'icons/check.svg',
      stroke=color.$text-light-emphasis
    );
    background-position: center;
    background-repeat: no-repeat;
    background-size: contain;
    inset: size.$edge-control;
  }

  &:checked {
    background-color: currentColor;

    /// End state of animation
    &::after {
      @include base-inner-pseudo-checked;
    }

    &:hover {
      color: var(--theme-color-text-toggle-checked-hover);
    }
  }

  &:disabled {
    @include base-disabled;

    &::after {
      /// Inline SVGs aren't aware of custom properties, so we have to do a
      /// bit of theming trickery here
      @include theme.styles {
        background-image: svg-load(
          'icons/check.svg',
          stroke=color.$base-gray-dark
        );
      }

      @include theme.styles(dark) {
        background-image: svg-load('icons/check.svg', stroke=color.$text-light);
      }
    }

    /// We can forego the border entirely for a disabled checkmark, as the hit
    /// area is unimportant.
    &:checked {
      border-color: transparent;
    }
  }
}

/// Radio styles
@mixin radio {
  @include base;
  border-radius: size.$border-radius-full;

  @include focus.focus-visible {
    @include base-focus;
  }

  &:hover {
    @include base-hover;
  }

  /// 1. Our linter is getting confused by the Sass expression and trying to
  ///    split this into multiple lines.
  &::after {
    @include base-inner-pseudo-default;
    background-color: currentColor;
    border-radius: inherit;
    // stylelint-disable-next-line liberty/use-logical-spec
    inset: size.$edge-control * 2; // 1
  }

  &:checked {
    &::after {
      @include base-inner-pseudo-checked;
    }
  }

  &:disabled {
    @include base-disabled;
  }
}
