@use "sass:map";
@use "../base/color" as cl;
@use "../base/border" as bo;
@use "../base/font" as ft;
@use "../base/space" as sp;
@use "../base/size" as sz;
@use "../base/variants" as vr;

// Form controls
//
//   <input class="qo-input" />
//   <input class="qo-input qo-input-sm qo-input-danger" />
//
// One class carries rest, :hover, :focus, :disabled and :read-only. The focus
// ring is the theme's single `$focus-ring` token, so every control on a screen
// focuses identically.

$input-sizes: (
  xs: (24px, sp.$space-2, ft.$font-size-xs),
  sm: (sz.$control-height-sm, sp.$space-2, ft.$font-size-sm),
  md: (sz.$control-height, sp.$space-3, ft.$font-size-md),
  lg: (48px, sp.$space-4, ft.$font-size-lg),
) !default;

.qo-input {
  width: 100%;
  height: sz.$control-height;
  padding: 0 sp.$space-3;
  display: inline-flex;
  align-items: center;
  border: bo.$border-width-sm solid cl.$border-default;
  border-radius: bo.$border-radius-md;
  background-color: cl.$background-default;
  color: cl.$text-dark;
  font-family: ft.$font-family-primary;
  font-size: ft.$font-size-md;
  font-weight: ft.$font-weight-regular;
  line-height: 1;
  transition: border-color 0.2s ease, box-shadow 0.2s ease;

  &::placeholder {
    color: cl.$text-placeholder;
    font-family: ft.$font-family-primary;
    font-weight: ft.$font-weight-regular;
    // Explicit colour, never reduced opacity — opacity renders inconsistently
    // across Chrome/Edge/Firefox.
    opacity: 1;
  }

  &:hover:not(:disabled):not([readonly]) { border-color: cl.$border-secondary; }

  &:focus,
  &:focus-visible {
    outline: 0;
    border-color: cl.$border-primary;
    box-shadow: cl.$focus-ring;
  }

  &:disabled,
  &.qo-disabled {
    background-color: cl.$background-disabled;
    color: cl.$text-default;
    cursor: not-allowed;
  }

  &[readonly] {
    background-color: cl.$background-light;
    cursor: default;
  }

  @each $name, $spec in $input-sizes {
    &.qo-input-#{$name} {
      height: nth($spec, 1);
      padding: 0 nth($spec, 2);
      font-size: nth($spec, 3);
    }
  }

  &.qo-input-full { display: flex; width: 100%; }
  &.qo-input-auto { width: auto; }
  &.qo-input-pill { border-radius: bo.$border-radius-pill; }

  // Validation states. Each re-colours the border and its own focus ring so
  // the ring never contradicts the state.
  @each $name in (success, warning, danger, info) {
    &.qo-input-#{$name} {
      border-color: map.get(map.get(vr.$variants, $name), base);
      &:focus,
      &:focus-visible {
        border-color: map.get(map.get(vr.$variants, $name), base);
        box-shadow: 0 0 0 3px rgba(0, 0, 0, 0);
        outline: 2px solid map.get(map.get(vr.$variants, $name), soft);
        outline-offset: 0;
      }
    }
  }

  // A textarea keeps the ramp but must not be pinned to a control height.
  &.qo-input-textarea {
    height: auto;
    min-height: 80px;
    padding: sp.$space-2 sp.$space-3;
    line-height: ft.$line-height-md;
  }
}

// Retained from 2.2.0 — `qo-input-default` was the only way to get a bordered
// input before `.qo-input` carried its own border.
.qo-input-default {
  background-color: cl.$background-default;
  border: bo.$border-width-sm solid cl.$border-default;
}

// Label + help + error, so a field is one block rather than three guesses.
.qo-label {
  display: inline-block;
  margin-bottom: sp.$space-1;
  color: cl.$text-darker;
  font-family: ft.$font-family-primary;
  font-size: ft.$font-size-sm;
  font-weight: ft.$font-weight-semibold;

  &.qo-label-required::after {
    content: " *";
    color: cl.$text-danger;
  }
}

.qo-help {
  display: block;
  margin-top: sp.$space-1;
  color: cl.$text-secondary;
  font-size: ft.$font-size-xs;
}

.qo-field {
  display: block;
  & + & { margin-top: sp.$space-3; }
}

// An input with a leading or trailing icon. The icon is positioned, not
// padded in by hand, so it cannot drift out of the control.
.qo-input-group {
  position: relative;
  display: flex;
  align-items: center;
  width: 100%;

  > .qo-input-icon {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    color: cl.$text-default;
    font-size: ft.$font-size-md;
    pointer-events: none;
  }

  > .qo-input-icon-start { left: sp.$space-3; }
  > .qo-input-icon-end { right: sp.$space-3; }

  > .qo-input-icon-start ~ .qo-input { padding-left: 38px; }
  > .qo-input:has(~ .qo-input-icon-end) { padding-right: 38px; }

  // Search is the listing page's most common group: the magnifier is primary
  // coloured and the control is the full-height one.
  &.qo-input-group-search > .qo-input-icon { color: cl.$text-primary; }
}

// Checkbox / radio — sized and coloured, not restyled from scratch.
.qo-check {
  width: 16px;
  height: 16px;
  margin: 0;
  accent-color: cl.$background-primary;
  cursor: pointer;

  &:focus-visible { outline: 0; box-shadow: cl.$focus-ring; }
  &:disabled { cursor: not-allowed; opacity: 0.45; }
}

// Native select needs the control ramp plus room for its own arrow.
.qo-select {
  @extend .qo-input;
  padding-right: sp.$space-6;
  cursor: pointer;
}
