@use "sass:math";
@use "sass:selector";

$text-inputs: 'input:not([type]), input[type="email"], input[type="time"], input[type="date"], input[type="datetime-local"], input[type="number"], input[type="password"], input[type="search"], input[type="tel"], input[type="text"], input[type="url"], textarea';
$input-fields: "#{$text-inputs}, select, .input, .textarea";

%input-disabled {
  cursor: not-allowed;
  opacity: $disabled-opacity;
}

#{$input-fields} {
  font-family: inherit;
  padding: $form-element-padding-y $form-element-padding-x;
  @include font-size($form-element-font-size);
  border: $border;
  border-radius: $form-element-border-radius;
  display: block;
  width: 100%;
  @include bg-color(filled);

  &::placeholder {
    @include text-muted;
  }

  &:focus-within {
    outline: $outline;
  }

  &:disabled {
    @extend %input-disabled;
  }
}

label {
  display: inline-flex;
  gap: spacer(2);
  @include font-size($form-element-font-size);
  cursor: pointer;

  &:has(input:disabled) {
    @extend %input-disabled;
  }
}

fieldset {
  // We use flexbox rather than grid because of a fieldset rendering bug in Safari
  display: flex;
  flex-direction: column;
  border: none;
  gap: spacer(2);

  legend {
    display: flex;
    align-items: center;
    position: relative;
    font-weight: bold;
    margin-bottom: spacer(2);
    width: 100%;
    @include font-size($form-element-font-size);

    label,
    a {
      font-weight: normal;
    }

    & > :last-child:not(:only-child) {
      float: right;
      margin-left: auto;
    }
  }

  small {
    @include text-muted;
  }

  &[role="group"] label {
    width: 100%;
    input {
      margin-left: auto;
    }
  }
}

@each $name in $states {
  fieldset.#{$name} {
    #{$input-fields},
    input[type="radio"],
    input[type="checkbox"] {
      border-color: full-color($name);
    }

    small {
      color: full-color($name);
    }
  }
}

.input.disabled,
.textarea.disabled {
  @extend %input-disabled;
}

#{selector.append($text-inputs, ":read-only")},
.input.read-only,
.textarea.read-only {
  background-color: var(--body-bg);
}

.input {
  display: inline-flex;
  align-items: center;
  gap: math.div($form-element-padding-x, 2);
  position: relative;
  padding-top: 0;
  padding-bottom: 0;
  min-height: $form-element-height;

  #{$input-fields} {
    border: none;
    flex: 1;
    background: none;
    box-shadow: none;
    outline: none;
    margin: 0 (-$form-element-padding-x);
    max-width: unset;
  }

  .fake-input {
    flex: 1;
  }

  &.disabled {
    #{$input-fields} {
      opacity: unset;
    }
  }

  & > .pill {
    flex-shrink: 0;

    &:first-child {
      margin-left: -(math.div($form-element-padding-x, 2));
    }

    &:last-child {
      margin-right: -(math.div($form-element-padding-x, 2));
    }
  }

  & > .icon {
    @include text-muted;
  }
}

select {
  appearance: none;
  background-image: linear-gradient(45deg, transparent 50%, currentColor 50%, full-color(filled) calc(50% + 2px)),
    linear-gradient(315deg, transparent 50%, currentColor 50%, full-color(filled) calc(50% + 2px));
  background-repeat: no-repeat;
  background-position:
    calc(100% - $form-element-padding-x - 0.5em) center,
    calc(100% - $form-element-padding-x) center;
  background-size: 0.5em 0.5em;
  padding-right: calc($form-element-padding-x + math.div($form-element-padding-x, 2) + 1em);
}

input[type="radio"],
input[type="checkbox"] {
  color: inherit;
  cursor: pointer;
  appearance: none;
  $width: calc(1lh + 2 * $border-width);
  width: $width;
  height: $width;
  aspect-ratio: 1;
  border: $border;
  background: full-color(filled);
  flex-shrink: 0;
  @include font-size($form-element-font-size);
  &:checked {
    @include bg-color(accent);
  }
  &:disabled {
    @extend %input-disabled;
  }
}

input[type="radio"] {
  border-radius: 100%;

  &:checked {
    padding: spacer(2) - 2 * $border-width;
    &::after {
      content: "";
      background-color: full-color(color);
      border-radius: 100%;
      height: 100%;
      display: block;
    }
  }
}

input[type="checkbox"]:not([role="switch"]) {
  border-radius: border-radius(2);

  &:checked::after {
    display: block;
    margin-inline: auto;
    @extend %icon, .icon-outline-check;
  }
}

.radio-buttons[role="radiogroup"] {
  display: grid;
  gap: spacer(4);
  grid-template-columns: repeat(auto-fit, minmax(min(size(15), 100%), 1fr));

  button[role="radio"] {
    @extend %select-button;

    &[aria-checked="true"] {
      @extend %select-button-active;
    }
  }
}

