@use "sass:math";
@use "../../core/settings" as *;
@use "../../core/tools" as *;
@use "../../core/helpers" as *;
@forward "../error-message";
@forward "../fieldset";
@forward "../hint";
@forward "../label";

////
/// Checkboxes component
///
/// @group components/checkboxes
////

$nhsuk-checkboxes-size: nhsuk-px-to-rem(40px);
$nhsuk-checkboxes-small-size: nhsuk-px-to-rem(24px);

$nhsuk-checkboxes-label-padding-left-right: nhsuk-px-to-rem(12px);

// Offset 2px due to 40px form control with 44px clickable area
// https://nhsuk.github.io/nhsuk-frontend/examples/form-alignment/
$nhsuk-checkboxes-offset: $nhsuk-border-width-form-element;

@include nhsuk-exports("nhsuk/components/checkboxes") {
  $nhsuk-touch-target-gutter: nhsuk-px-to-rem(4px);
  $nhsuk-touch-target-size: $nhsuk-checkboxes-size + nhsuk-px-to-rem($nhsuk-touch-target-gutter);

  .nhsuk-checkboxes {
    margin: -$nhsuk-checkboxes-offset nhsuk-px-to-rem(-$nhsuk-checkboxes-offset);
    margin-right: 0;
  }

  .nhsuk-checkboxes__item {
    display: flex;
    position: relative;
    flex-wrap: wrap;
    margin-top: nhsuk-spacing(2) - $nhsuk-checkboxes-offset;

    .nhsuk-checkboxes__conditional:not(.nhsuk-checkboxes__conditional--hidden) + & {
      @include nhsuk-responsive-margin(4, "top", $adjustment: - $nhsuk-checkboxes-offset);
    }
  }

  .nhsuk-checkboxes__item:first-child {
    margin-top: 0;
  }

  .nhsuk-checkboxes__input {
    // Allow the input to sit above the label, enabling its proper detection
    // when exploring by touch or using automation tools like Selenium
    z-index: 1;

    width: $nhsuk-touch-target-size;
    height: $nhsuk-touch-target-size;
    margin: 0;

    opacity: 0;

    cursor: pointer;
  }

  .nhsuk-checkboxes__label {
    box-sizing: border-box;

    align-self: center;

    // Ensure that the width of the label is never more than the width of the
    // container minus the input. This prevents the label from wrapping due to
    // __item using flex-wrap because we want hints on a separate line
    max-width: calc(100% - $nhsuk-touch-target-size);
    margin-bottom: 0;
    padding: (nhsuk-spacing(1) + $nhsuk-border-width-form-element) $nhsuk-checkboxes-label-padding-left-right;

    cursor: pointer;
    // remove 300ms pause on mobile
    touch-action: manipulation;
  }

  // [ ] Check box
  .nhsuk-checkboxes__label::before {
    content: "";

    box-sizing: border-box;

    position: absolute;
    top: math.div($nhsuk-touch-target-gutter, 2);
    left: math.div($nhsuk-touch-target-gutter, 2);

    width: $nhsuk-checkboxes-size;
    height: $nhsuk-checkboxes-size;

    border: $nhsuk-border-width-form-element solid $nhsuk-input-border-colour;

    background: $nhsuk-input-background-colour;
  }

  // ✔ Check mark
  //
  // The check mark is a box with a border on the left and bottom side (└──),
  // rotated 45 degrees
  .nhsuk-checkboxes__label::after {
    content: "";

    box-sizing: border-box;

    position: absolute;

    // Use "magic numbers" to define shape and position of check mark because
    // the complexity of the shape makes it difficult to calculate dynamically.
    top: nhsuk-px-to-rem(15px);
    left: nhsuk-px-to-rem(12px);

    width: nhsuk-px-to-rem(22px);
    height: nhsuk-px-to-rem(10px);

    transform: rotate(-45deg);

    border: solid;
    border-width: 0 0 nhsuk-px-to-rem(4px) nhsuk-px-to-rem(4px);
    // Fix bug in IE11 caused by transform rotate (-45deg).
    // See: alphagov/nhsuk_elements/issues/518
    border-top-color: transparent;

    opacity: 0;

    background: transparent;
  }

  .nhsuk-checkboxes__hint {
    display: block;
    width: 100%;
    margin-top: nhsuk-spacing(-1);
    padding-right: $nhsuk-checkboxes-label-padding-left-right;
    padding-left: $nhsuk-checkboxes-label-padding-left-right + $nhsuk-touch-target-size;
  }

  // This is to bypass nhsuk-hint's specificity on hints following labels having
  // a margin bottom of 8px (nhsuk-spacing(2)). Because checkboxes are flexbox,
  // the margin doesn't collapse so we have to do this manually.
  .nhsuk-label:not(.nhsuk-label--m):not(.nhsuk-label--l):not(.nhsuk-label--xl) + .nhsuk-checkboxes__hint {
    margin-bottom: 0;
  }

  // Focused state
  .nhsuk-checkboxes__input:focus + .nhsuk-checkboxes__label::before {
    @include nhsuk-focused-checkbox;
  }

  // Selected state
  .nhsuk-checkboxes__input:checked + .nhsuk-checkboxes__label::after {
    opacity: 1;
  }

  // Disabled state
  .nhsuk-checkboxes__input:disabled,
  .nhsuk-checkboxes__input:disabled + .nhsuk-checkboxes__label {
    cursor: not-allowed;
  }

  .nhsuk-checkboxes__input:disabled + .nhsuk-checkboxes__label,
  .nhsuk-checkboxes__input:disabled ~ .nhsuk-hint {
    opacity: 0.5;
  }

  // =========================================================
  // Inline checkboxes
  // =========================================================

  .nhsuk-checkboxes--inline {
    @include nhsuk-media-query($from: tablet) {
      display: flex;
      flex-wrap: wrap;
      align-items: flex-start;
      row-gap: nhsuk-spacing(2) - $nhsuk-checkboxes-offset;

      &.nhsuk-checkboxes--small {
        row-gap: 0;
      }

      .nhsuk-checkboxes__item {
        max-width: calc(50% - $nhsuk-checkboxes-label-padding-left-right - nhsuk-spacing(4));
        margin-top: 0;
        margin-right: nhsuk-spacing(4);
      }
    }
  }

  // =========================================================
  // Dividers ('or')
  // =========================================================

  .nhsuk-checkboxes__divider {
    width: $nhsuk-checkboxes-size;
    margin: nhsuk-spacing(2) - $nhsuk-checkboxes-offset nhsuk-px-to-rem($nhsuk-checkboxes-offset);
    text-align: center;
    @include nhsuk-text-colour;
    @include nhsuk-font($size: 19);
  }

  // =========================================================
  // Conditional reveals
  // =========================================================

  // Calculate the amount of padding needed to keep the border centered against the checkbox.
  $conditional-border-padding: math.div($nhsuk-touch-target-size, 2) - nhsuk-px-to-rem($nhsuk-border-width-form-element);
  // Move the border centered with the checkbox
  $conditional-margin-left: $conditional-border-padding;
  // Move the contents of the conditional inline with the label
  $conditional-padding-left: $conditional-border-padding + $nhsuk-checkboxes-label-padding-left-right;

  .nhsuk-checkboxes__conditional {
    margin-top: nhsuk-spacing(2) - $nhsuk-checkboxes-offset;
    margin-bottom: $nhsuk-checkboxes-offset;
    margin-left: $conditional-margin-left;
    padding-left: $conditional-padding-left;
    border-left: nhsuk-px-to-rem($nhsuk-border-width) solid nhsuk-colour("grey-3");

    .nhsuk-frontend-supported &--hidden {
      display: none;
    }
  }

  // =========================================================
  // Small checkboxes
  // =========================================================

  .nhsuk-checkboxes--small {
    $input-offset: math.div($nhsuk-touch-target-size - $nhsuk-checkboxes-small-size, 2);

    .nhsuk-checkboxes__item {
      margin-top: 0;
    }

    // Shift the touch target into the left margin so that the visible edge of
    // the control is aligned
    //
    //   ┆What colours do you like?
    //  ┌┆───┐
    //  │┆[] │ Purple
    //  └┆▲──┘
    //  ▲┆└─ Check box pseudo element, aligned with margin
    //  └─── Touch target (invisible input), shifted into the margin
    .nhsuk-checkboxes__input {
      margin-left: $input-offset * -1;
    }

    .nhsuk-checkboxes__label {
      max-width: calc(100% - $nhsuk-touch-target-size + $input-offset);

      // Create a tiny space between the small checkbox hover state so that it
      // doesn't clash with the label
      padding-left: $nhsuk-checkboxes-label-padding-left-right - $input-offset;
    }

    // [ ] Check box
    //
    // Reduce the size of the check box [1], vertically center it within the
    // touch target [2]
    .nhsuk-checkboxes__label::before {
      top: $input-offset; // 2
      left: nhsuk-px-to-rem($nhsuk-checkboxes-offset);
      width: $nhsuk-checkboxes-small-size; // 1
      height: $nhsuk-checkboxes-small-size; // 1
    }

    // ✔ Check mark
    //
    // Reduce the size of the check mark and re-align within the checkbox
    .nhsuk-checkboxes__label::after {
      top: nhsuk-px-to-rem(18px);
      left: nhsuk-px-to-rem(8px);
      width: nhsuk-px-to-rem(12px);
      height: nhsuk-px-to-rem(6px);
      border-width: 0 0 nhsuk-px-to-rem(3px) nhsuk-px-to-rem(3px);
    }

    // Fix position of hint with small checkboxes
    .nhsuk-checkboxes__hint {
      padding-left: $nhsuk-touch-target-size + $nhsuk-checkboxes-label-padding-left-right - ($input-offset * 2);
    }

    // Align conditional reveals with small checkboxes
    .nhsuk-checkboxes__conditional {
      margin-left: $conditional-border-padding - $input-offset + nhsuk-px-to-rem($nhsuk-checkboxes-offset);
      padding-left: $conditional-border-padding + $nhsuk-checkboxes-label-padding-left-right -
        $input-offset - nhsuk-px-to-rem($nhsuk-checkboxes-offset);
    }

    .nhsuk-checkboxes__divider {
      width: $nhsuk-checkboxes-small-size;
      margin: nhsuk-spacing(1) - $nhsuk-checkboxes-offset nhsuk-px-to-rem($nhsuk-checkboxes-offset);
    }

    // Hover state for small checkboxes.
    //
    // We use a hover state for small checkboxes because the touch target size
    // is so much larger than their visible size, and so we need to provide
    // feedback to the user as to which checkbox they will select when their
    // cursor is outside of the visible area.
    .nhsuk-checkboxes__input:not(:disabled):hover + .nhsuk-checkboxes__label::before,
    .nhsuk-checkboxes__input:not(:disabled) + .nhsuk-checkboxes__label:hover::before {
      // Forced colours modes tend to ignore box-shadow.
      // Apply an outline for those modes to use instead.
      outline: $nhsuk-focus-width dashed transparent;
      outline-offset: 1px;
      box-shadow: 0 0 0 $nhsuk-hover-width $nhsuk-hover-colour;
    }

    // Because we've overridden the border-shadow provided by the focus state,
    // we need to redefine that too.
    //
    // We use two box shadows, one that restores the original focus state [1]
    // and another that then applies the hover state [2].
    .nhsuk-checkboxes__input:focus:hover + .nhsuk-checkboxes__label::before,
    .nhsuk-checkboxes__input:focus + .nhsuk-checkboxes__label:hover::before {
      // prettier-ignore
      box-shadow:
        0 0 0 $nhsuk-focus-width $nhsuk-focus-colour, // 1
        0 0 0 $nhsuk-hover-width $nhsuk-hover-colour; // 2

      // Set different HCM colour when we have both hover/focus applied at once
      @media screen and (forced-colors: active), (-ms-high-contrast: active) {
        outline-color: Highlight;
      }
    }

    // For devices that explicitly don't support hover, don't provide a hover
    // state (e.g. on touch devices like iOS).
    //
    // We can't use `@media (hover: hover)` because we wouldn't get the hover
    // state in browsers that don't support `@media (hover)` (like Internet
    // Explorer) – so we have to 'undo' the hover state instead.
    @media (hover: none), (pointer: coarse) {
      .nhsuk-checkboxes__input:not(:disabled):hover + .nhsuk-checkboxes__label::before,
      .nhsuk-checkboxes__input:not(:disabled) + .nhsuk-checkboxes__label:hover::before {
        box-shadow: initial;
      }

      .nhsuk-checkboxes__input:focus:hover + .nhsuk-checkboxes__label::before,
      .nhsuk-checkboxes__input:focus + .nhsuk-checkboxes__label:hover::before {
        box-shadow: 0 0 0 $nhsuk-focus-width $nhsuk-focus-colour;
      }
    }
  }
}
