//
// Check/radio
//

@use '../../config' as *;

.form-check {
  // scss-docs-start form-check-css-vars
  --form-check-min-height: #{$form-check-min-height};
  --form-check-padding-start: #{$form-check-padding-start};
  --form-check-margin-bottom: #{$form-check-margin-bottom};
  // scss-docs-end form-check-css-vars

  display: block;
  min-height: var(--form-check-min-height);
  padding-inline-start: var(--form-check-padding-start);
  margin-bottom: var(--form-check-margin-bottom);

  .form-check-input {
    float: inline-start;
    margin-inline-start: calc(var(--form-check-padding-start) * -1);
  }
}

.form-check-reverse {
  padding-inline-end: var(--form-check-padding-start);
  padding-inline-start: 0;
  text-align: end;

  .form-check-input {
    float: inline-end;
    margin-inline-end: calc(var(--form-check-padding-start) * -1);
    margin-inline-start: 0;
  }
}

// The checked, indeterminate and disabled tokens read the shared state colors
// on `:root` (`--control-checked-bg` and friends) until the Sass variable is
// configured, so one override retunes checks, radios and switches together.
.form-check-input {
  // scss-docs-start form-check-input-css-vars
  --form-check-input-width: #{$form-check-input-width};
  --form-check-bg: #{$form-check-input-bg};
  --form-check-border: #{$form-check-input-border};
  --form-check-border-radius: #{$form-check-input-border-radius};
  --form-check-box-shadow: #{$form-check-input-box-shadow};
  --form-check-icon-color: #{$form-check-input-checked-color};
  --form-check-focus-border-color: #{$form-check-input-focus-border};
  --form-check-active-filter: #{$form-check-input-active-filter};
  --form-check-checked-bg: #{var-if-default($form-check-input-checked-bg-color, var(--primary), '--control-checked-bg')};
  --form-check-checked-border-color: #{var-if-default($form-check-input-checked-border-color, var(--border-color-translucent), '--control-checked-border-color')};
  --form-check-indeterminate-bg: #{var-if-default($form-check-input-indeterminate-bg-color, var(--primary), '--control-checked-bg')};
  --form-check-indeterminate-border-color: #{var-if-default($form-check-input-indeterminate-border-color, var(--primary), '--form-check-indeterminate-bg')};
  --form-check-disabled-opacity: #{var-if-default($form-check-input-disabled-opacity, 0.5, '--control-disabled-opacity')};
  --form-check-transition: #{$form-check-transition};
  // scss-docs-end form-check-input-css-vars

  position: relative;
  flex-shrink: 0;
  width: var(--form-check-input-width);
  height: var(--form-check-input-width);
  margin-top: ($line-height-base - $form-check-input-width) * 0.5; // line-height minus check height
  vertical-align: top;
  appearance: none;
  background-color: var(--form-check-bg);
  border: var(--form-check-border);
  print-color-adjust: exact; // Keep themed appearance for print
  @include transition(var(--form-check-transition));
  // Start the focus ring's `outline-color` transition from transparent, not `currentcolor`.
  outline-color: transparent;

  // The check, dash or dot is a pseudo-element painted through a CSS mask, so
  // its colour comes from `--form-check-icon-color` instead of a colour baked
  // into the svg. Hidden until the input is checked or indeterminate.
  &::before {
    position: absolute;
    inset: 0;
    pointer-events: none;
    content: '';
    background-color: var(--form-check-icon-color);
    opacity: 0;
    @include mask-icon(var(--form-check-icon));
  }

  &[type='checkbox'] {
    --form-check-icon: #{escape-svg($form-check-input-checked-bg-image)};

    @include border-radius(var(--form-check-border-radius));
  }

  &[type='radio'] {
    --form-check-icon: #{escape-svg($form-check-radio-checked-bg-image)};

    // stylelint-disable-next-line property-disallowed-list
    border-radius: $form-check-radio-border-radius;
  }

  &:active {
    filter: var(--form-check-active-filter);
  }

  &:focus-visible {
    border-color: var(--form-check-focus-border-color);
    @include focus-ring(true);
  }

  &:checked {
    background-color: var(--form-check-checked-bg);
    border-color: var(--form-check-checked-border-color);

    &::before {
      opacity: 1;
    }
  }

  &[type='checkbox']:indeterminate {
    --form-check-icon: #{escape-svg($form-check-input-indeterminate-bg-image)};
    --form-check-icon-color: #{$form-check-input-indeterminate-color};

    background-color: var(--form-check-indeterminate-bg);
    border-color: var(--form-check-indeterminate-border-color);

    &::before {
      opacity: 1;
    }
  }

  &:disabled {
    pointer-events: none;
    filter: none;
    opacity: var(--form-check-disabled-opacity);
  }

  // Use disabled attribute in addition of :disabled pseudo-class
  // See: https://github.com/twbs/bootstrap/issues/28247
  &[disabled],
  &:disabled {
    ~ .form-check-label {
      cursor: default;
      opacity: $form-check-label-disabled-opacity;
    }
  }
}