input[role="switch"] {
  $padding: size(0.1875);
  width: calc(2 * #{$big-icon-size} - #{2 * $padding});
  height: $big-icon-size;
  border-radius: border-radius(3);
  position: relative;
  @include transition(all);

  &::after {
    background: currentColor;
    border-radius: border-radius(3);
    content: "";
    height: calc(#{$big-icon-size} - #{2 * $padding});
    width: calc(#{$big-icon-size} - #{2 * $padding});
    position: absolute;
    top: size(0.125);
    left: size(0.1875);
    @include transition(all);
  }

  &:checked::after {
    left: calc(100% - #{$big-icon-size} + #{$padding});
    background-color: full-color(contrast-accent);
  }
}

input[type="file"] {
  display: none;
}

input[type="range"] {
  $track-height: size(0.3125);
  $thumb-size: 1em;
  --progress: 0%;
  appearance: none;
  background: none;
  height: $track-height;

  @mixin track {
    background: linear-gradient(to right, currentColor var(--progress), gray(2) var(--progress));
    border-radius: border-radius(1);
    width: 100%;
    height: $track-height;
    cursor: pointer;
  }

  // Chrome/Safari ignore these styles if specified alongside -moz-range-track, so defining them separately
  &::-webkit-slider-runnable-track {
    @include track();
  }

  &::-moz-range-track {
    @include track();
  }

  @mixin thumb {
    margin-top: calc(0.5 * (#{$track-height} - #{$thumb-size}));
    appearance: none;
    border: none;
    width: $thumb-size;
    height: $thumb-size;
    background: full-color(color);
    border-radius: border-radius(3);
    cursor: pointer;
  }

  &::-webkit-slider-thumb {
    @include thumb();
  }

  &::-moz-range-thumb {
    @include thumb();
  }
}

input[type="search"] {
  appearance: none;
}

form {
  & > section {
    $y-gap: spacer(6);
    display: grid;
    padding: spacer(7) 0;
    border-top: $border;
    gap: $y-gap;
    & > header {
      display: grid;
      gap: spacer(3);
      align-content: start;
    }

    &:not(form + form section):first-of-type {
      padding-top: 0;
      border-top: none;
    }

    &:is([role="separator"] + section) {
      border-top: none;
    }

    @include breakpoint-up(lg, true) {
      // There currently is no way to make an element take up an entire grid/flex column when using an implicit grid.
      gap: 0 spacer(8);
      padding-bottom: spacer(7) - $y-gap;
      grid-template-columns: 25% 1fr;
      & > * {
        margin-bottom: $y-gap;
        grid-column: 2;
      }
      & > header {
        grid-column: 1/2;
        grid-row: 1/10;
      }
    }
  }
}

.combobox {
  position: relative;

  input[aria-expanded="true"],
  .input:has(input[aria-expanded="true"]) {
    border-bottom-left-radius: 0;
    border-bottom-right-radius: 0;
  }

  datalist {
    display: block;
    @include bg-color(filled);
    border: $border;
    width: 100%;
    overflow: auto;
    position: absolute;
    top: 100%;
    left: 0;
    border-radius: 0 0 border-radius(1) border-radius(1);
    box-shadow: box-shadow(1);
    z-index: z-index(modal);
    padding: spacer(2) 0;

    option,
    [role="option"],
    .option {
      padding: spacer(2) spacer(4);
      cursor: pointer;
      display: flex;
      align-items: center;
      &.focused,
      &:focus {
        @include bg-color(primary);
      }

      img {
        border-radius: border-radius(1);
        border: $border;
        height: size(3);
        flex: 0 0 size(3);
        object-fit: cover;
      }
    }

    &[aria-multiselectable="true"] {
      option,
      [role="option"] {
        &[aria-selected="true"]:after {
          @extend %icon, .icon-solid-check-circle;
          color: full-color(success);
          margin-left: auto;
        }
      }
    }

    h3 {
      padding: spacer(2) spacer(4);

      &:not(:first-child) {
        border-top: $border;
        padding-top: spacer(4);
        margin-top: spacer(2);
      }
    }
  }
}

[role="combobox"] {
  cursor: pointer;
}

textarea {
  resize: vertical;
}

.color-picker {
  position: relative;
  overflow: hidden;
  padding: spacer(4);
  border: $border;
  border-radius: border-radius(3);
  max-width: fit-content;

  > input[type="color"] {
    position: absolute;
    width: 200%;
    height: 200%;
    max-width: unset;
    left: -50%;
    top: -50%;
    border: none;
    cursor: pointer;
  }
}

[role="radio"],
[role="checkbox"] {
  cursor: pointer;
}