.form-check-label {
  color: $form-check-label-color;
  cursor: $form-check-label-cursor;
}

//
// Switch
//

.form-switch {
  // scss-docs-start form-switch-css-vars
  --form-switch-width: #{$form-switch-width};
  --form-switch-height: #{$form-switch-height};
  --form-switch-padding-start: #{if(sass($form-switch-padding-start == $form-switch-width + 0.5rem): calc(var(--form-switch-width) + 0.5rem); else: $form-switch-padding-start)};
  --form-switch-border-radius: #{if(sass($form-switch-border-radius == $form-switch-width): var(--form-switch-width); else: $form-switch-border-radius)};
  --form-switch-bg: #{$form-switch-bg};
  --form-switch-focus-color: #{$form-switch-focus-color};
  --form-switch-checked-color: #{$form-switch-checked-color};
  --form-switch-disabled-bg: #{var-if-default($form-switch-disabled-bg, var(--bg-forms-disabled), '--control-disabled-bg')};
  --form-switch-disabled-color: #{$form-switch-disabled-color};
  // scss-docs-end form-switch-css-vars

  padding-inline-start: var(--form-switch-padding-start);

  .form-check-input {
    --form-switch-color: #{$form-switch-color};
    // The knob is a circle with the same gap to the outer edge of the track on
    // every side. The gap is a whole number of pixels, so the knob stays round.
    --form-switch-knob-offset: 0.125rem;
    --form-switch-knob-size: calc(var(--form-switch-height) - var(--form-switch-knob-offset) * 2);
    // The knob is positioned inside the border, the gap is measured from outside it.
    --form-switch-knob-inset: calc(var(--form-switch-knob-offset) - var(--border-width));

    width: var(--form-switch-width);
    margin-inline-start: calc(var(--form-switch-padding-start) * -1);
    @include border-radius(var(--form-switch-border-radius), 0);
    @include transition($form-switch-transition);

    // The knob replaces the masked check icon: a plain circle that slides.
    &::before {
      inset-block: 0;
      inset-inline: var(--form-switch-knob-inset) auto;
      width: var(--form-switch-knob-size);
      height: var(--form-switch-knob-size);
      margin-block: auto;
      background-color: var(--form-switch-color);
      // stylelint-disable-next-line property-disallowed-list
      border-radius: 50%;
      opacity: 1;
      mask-image: none;
      @include transition($form-switch-knob-transition);
    }

    // An off switch is a filled track with no outline, so it reads as a
    // switch and not as an empty input.
    &:not(:checked, :disabled) {
      background-color: var(--form-switch-bg);
      border-color: transparent;
    }

    &:focus {
      --form-switch-color: var(--form-switch-focus-color);
    }

    &:checked {
      --form-switch-color: var(--form-switch-checked-color);

      &::before {
        inset-inline-start: calc(100% - var(--form-switch-knob-size) - var(--form-switch-knob-inset));
      }
    }
  }

  &.form-check-reverse {
    padding-inline-end: var(--form-switch-padding-start);
    padding-inline-start: 0;

    .form-check-input {
      margin-inline-end: calc(var(--form-switch-padding-start) * -1);
      margin-inline-start: 0;
    }
  }
}

.form-check-inline {
  display: inline-block;
  margin-inline-end: $form-check-inline-margin-end;
}

.btn-check {
  position: absolute;
  clip: rect(0, 0, 0, 0);
  pointer-events: none;

  &[disabled],
  &:disabled {
    + .btn {
      pointer-events: none;
      filter: none;
      opacity: $form-check-btn-check-disabled-opacity;
    }
  }
}
